commit
cbe5c55f6d
48 ha cambiato i file con 10679 aggiunte e 0 eliminazioni
@ -0,0 +1,8 @@
|
||||
<?php |
||||
|
||||
return [ |
||||
'host' => 'localhost', |
||||
'database' => 'database', |
||||
'username' => 'username', |
||||
'password' => 'password', |
||||
]; |
||||
@ -0,0 +1,5 @@
|
||||
<?php |
||||
|
||||
return [ |
||||
'key' => 'CHANGE_ME', |
||||
]; |
||||
@ -0,0 +1,141 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Controllers; |
||||
|
||||
use MwgAuth\Core\Controller; |
||||
use MwgAuth\Models\User; |
||||
|
||||
class ControllerV1 extends Controller |
||||
{ |
||||
public static function login(): string |
||||
{ |
||||
self::requireMethod('POST'); |
||||
$input = self::getPost(); |
||||
if (null === $input) { |
||||
return self::error(self::ERROR_INVALID_INPUT); |
||||
} |
||||
$userName = $input[self::PARAMETER_USERNAME] ?? null; |
||||
if (null === $userName) { |
||||
return self::error(self::ERROR_MISSING_PARAMETER, self::PARAMETER_USERNAME); |
||||
} |
||||
$password = $input[self::PARAMETER_PASSWORD] ?? null; |
||||
if (null === $password) { |
||||
return self::error(self::ERROR_MISSING_PARAMETER, self::PARAMETER_PASSWORD); |
||||
} |
||||
$user = User::load($userName, $password, $_SERVER['REMOTE_ADDR']); |
||||
if (null === $user) { |
||||
return self::error(self::ERROR_INVALID_PASSWORD); |
||||
} |
||||
return self::response([self::PARAMETER_AUTH => $user->getAuth()]); |
||||
} |
||||
|
||||
public static function getToken(): string |
||||
{ |
||||
self::requireMethod('POST'); |
||||
$input = self::getPost(); |
||||
if (null === $input) { |
||||
return self::error(self::ERROR_INVALID_INPUT); |
||||
} |
||||
$auth = $input[self::PARAMETER_AUTH] ?? null; |
||||
if (null === $auth) { |
||||
return self::error(self::ERROR_MISSING_PARAMETER, self::PARAMETER_AUTH); |
||||
} |
||||
$callback = $input[self::PARAMETER_CALLBACK_URL] ?? null; |
||||
if (null === $callback) { |
||||
return self::error(self::ERROR_MISSING_PARAMETER, self::PARAMETER_CALLBACK_URL); |
||||
} |
||||
$user = User::verifyAuth($auth); |
||||
if (null === $user) { |
||||
return self::error(self::ERROR_INVALID_AUTH); |
||||
} |
||||
$token = $user->getToken($callback); |
||||
return self::response([self::PARAMETER_TOKEN => $token]); |
||||
} |
||||
|
||||
public static function getUser(): string |
||||
{ |
||||
self::requireMethod('POST'); |
||||
$input = self::getPost(); |
||||
if (null === $input) { |
||||
return self::error(self::ERROR_INVALID_INPUT); |
||||
} |
||||
$auth = $input[self::PARAMETER_AUTH] ?? null; |
||||
if (null === $auth) { |
||||
return self::error(self::ERROR_MISSING_PARAMETER, self::PARAMETER_AUTH); |
||||
} |
||||
$user = User::verifyAuth($auth); |
||||
if (null === $user) { |
||||
return self::error(self::ERROR_INVALID_AUTH); |
||||
} |
||||
$token = $input[self::PARAMETER_TOKEN] ?? null; |
||||
if (null === $token) { |
||||
return self::error(self::ERROR_MISSING_PARAMETER, self::PARAMETER_TOKEN); |
||||
} |
||||
if (!$user->verifyToken($token)) { |
||||
return self::error(self::ERROR_INVALID_TOKEN); |
||||
} |
||||
$userData = $user->getLoginData($token); |
||||
if (null === $userData) { |
||||
return self::error(self::ERROR_INVALID_LOGIN); |
||||
} |
||||
return self::response($userData); |
||||
} |
||||
|
||||
private static function json(array $values): string |
||||
{ |
||||
return json_encode($values, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); |
||||
} |
||||
|
||||
private static function response(array $values): string |
||||
{ |
||||
$response = [ |
||||
self::LABEL_ERROR_CODE => self::ERROR_OK, |
||||
self::LABEL_STATUS => self::STATUS_OK, |
||||
self::LABEL_DESCRIPTION => self::ERROR_DESCRIPTIONS[self::ERROR_OK], |
||||
]; |
||||
$response += $values; |
||||
return self::json($response); |
||||
} |
||||
|
||||
private static function error(int $errorCode, ...$parameters): string |
||||
{ |
||||
$status = $errorCode == self::ERROR_OK ? self::STATUS_OK : self::STATUS_ERROR; |
||||
return self::json([ |
||||
self::LABEL_ERROR_CODE => $errorCode, |
||||
self::LABEL_STATUS => $status, |
||||
self::LABEL_DESCRIPTION => vsprintf(self::ERROR_DESCRIPTIONS[$errorCode], $parameters), |
||||
]); |
||||
} |
||||
|
||||
protected const LABEL_ERROR_CODE = 'code'; |
||||
protected const LABEL_DESCRIPTION = 'description'; |
||||
protected const LABEL_STATUS = 'status'; |
||||
|
||||
protected const ERROR_OK = 0; |
||||
protected const ERROR_INVALID_AUTH = 1; |
||||
protected const ERROR_INVALID_LOGIN = 2; |
||||
protected const ERROR_INVALID_TOKEN = 3; |
||||
protected const ERROR_INVALID_INPUT = 4; |
||||
protected const ERROR_MISSING_PARAMETER = 5; |
||||
protected const ERROR_INVALID_PASSWORD = 6; |
||||
|
||||
protected const STATUS_OK = 'success'; |
||||
protected const STATUS_ERROR = 'error'; |
||||
|
||||
protected const ERROR_DESCRIPTIONS = [ |
||||
self::ERROR_OK => 'success', |
||||
self::ERROR_INVALID_AUTH => 'invalid or expired authorization', |
||||
self::ERROR_INVALID_LOGIN => 'no login associated with this token', |
||||
self::ERROR_INVALID_TOKEN => 'invalid or expired token', |
||||
self::ERROR_INVALID_INPUT => 'invalid input', |
||||
self::ERROR_MISSING_PARAMETER => "parameter '%s' is missing", |
||||
self::ERROR_INVALID_PASSWORD => 'invalid username or password', |
||||
]; |
||||
|
||||
protected const PARAMETER_AUTH = 'auth'; |
||||
protected const PARAMETER_CALLBACK_URL = 'callback'; |
||||
protected const PARAMETER_REDIRECT = 'redirect'; |
||||
protected const PARAMETER_TOKEN = 'token'; |
||||
protected const PARAMETER_USERNAME = 'username'; |
||||
protected const PARAMETER_PASSWORD = 'password'; |
||||
} |
||||
@ -0,0 +1,29 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Core; |
||||
|
||||
class AutoLoader |
||||
{ |
||||
private static $patterns = []; |
||||
private static $replacements = []; |
||||
|
||||
public static function register() |
||||
{ |
||||
if (empty(self::$patterns)) { |
||||
self::$patterns = [ |
||||
'/^' . explode('\\', self::class)[0] . '/', |
||||
'/\\\\/', |
||||
]; |
||||
} |
||||
if (empty(self::$replacements)) { |
||||
self::$replacements = ['', '/']; |
||||
} |
||||
spl_autoload_register(self::class . '::autoLoader'); |
||||
} |
||||
|
||||
public static function autoLoader(string $class) |
||||
{ |
||||
$class = preg_replace(self::$patterns, self::$replacements, $class); |
||||
require_once(dirname(__DIR__) . $class . '.php'); |
||||
} |
||||
} |
||||
@ -0,0 +1,30 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Core; |
||||
|
||||
class Config |
||||
{ |
||||
private static $config = []; |
||||
|
||||
private static function load(): void |
||||
{ |
||||
if (empty(self::$config)) { |
||||
foreach (glob(dirname(__DIR__) . '/Config/*.php') as $config) { |
||||
$section = pathinfo($config, PATHINFO_FILENAME); |
||||
self::$config[$section] = include($config); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static function getSection(string $section): array |
||||
{ |
||||
self::load(); |
||||
return self::$config[$section] ?? []; |
||||
} |
||||
|
||||
public static function getValue(string $section, string $name): ?string |
||||
{ |
||||
self::load(); |
||||
return self::$config[$section][$name] ?? null; |
||||
} |
||||
} |
||||
@ -0,0 +1,109 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Core; |
||||
|
||||
class Controller |
||||
{ |
||||
|
||||
private static $charset = 'UTF-8'; |
||||
private static $contentType = 'application/json'; |
||||
private static $responseCode = 200; |
||||
|
||||
public static function run(string $function): void |
||||
{ |
||||
if ($function === '') { |
||||
$function = 'index'; |
||||
} else { |
||||
$function = self::camelize($function); |
||||
} |
||||
if (method_exists(static::class, $function)) { |
||||
$html = static::$function(); |
||||
$header = 'Content-Type: ' . self::$contentType; |
||||
if (null !== self::$charset) { |
||||
$header .= "; charset=" . self::$charset; |
||||
} |
||||
header($header, true, self::$responseCode); |
||||
echo $html; |
||||
} else { |
||||
self::page404(); |
||||
} |
||||
} |
||||
|
||||
protected static function camelize(string $input): string |
||||
{ |
||||
$ret = []; |
||||
foreach (explode('_', $input) as $part) { |
||||
$ret[] = ucfirst($part); |
||||
} |
||||
return implode('', $ret); |
||||
} |
||||
|
||||
protected static function getPost(): ?array |
||||
{ |
||||
$input = file_get_contents('php://input'); |
||||
return json_decode($input, true); |
||||
} |
||||
|
||||
protected static function requireMethod(string $method): void |
||||
{ |
||||
if ($method !== $_SERVER['REQUEST_METHOD']) { |
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 405 Method Not Allowed', true, 405); |
||||
die("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" . |
||||
"<html><head>\n" . |
||||
"<title>405 Method Not Allowed</title>\n" . |
||||
"</head><body>\n" . |
||||
"<h1>Method Not Allowed</h1>\n" . |
||||
"<p>The requested method " . $_SERVER['REQUEST_METHOD'] . " is not allowed for this resource.</p>\n" . |
||||
self::serverSignature()); |
||||
} |
||||
} |
||||
|
||||
protected static function page404(): string |
||||
{ |
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true, 404); |
||||
die("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" . |
||||
"<html><head>\n" . |
||||
"<title>404 Not Found</title>\n" . |
||||
"</head><body>\n" . |
||||
"<h1>Not Found</h1>\n" . |
||||
"<p>The requested URL was not found on this server.</p>\n" . |
||||
self::serverSignature()); |
||||
} |
||||
|
||||
public static function redirect(string $location) |
||||
{ |
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 302 Found', true, 302); |
||||
header('Location: ' . $location, true); |
||||
die("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" . |
||||
"<html><head>\n" . |
||||
"<title>302 Found</title>\n" . |
||||
"</head><body>\n" . |
||||
"<h1>Found</h1>\n" . |
||||
"<p>The document has moved <a href=\"" . $location . "\">here</a>.</p>\n" . |
||||
self::serverSignature()); |
||||
} |
||||
|
||||
private static function serverSignature(): string |
||||
{ |
||||
return |
||||
"<hr>\n" . |
||||
"<address>" . $_SERVER['SERVER_SOFTWARE'] . " Server at " . $_SERVER['SERVER_NAME'] . " Port " . |
||||
$_SERVER['SERVER_PORT'] . "</address>\n" . |
||||
"</body></html>\n"; |
||||
} |
||||
|
||||
protected static function setCharset(string $charset): void |
||||
{ |
||||
self::$charset = $charset; |
||||
} |
||||
|
||||
protected static function setContentType(string $contentType): void |
||||
{ |
||||
self::$contentType = $contentType; |
||||
} |
||||
|
||||
protected static function setResponseCode(string $responseCode): void |
||||
{ |
||||
self::$responseCode = $responseCode; |
||||
} |
||||
} |
||||
@ -0,0 +1,160 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Core; |
||||
|
||||
use PDO; |
||||
use PDOStatement; |
||||
|
||||
class Model |
||||
{ |
||||
private static $database = null; |
||||
private static $lastErrorMessage = ''; |
||||
|
||||
private static function connect(): void |
||||
{ |
||||
if (null === self::$database) { |
||||
$config = Config::getSection('database'); |
||||
self::$database = new PDO( |
||||
'mysql:host=' . $config['host'] . ';dbname=' . $config['database'], |
||||
$config['username'], |
||||
$config['password'], |
||||
); |
||||
} |
||||
} |
||||
|
||||
protected static function delete(string $table, array $conditions): bool |
||||
{ |
||||
$where = $parameters = []; |
||||
foreach ($conditions as $condition) { |
||||
switch (count($condition)) { |
||||
case 1: |
||||
$where[] = '`' . $condition[0] . '`'; |
||||
break; |
||||
case 2: |
||||
$where[] = '`' . $condition[0] . '`=:' . $condition[0]; |
||||
$parameters[':' . $condition[0]] = $condition[1]; |
||||
break; |
||||
case 3: |
||||
$where[] = '`' . $condition[0] . '`' . $condition[1] . ':' . $condition[0]; |
||||
$parameters[':' . $condition[0]] = $condition[2]; |
||||
break; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
$sql = "DELETE FROM `$table` WHERE (" . implode(") AND (", $where) . ")"; |
||||
$statement = self::prepare($sql, $parameters); |
||||
return self::execute($statement); |
||||
} |
||||
|
||||
private static function execute(PDOStatement $statement): bool |
||||
{ |
||||
if ($ret = $statement->execute()) { |
||||
self::$lastErrorMessage = ''; |
||||
} else { |
||||
$errorInfo = $statement->errorInfo(); |
||||
self::$lastErrorMessage = $errorInfo[0] . ': ' . $errorInfo[2]; |
||||
} |
||||
return $ret; |
||||
} |
||||
|
||||
protected static function getLastErrorMessage(): string |
||||
{ |
||||
return self::$lastErrorMessage; |
||||
} |
||||
|
||||
private static function getParameters(array $conditions): array |
||||
{ |
||||
$parameters = []; |
||||
foreach ($conditions as $field => $value) { |
||||
$parameters[":$field"] = $value; |
||||
} |
||||
return $parameters; |
||||
} |
||||
|
||||
private static function getSelectQuery(string $table, array $fields, array $conditions): string |
||||
{ |
||||
$where = []; |
||||
foreach ($conditions as $field => $value) { |
||||
$where[] = "(`$field`=:$field)"; |
||||
} |
||||
return "SELECT `" . implode('`,`', $fields) . "` FROM `$table` WHERE " . implode(' AND ', $where); |
||||
} |
||||
|
||||
protected static function insert(string $table, array $fields): bool |
||||
{ |
||||
$fields['created_at'] = $fields['modified_at'] = date('Y-m-d H:i:s'); |
||||
$parameters = self::getParameters($fields); |
||||
$sql = "INSERT INTO `$table`(`" . implode('`,`', array_keys($fields)) . "`) VALUES (" . |
||||
implode(',', array_keys($parameters)) . ')'; |
||||
$statement = self::prepare($sql, $parameters); |
||||
return self::execute($statement); |
||||
} |
||||
|
||||
private static function prepare(string $sql, array $parameters): PDOStatement |
||||
{ |
||||
self::connect(); |
||||
$statement = self::$database->prepare($sql); |
||||
foreach ($parameters as $name => $value) { |
||||
if (is_bool($value)) { |
||||
$type = PDO::PARAM_BOOL; |
||||
} elseif (is_int($value)) { |
||||
$type = PDO::PARAM_INT; |
||||
} else { |
||||
$type = PDO::PARAM_STR; |
||||
} |
||||
$statement->bindValue($name, $value, $type); |
||||
} |
||||
return $statement; |
||||
} |
||||
|
||||
protected static function select(string $table, array $fields, array $conditions): ?array |
||||
{ |
||||
$parameters = self::getParameters($conditions); |
||||
$sql = self::getSelectQuery($table, $fields, $conditions); |
||||
$statement = self::prepare($sql, $parameters); |
||||
self::execute($statement); |
||||
$ret = $statement->fetchAll(PDO::FETCH_ASSOC); |
||||
$statement->closeCursor(); |
||||
return false === $ret ? null : $ret; |
||||
} |
||||
|
||||
protected static function selectOne(string $table, array $fields, array $conditions): ?array |
||||
{ |
||||
$parameters = self::getParameters($conditions); |
||||
$sql = self::getSelectQuery($table, $fields, $conditions) . ' LIMIT 1'; |
||||
$statement = self::prepare($sql, $parameters); |
||||
self::execute($statement); |
||||
$ret = $statement->fetch(PDO::FETCH_ASSOC); |
||||
$statement->closeCursor(); |
||||
return false === $ret ? null : $ret; |
||||
} |
||||
|
||||
protected static function selectSingleValue(string $table, string $field, array $conditions) |
||||
{ |
||||
$parameters = self::getParameters($conditions); |
||||
$sql = self::getSelectQuery($table, [$field], $conditions) . ' LIMIT 1'; |
||||
$statement = self::prepare($sql, $parameters); |
||||
self::execute($statement); |
||||
$ret = $statement->fetchColumn(); |
||||
$statement->closeCursor(); |
||||
return false === $ret ? null : $ret; |
||||
} |
||||
|
||||
protected static function update(string $table, array $fields, array $conditions): bool |
||||
{ |
||||
$fields['modified_at'] = date('Y-m-d H:i:s'); |
||||
$where = $parameters = $set = []; |
||||
foreach ($fields as $field => $value) { |
||||
$set[] = "`$field`=:p$field"; |
||||
$parameters[":p$field"] = $value; |
||||
} |
||||
foreach ($conditions as $field => $value) { |
||||
$where[] = "(`$field`=:w$field)"; |
||||
$parameters[":w$field"] = $value; |
||||
} |
||||
$sql = "UPDATE `$table` SET " . implode(',', $set) . " WHERE " . implode(',', $where); |
||||
$statement = self::prepare($sql, $parameters); |
||||
return self::execute($statement); |
||||
} |
||||
} |
||||
@ -0,0 +1,96 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Models; |
||||
|
||||
use MwgAuth\Core\Model; |
||||
|
||||
class Cns extends Model |
||||
{ |
||||
private static $policyValide = [ |
||||
'1.3.76.16.2.1', // CNS |
||||
'1.3.76.47.4', // CIE |
||||
'1.3.6.1.4.1.29741.1.1.10', // CNS-Like |
||||
'1.3.159.1.10.1', // Actalis |
||||
'1.3.76.36.1.1.3', // CNS-Like Infocert |
||||
]; |
||||
private $certificato; |
||||
private $codiceFiscale; |
||||
|
||||
public function __construct(string $certificato) |
||||
{ |
||||
if (null !== $certificato) { |
||||
$this->certificato = openssl_x509_parse($certificato, false); |
||||
$this->verificaCertificato(); |
||||
// https://www.agid.gov.it/sites/default/files/repository_files/documentazione_trasparenza/strutturacertificatoautenticazionecns_v1.1_.pdf |
||||
if (isset($this->certificato['subject']['serialNumber'])) { |
||||
$this->codiceFiscale = preg_replace('/^[A-Za-z]{2}:/', '', $this->certificato['subject']['serialNumber']); |
||||
} else { |
||||
$this->codiceFiscale = explode('/', $this->certificato['subject']['commonName'])[0]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public function getCertificato(): array |
||||
{ |
||||
return $this->certificato; |
||||
} |
||||
|
||||
public function getCodiceFiscale(): ?string |
||||
{ |
||||
return $this->codiceFiscale; |
||||
} |
||||
|
||||
public function getCognome(): ?string |
||||
{ |
||||
if (isset($this->certificato['subject']['surname'])) { |
||||
$ret = $this->certificato['subject']['surname']; |
||||
} elseif (isset($this->certificato['subject']['organizationalUnitName'])) { |
||||
$ret = $this->certificato['subject']['organizationalUnitName']; |
||||
if (is_array($ret)) { |
||||
$ret = implode('/', $ret); |
||||
} |
||||
} else { |
||||
$ret = $this->codiceFiscale; |
||||
} |
||||
return $ret; |
||||
} |
||||
|
||||
public function getNome(): ?string |
||||
{ |
||||
return $this->certificato['subject']['givenName'] ?? $this->codiceFiscale; |
||||
} |
||||
|
||||
public function verificaPolicyCertificato(): bool |
||||
{ |
||||
preg_match_all( |
||||
'/Policy: ([0-9\.]+)/', |
||||
$this->certificato['extensions']['certificatePolicies'], |
||||
$policies |
||||
); |
||||
foreach ($policies[1] as $policy) { |
||||
if (in_array($policy, self::$policyValide)) { |
||||
return true; |
||||
} |
||||
} |
||||
$this->salvaCertificato(); |
||||
return false; |
||||
} |
||||
|
||||
private function verificaCertificato() |
||||
{ |
||||
// if (!isset($this->certificato['subject']['commonName']) || |
||||
// !isset($this->certificato['subject']['surname']) || |
||||
// !isset($this->certificato['subject']['givenName']) || |
||||
// isset($this->certificato['subject']['serialNumber']) || |
||||
// !isset($this->certificato['extensions']['certificatePolicies'])) { |
||||
$this->salvaCertificato(); |
||||
// } |
||||
} |
||||
|
||||
private function salvaCertificato() |
||||
{ |
||||
$file = '/var/www/html/cns/policy/cert-' . sha1($this->certificato['subject']['commonName']); |
||||
@file_put_contents($file . '.txt', print_r($this->certificato, true)); |
||||
@file_put_contents($file . '.cer', $_SERVER['SSL_CLIENT_CERT']); |
||||
} |
||||
} |
||||
@ -0,0 +1,18 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Models; |
||||
|
||||
use MwgAuth\Core\Model; |
||||
|
||||
class SiteConfig extends Model |
||||
{ |
||||
private static $config = []; |
||||
|
||||
public static function getSetting(string $key): string |
||||
{ |
||||
if (!isset(self::$config[$key])) { |
||||
self::$config[$key] = self::selectSingleValue('config', 'value', ['key' >= $key]); |
||||
} |
||||
return self::$config[$key]; |
||||
} |
||||
} |
||||
@ -0,0 +1,31 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Models; |
||||
|
||||
use MwgAuth\Core\Model; |
||||
|
||||
class Storage extends Model |
||||
{ |
||||
public static function fileGetContents(string $fileName): ?string |
||||
{ |
||||
$fullName = self::getFullName($fileName); |
||||
if (file_exists($fullName)) { |
||||
return file_get_contents($fullName); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public static function filePutContents(string $fileName, string $data, int $flags = 0) |
||||
{ |
||||
$fullName = self::getFullName($fileName); |
||||
$umask = umask(0); |
||||
mkdir(dirname($fullName), 0777, true); |
||||
file_put_contents($fullName, $data, $flags); |
||||
umask($umask); |
||||
} |
||||
|
||||
private static function getFullName(string $fileName): string |
||||
{ |
||||
return $_SERVER['DOCUMENT_ROOT'] . '/storage/' . $fileName; |
||||
} |
||||
} |
||||
@ -0,0 +1,137 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Models; |
||||
|
||||
use MwgAuth\Core\Config; |
||||
use MwgAuth\Core\Model; |
||||
|
||||
class User extends Model |
||||
{ |
||||
private $id; |
||||
private $auth; |
||||
private $userName; |
||||
|
||||
public static function load(string $userName, string $password, string $remoteAddress): ?User |
||||
{ |
||||
$password = self::hashPassword($password); |
||||
#file_put_contents('/var/www/storage/password.txt', "$userName\n$password\n$remoteAddress\n"); |
||||
$rows = self::select('users', ['id', 'username', 'remote'], ['username' => $userName, 'password' => $password]); |
||||
foreach ($rows as $row) { |
||||
if (fnmatch($row['remote'], $remoteAddress)) { |
||||
return new User($row['id'], $row['username']); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public function __construct(int $id, string $userName, ?string $auth = null) |
||||
{ |
||||
$this->id = $id; |
||||
$this->userName = $userName; |
||||
if (null === $auth) { |
||||
do { |
||||
$this->auth = sha1(random_int(PHP_INT_MIN, PHP_INT_MAX)); // /dev/urandom |
||||
$result = $this->insert('sessions', [ |
||||
'auth' => $this->auth, |
||||
'user_id' => $this->id, |
||||
'username' => $this->userName, |
||||
]); |
||||
} while (!$result); |
||||
} else { |
||||
$this->auth = $auth; |
||||
} |
||||
} |
||||
|
||||
|
||||
public static function cleanUp(): void |
||||
{ |
||||
$timestamp = date('Y-m-d H:i:s', time() - 900); |
||||
self::delete('tokens', [['modified_at', '<', $timestamp]]); |
||||
self::delete('sessions', [['modified_at', '<', $timestamp]]); |
||||
} |
||||
|
||||
public function getAuth(): string |
||||
{ |
||||
return $this->auth; |
||||
} |
||||
|
||||
public static function getCallback(string $token): ?string |
||||
{ |
||||
return self::selectSingleValue('tokens', 'callback', ['token' => $token]); |
||||
} |
||||
|
||||
public function getLoginData(string $token): ?array |
||||
{ |
||||
$ret = $this->select('logins', ['codice_fiscale', 'nome', 'cognome'], ['token' => $token]); |
||||
return empty($ret) ? null : $ret[0]; |
||||
} |
||||
|
||||
public function getId(): int |
||||
{ |
||||
return $this->id; |
||||
} |
||||
|
||||
public function getToken(string $callback): string |
||||
{ |
||||
do { |
||||
$token = sha1(random_int(PHP_INT_MIN, PHP_INT_MAX)); // /dev/urandom |
||||
$result = $this->insert('tokens', [ |
||||
'token' => $token, |
||||
'auth' => $this->auth, |
||||
'callback' => $callback, |
||||
]); |
||||
} while (!$result); |
||||
$this->touchAuth($this->auth); |
||||
return $token; |
||||
} |
||||
|
||||
public function getUserName(): string |
||||
{ |
||||
return $this->userName; |
||||
} |
||||
|
||||
public static function setLoginData(string $token, string $codiceFiscale, string $nome, string $cognome): bool |
||||
{ |
||||
return self::insert('logins', [ |
||||
'token' => $token, |
||||
'codice_fiscale' => $codiceFiscale, |
||||
'nome' => $nome, |
||||
'cognome' => $cognome, |
||||
]); |
||||
} |
||||
|
||||
public static function verifyAuth(string $auth): ?User |
||||
{ |
||||
$row = self::selectOne('sessions', ['user_id', 'username', 'auth'], ['auth' => $auth]); |
||||
if (null === $row) { |
||||
return null; |
||||
} |
||||
self::touchAuth($row['auth']); |
||||
return new User($row['user_id'], $row['username'], $row['auth']); |
||||
} |
||||
|
||||
public function verifyToken(string $token): bool |
||||
{ |
||||
$row = $this->select('tokens', ['token'], ['auth' => $this->auth, 'token' => $token]); |
||||
return count($row) > 0; |
||||
} |
||||
|
||||
private static function getSiteKey(): string |
||||
{ |
||||
return Config::getValue('site', 'key'); |
||||
} |
||||
|
||||
private static function hashPassword(string $password): string |
||||
{ |
||||
$siteKey = self::getSiteKey(); |
||||
return hash('sha256', $siteKey . $password); |
||||
} |
||||
|
||||
/** |
||||
* Ha il solo effetto di aggiornare il campo "modified_at" della sessione |
||||
*/ |
||||
private static function touchAuth(string $auth): bool |
||||
{ |
||||
return self::update('sessions', [], ['auth' => $auth]); |
||||
} |
||||
} |
||||
@ -0,0 +1,6 @@
|
||||
<?php |
||||
|
||||
namespace MwgAuth\Core; |
||||
|
||||
require_once(__DIR__.'/Core/AutoLoader.php'); |
||||
AutoLoader::register(); |
||||
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env php |
||||
<?php |
||||
|
||||
use MwgAuth\Models\User; |
||||
|
||||
require('bootstrap.php'); |
||||
|
||||
User::cleanUp(); |
||||
@ -0,0 +1,5 @@
|
||||
#!/bin/bash |
||||
for a in $(seq 0 $(($(ls html/cns/policy/*.txt | wc -l) - 1))); do |
||||
echo $a |
||||
php int.php $a | grep 'Codice fiscale:' |
||||
done |
||||
@ -0,0 +1,6 @@
|
||||
<IfModule mod_rewrite.c> |
||||
RewriteEngine On |
||||
RewriteCond %{REQUEST_FILENAME} !-f |
||||
RewriteCond %{REQUEST_FILENAME} !-d |
||||
RewriteRule . index.php [L] |
||||
</IfModule> |
||||
@ -0,0 +1,8 @@
|
||||
<?php |
||||
|
||||
use MwgAuth\Controllers\ControllerV1; |
||||
|
||||
require(dirname($_SERVER['DOCUMENT_ROOT']) . '/App/bootstrap.php'); |
||||
preg_match('@/([_0-9A-Za-z]+)\.cgi$@', $_SERVER['REQUEST_URI'], $matches); |
||||
$function = $matches[1] ?? ''; |
||||
ControllerV1::run($function); |
||||
@ -0,0 +1,21 @@
|
||||
<?php |
||||
|
||||
use MwgAuth\Core\Controller; |
||||
use MwgAuth\Models\Cns; |
||||
use MwgAuth\Models\User; |
||||
|
||||
require_once(dirname($_SERVER['DOCUMENT_ROOT']) . '/App/bootstrap.php'); |
||||
$cns = new Cns($_SERVER['SSL_CLIENT_CERT']); |
||||
if (!$cns->verificaPolicyCertificato()) { |
||||
Controller::redirect('/cns/policy-error.html'); |
||||
} |
||||
$token = $_GET['t'] ?? null; |
||||
if (null === $token) { |
||||
include($_SERVER['DOCUMENT_ROOT'] . '/errors/generic.php'); |
||||
} else { |
||||
if (null !== $cns->getCodiceFiscale()) { |
||||
User::setLoginData($token, $cns->getCodiceFiscale(), $cns->getNome(), $cns->getCognome()); |
||||
} |
||||
$callback = User::getCallback($token); |
||||
Controller::redirect($callback); |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> |
||||
<title>Policy Error</title> |
||||
</head> |
||||
<body> |
||||
<h1>Errore Certificate Policies (Object ID: 2.5.29.32)<br></h1> |
||||
<h2>Non è stato possibile autenticarti.</h2> |
||||
<p>Il certificato presentato è valido ma non rispetta le <strong>Certificate Policies (Object ID: |
||||
2.5.29.32)</strong> previste per la CIE e TS-CNS.</p> |
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,39 @@
|
||||
* { |
||||
font-family: 'Titillium Web', sans-serif; |
||||
} |
||||
|
||||
.btn-label, #spid-button .spid-button-icon { |
||||
position: relative; |
||||
left: -12px; |
||||
display: inline-block; |
||||
padding: 6px 12px; |
||||
background: rgba(0,0,0,0.15); |
||||
border-radius: 3px 0 0 3px; |
||||
} |
||||
.btn-labeled { |
||||
padding-top: 0; |
||||
padding-bottom: 0; |
||||
} |
||||
.btn { |
||||
margin-bottom:10px; |
||||
border-radius: 0; |
||||
font-size: 16px; |
||||
} |
||||
hr.solid { |
||||
border-top: 1px solid #ccc; |
||||
width: 40%; |
||||
margin-left: 0; |
||||
} |
||||
|
||||
#spid-button .spid-button { |
||||
margin: 0; |
||||
border-radius: 0; |
||||
padding: 0 0.75rem; |
||||
height: auto; |
||||
font-size: 16px; |
||||
} |
||||
|
||||
.spid-button-text{ |
||||
vertical-align: initial !important; |
||||
font-weight: normal; |
||||
} |
||||
@ -0,0 +1,38 @@
|
||||
<?php require_once('init.php'); ?><!doctype html>
|
||||
<html lang="it"> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
<title>Autenticazione Regione Siciliana</title> |
||||
<link rel="stylesheet" |
||||
href="https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap"> |
||||
<link href="/css/bootstrap.css" rel="stylesheet"> |
||||
<link href="/css/custom.css" rel="stylesheet"> |
||||
</head> |
||||
<body class="bg-light"> |
||||
<div class="container"> |
||||
<div class="row mt-3"> |
||||
<div class="col-xs-12 col-sm-12 pb-4"> |
||||
<img src="/images/logo-regione.png"> |
||||
</div> |
||||
</div> |
||||
<div class="row"> |
||||
<div class="col-xs-12 col-sm-12"> |
||||
<h2>Errore di autenticazione</h2> |
||||
<p>Si è verificato un errore inatteso durante l'autenticazione. Si prega di riprovare più tardi.</p> |
||||
<?php if (null !== $callback) { ?> |
||||
<div class="text-center d-block"> |
||||
<a class="btn btn-primary btn-lg mt-4 text-center " href="<?= $callback ?>">Torna al portale</a>
|
||||
</div> |
||||
<?php } ?> |
||||
</div> |
||||
</div> |
||||
<div class="row mt-3"> |
||||
<div class="col-xs-12 col-sm-12 pb-4 text-center"> |
||||
<p>Regione Siciliana - D.R.T.</p> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,22 @@
|
||||
<?php |
||||
|
||||
use MwgAuth\Models\User; |
||||
|
||||
require_once(dirname($_SERVER['DOCUMENT_ROOT']) . '/App/bootstrap.php'); |
||||
|
||||
$callback = null; |
||||
parse_str($_SERVER['REDIRECT_QUERY_STRING'], $get); |
||||
$token = $get['t'] ?? null; |
||||
if (null !== $token) { |
||||
$callback = User::getCallback($token); |
||||
$parsed = parse_url($callback); |
||||
if (isset($parsed['scheme']) && isset($parsed['host'])) { |
||||
$callback = $parsed['scheme'] . '://' . $parsed['host']; |
||||
if (($parsed['scheme'] === 'http' && $parsed['port'] != 80) |
||||
|| ($parsed['scheme'] === 'https' && $parsed['port'] != 443) |
||||
) { |
||||
$callback .= ':' . $parsed['port']; |
||||
} |
||||
$callback .= '/'; |
||||
} |
||||
} |
||||
@ -0,0 +1,39 @@
|
||||
<?php require_once('init.php'); ?><!doctype html>
|
||||
<html lang="it"> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
<title>Autenticazione Regione Siciliana</title> |
||||
<link href="https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap" rel="stylesheet"> |
||||
<link href="/css/bootstrap.css" rel="stylesheet"> |
||||
<link href="/css/custom.css" rel="stylesheet"> |
||||
</head> |
||||
<body class="bg-light"> |
||||
<div class="container"> |
||||
<div class="row mt-3"> |
||||
<div class="col-xs-12 col-sm-12 pb-4"> |
||||
<img src="/images/logo-regione.png"> |
||||
</div> |
||||
</div> |
||||
<div class="row"> |
||||
<div class="col-xs-12 col-sm-12"> |
||||
<h2>Errore autenticazione con CNS</h2> |
||||
<p>Non è stato possibile autenticarti. Verifica che il lettore sia correttamente collegato e |
||||
funzionante, e che la carta CIE o TS-CNS sia correttamente inserita o appoggiata sul lettore nel |
||||
momento in cui procedi con l'accesso.</p> |
||||
<?php if (null !== $callback) { ?> |
||||
<div class="text-center d-block"> |
||||
<a class="btn btn-primary btn-lg mt-4 text-center " href="<?= $callback ?>">Torna al portale</a>
|
||||
</div> |
||||
<?php } ?> |
||||
</div> |
||||
</div> |
||||
<div class="row mt-3"> |
||||
<div class="col-xs-12 col-sm-12 pb-4 text-center"> |
||||
<p>Regione Siciliana - D.R.T.</p> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
</body> |
||||
</html> |
||||
|
Dopo Larghezza: | Altezza: | Dimensione: 24 KiB |
|
Dopo Larghezza: | Altezza: | Dimensione: 20 KiB |
|
Dopo Larghezza: | Altezza: | Dimensione: 2.4 KiB |
@ -0,0 +1,63 @@
|
||||
<!doctype html> |
||||
<html lang="it"> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
<title>Autenticazione Regione Siciliana</title> |
||||
<link href="https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap" rel="stylesheet"> |
||||
<link href="/css/bootstrap.css" rel="stylesheet"> |
||||
<link href="/css/custom.css" rel="stylesheet"> |
||||
</head> |
||||
<body class="bg-light"> |
||||
<div class="container"> |
||||
<div class="row mt-3"> |
||||
<div class="col-12 pb-4"> |
||||
<img src="/images/logo-regione.png"> |
||||
</div> |
||||
</div> |
||||
<div class="row"> |
||||
<div class="col-md-6 col-xs-12"> |
||||
<h2>Accedi con CNS</h2> |
||||
<hr class="solid"> |
||||
<p> |
||||
La Carta Nazionale dei Servizi o CNS è una smart card o una chiavetta USB che contiene un |
||||
"certificato digitale" di autenticazione personale, utile per accedere ai servizi online della |
||||
Regione Siciliana. |
||||
</p> |
||||
<form action="/cns/" method="GET"> |
||||
<input type="hidden" name="t" value="<?= @$_GET['t'] ?>">
|
||||
<button type="submit" class="btn btn-labeled btn-primary"> |
||||
<span class="btn-label"> |
||||
<img width="30" src="images/cns-icon.png"> |
||||
</span> Entra con CNS |
||||
</button> |
||||
</form> |
||||
</div> |
||||
<div class="col-md-6 col-xs-12"> |
||||
<h2>Accedi con SPID o CieID</h2> |
||||
<hr class="solid"> |
||||
<p> |
||||
SPID è il sistema di accesso che consente di utilizzare, con un'identità digitale unica, i servizi |
||||
online della Pubblica Amministrazione e dei privati accreditati. Se sei già in possesso di |
||||
un'identità digitale, accedi con le credenziali del tuo gestore. Se non hai ancora un'identità |
||||
digitale, richiedila ad uno dei gestori. |
||||
</p> |
||||
<form action="/spid/" method="GET"> |
||||
<input type="hidden" name="t" value="<?= @$_GET['t'] ?>">
|
||||
<button type="submit" class="btn btn-labeled btn-primary"> |
||||
<span class="btn-label"> |
||||
<img width="30" src="images/spid-icon.png"> |
||||
</span> Entra con SPID o CieID |
||||
</button> |
||||
</form> |
||||
</div> |
||||
</div> |
||||
<div class="row mt-3"> |
||||
<div class="col-xs-12 col-sm-12 pb-4 text-center"> |
||||
<p>Regione Siciliana - D.R.T.</p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<script src="/js/jquery.min.js"></script> |
||||
</body> |
||||
</html> |
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,12 @@
|
||||
{ |
||||
"keys": [ |
||||
{ |
||||
"kty": "RSA", |
||||
"alg": "RS256", |
||||
"use": "sig", |
||||
"kid": "auth", |
||||
"n": "0guv1uiJLOulgTJN7O4m+Hrf9N80ByPnncssc7ule+3XtSdgSbUEG4ztZq+TsBoAmAwsE44LxY4FvYxy39n1cZrw9EeuGY62bMulh9qdScHyHoUQwPGz6xLDQGJ0orr5THcFfLISGJdXutND9bNsxlPwC328Nbvym2SEp6NL8g77tGlg1dDGNybs6lAeUTUWS1qXbWEMl3VhJZa711BUstCujZsL2WyEsupVr80tWYobeCxuys/XBnbWbuPLiFMXCaGUnEzaoc1N4bF9AO6LrGphMG9JLAcPbNyF/DIFYn2Mlvy7eaXkyFIom7GJejpZexABhtKDMSLBHnDHaneLrkwmy0WogJpVSuTYL0nJdfPT1bT8ONx8YGikWQS/b8gtk/u/QQRBGtsBTA5a4Begyo8LmqLzeXBilqopviyIHpJ3kOU2iZo4Fj5qSjnAMT2IGuKKDhrjCGjito40GtYQEqkxbZf+Zz8QSuf4EWQt4oXLVYqD1WiSUk1MQ93ZT2MwCyh+jDG7m67dkcikDJa7yQYi7knDEGKmhBCBu3u/q2042vlSUe/OJIeBpqB16pZUZxPAKr1LUjURCKeHA2R7f3N3oC4jjVYrdgCvrOV/ZcJpsXR4EpyChgRtK0owXFCs+981xbnlBLSBazJwUxB+LbRJoHRiUc+TuqFM38CQJ9M=", |
||||
"e": "AQAB" |
||||
} |
||||
] |
||||
} |
||||
@ -0,0 +1,27 @@
|
||||
{ |
||||
"client_id": "https://auth.mwg.it", |
||||
"client_name": "Autenticazione Lavori Pubblici Sicilia", |
||||
"grant_types": [ |
||||
"authorization_code", |
||||
"refresh_token" |
||||
], |
||||
"jwks_uri": "https://auth.mwg.it/openidc/jwks.json", |
||||
"jwks": { |
||||
"keys": [ |
||||
{ |
||||
"kty": "RSA", |
||||
"alg": "RS256", |
||||
"use": "sig", |
||||
"kid": "auth", |
||||
"n": "0guv1uiJLOulgTJN7O4m+Hrf9N80ByPnncssc7ule+3XtSdgSbUEG4ztZq+TsBoAmAwsE44LxY4FvYxy39n1cZrw9EeuGY62bMulh9qdScHyHoUQwPGz6xLDQGJ0orr5THcFfLISGJdXutND9bNsxlPwC328Nbvym2SEp6NL8g77tGlg1dDGNybs6lAeUTUWS1qXbWEMl3VhJZa711BUstCujZsL2WyEsupVr80tWYobeCxuys/XBnbWbuPLiFMXCaGUnEzaoc1N4bF9AO6LrGphMG9JLAcPbNyF/DIFYn2Mlvy7eaXkyFIom7GJejpZexABhtKDMSLBHnDHaneLrkwmy0WogJpVSuTYL0nJdfPT1bT8ONx8YGikWQS/b8gtk/u/QQRBGtsBTA5a4Begyo8LmqLzeXBilqopviyIHpJ3kOU2iZo4Fj5qSjnAMT2IGuKKDhrjCGjito40GtYQEqkxbZf+Zz8QSuf4EWQt4oXLVYqD1WiSUk1MQ93ZT2MwCyh+jDG7m67dkcikDJa7yQYi7knDEGKmhBCBu3u/q2042vlSUe/OJIeBpqB16pZUZxPAKr1LUjURCKeHA2R7f3N3oC4jjVYrdgCvrOV/ZcJpsXR4EpyChgRtK0owXFCs+981xbnlBLSBazJwUxB+LbRJoHRiUc+TuqFM38CQJ9M=", |
||||
"e": "AQAB" |
||||
} |
||||
] |
||||
}, |
||||
"redirect_uris": [ |
||||
"https://auth.mwg.it/spid/callback/" |
||||
], |
||||
"response_types": [ |
||||
"code" |
||||
] |
||||
} |
||||
@ -0,0 +1,23 @@
|
||||
<?php |
||||
|
||||
use MwgAuth\Core\Controller; |
||||
use MwgAuth\Models\User; |
||||
|
||||
require_once(dirname($_SERVER['DOCUMENT_ROOT']) . '/App/bootstrap.php'); |
||||
$token = $_GET['t'] ?? null; |
||||
if ('' === ($token ?? '')) { |
||||
include($_SERVER['DOCUMENT_ROOT'] . '/errors/generic.php'); |
||||
} else { |
||||
User::setLoginData( |
||||
$token, |
||||
$_SERVER['SPID_claim_fiscalNumber'], |
||||
$_SERVER['SPID_claim_given_name'], |
||||
$_SERVER['SPID_claim_family_name'] |
||||
); |
||||
$callback = User::getCallback($token); |
||||
if (null === $callback) { |
||||
include($_SERVER['DOCUMENT_ROOT'] . '/errors/generic.php'); |
||||
} else { |
||||
Controller::redirect($callback); |
||||
} |
||||
} |
||||
@ -0,0 +1,18 @@
|
||||
<?php |
||||
|
||||
if (php_sapi_name() != 'cli') { |
||||
die(); |
||||
} |
||||
require_once('App/Core/Model.php'); |
||||
require_once('App/Models/Cns.php'); |
||||
|
||||
$files = glob('html/cns/policy/*.cer'); |
||||
if (count($files)) { |
||||
$idx = $argc > 1 ? intval($argv[1]) : 0; |
||||
$crt = file_get_contents($files[$idx]); |
||||
$cns = new \MwgAuth\Models\Cns($crt); |
||||
echo 'Codice fiscale: ' . $cns->getCodiceFiscale() . "\n"; |
||||
echo 'Cognome: ' . $cns->getCognome() . "\n"; |
||||
echo 'Nome: ' . $cns->getNome() . "\n"; |
||||
echo 'Valido: ' . ($cns->verificaPolicyCertificato() ? 'true' : 'false') . "\n"; |
||||
} |
||||
@ -0,0 +1 @@
|
||||
25 3 * * * root /usr/local/bin/auto-update-gov-certificates |
||||
@ -0,0 +1,20 @@
|
||||
<VirtualHost *:80> |
||||
ServerAdmin ${APACHE_SERVER_ADMIN} |
||||
ServerName ${SERVER_NAME} |
||||
|
||||
DocumentRoot /var/www/certbot |
||||
|
||||
RewriteEngine On |
||||
|
||||
RewriteRule ^/$ https://%{HTTP_HOST}/ [L,R=301] |
||||
|
||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f |
||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d |
||||
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] |
||||
|
||||
<Directory "/var/www/certbot"> |
||||
Require all granted |
||||
AllowOverride All |
||||
Options -Indexes |
||||
</Directory> |
||||
</VirtualHost> |
||||
@ -0,0 +1,70 @@
|
||||
SSLStrictSNIVHostCheck off |
||||
|
||||
<VirtualHost *:${APACHE_SSL_PORT}> |
||||
ServerAdmin ${APACHE_SERVER_ADMIN} |
||||
ServerName ${SERVER_NAME} |
||||
|
||||
DocumentRoot /var/www/html |
||||
|
||||
LogLevel ${APACHE_LOG_LEVEL} ssl:${APACHE_SSL_LOG_LEVEL} |
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/${SERVER_NAME}_error.log |
||||
CustomLog ${APACHE_LOG_DIR}/${SERVER_NAME}_access.log "%h %{SSL_PROTOCOL}x %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" |
||||
|
||||
SSLEngine on |
||||
|
||||
SSLCertificateFile /etc/letsencrypt/live/${SERVER_NAME}/${APACHE_SSL_CERTS} |
||||
SSLCertificateKeyFile /etc/letsencrypt/live/${SERVER_NAME}/${APACHE_SSL_PRIVATE} |
||||
|
||||
SSLCACertificatePath /etc/ssl/itaca/ |
||||
SSLInsecureRenegotiation on |
||||
|
||||
OIDCProviderMetadataURL https://is-test.regione.sicilia.it:443/oauth2/token/.well-known/openid-configuration |
||||
OIDCClientID sJs9yMsWWz8K2Vkvys1F37zmtwwa |
||||
OIDCRedirectURI https://${SERVER_NAME}/spid/callback/ |
||||
OIDCClientName SISMICA |
||||
OIDCClientContact admin@mwg.it |
||||
OIDCCryptoPassphrase zyNVgGtYvDh5d7RqsSvnz8EYR2a8 |
||||
OIDCClaimPrefix SPID_claim_ |
||||
OIDCPassClaimsAs environment |
||||
OIDCPublicKeyFiles "auth#/etc/apache2/keys/public.pem" |
||||
OIDCPrivateKeyFiles "auth#/etc/apache2/keys/private.pem" |
||||
|
||||
<Directory "/var/www/html"> |
||||
Require all granted |
||||
AllowOverride All |
||||
Options -MultiViews +SymLinksIfOwnerMatch |
||||
SSLOptions +StdEnvVars |
||||
|
||||
#Order Allow,Deny |
||||
#Allow from 79.8.172.13 |
||||
#Allow from 80.17.206.46 |
||||
</Directory> |
||||
|
||||
<Directory "/var/www/html/cns"> |
||||
AllowOverride None |
||||
|
||||
SSLVerifyClient ${APACHE_SSL_VERIFY_CLIENT} |
||||
SSLRenegBufferSize 16777216 |
||||
SSLVerifyDepth 10 |
||||
SSLOptions +ExportCertData +StdEnvVars +OptRenegotiate |
||||
|
||||
SSLUserName SSL_CLIENT_S_DN_CN |
||||
|
||||
<If "env('APACHE_SSL_VERIFY_CLIENT') =~ /optional|optional_no_ca/"> |
||||
RewriteEngine on |
||||
RewriteCond %{SSL:SSL_CLIENT_VERIFY} !^SUCCESS$ |
||||
RewriteRule .? - [F] |
||||
ErrorDocument 403 ${CLIENT_VERIFY_LANDING_PAGE} |
||||
</If> |
||||
</Directory> |
||||
|
||||
<Directory "/var/www/html/spid"> |
||||
Options -Indexes |
||||
</Directory> |
||||
|
||||
<Location "/spid"> |
||||
AuthType openid-connect |
||||
Require valid-user |
||||
</Location> |
||||
</VirtualHost> |
||||
@ -0,0 +1,63 @@
|
||||
/*!40101 SET NAMES utf8 */; |
||||
|
||||
/*!40101 SET SQL_MODE=''*/; |
||||
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; |
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; |
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; |
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; |
||||
CREATE DATABASE /*!32312 IF NOT EXISTS*/`autenticazione` /*!40100 DEFAULT CHARACTER SET utf8 */; |
||||
USE `autenticazione`; |
||||
|
||||
DROP TABLE IF EXISTS `logins`; |
||||
CREATE TABLE `logins` ( |
||||
`token` char(40) NOT NULL, |
||||
`codice_fiscale` varchar(255) DEFAULT NULL, |
||||
`nome` varchar(255) DEFAULT NULL, |
||||
`cognome` varchar(255) DEFAULT NULL, |
||||
`created_at` timestamp NULL DEFAULT NULL, |
||||
`modified_at` timestamp NULL DEFAULT NULL, |
||||
PRIMARY KEY (`token`) |
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
||||
|
||||
DROP TABLE IF EXISTS `sessions`; |
||||
CREATE TABLE `sessions` ( |
||||
`auth` char(40) NOT NULL, |
||||
`user_id` int(10) unsigned NOT NULL, |
||||
`username` varchar(255) NOT NULL, |
||||
`created_at` timestamp NULL DEFAULT NULL, |
||||
`modified_at` timestamp NULL DEFAULT NULL, |
||||
PRIMARY KEY (`auth`) |
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
||||
|
||||
DROP TABLE IF EXISTS `tokens`; |
||||
CREATE TABLE `tokens` ( |
||||
`token` char(40) NOT NULL, |
||||
`auth` char(40) NOT NULL, |
||||
`callback` TEXT DEFAULT NULL, |
||||
`created_at` timestamp NULL DEFAULT NULL, |
||||
`modified_at` timestamp NULL DEFAULT NULL, |
||||
PRIMARY KEY (`token`) |
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
||||
|
||||
DROP TABLE IF EXISTS `users`; |
||||
CREATE TABLE `users` ( |
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, |
||||
`username` varchar(255) NOT NULL, |
||||
`password` char(64) NOT NULL, |
||||
`remote` varchar(45) DEFAULT NULL, |
||||
`created_at` timestamp NULL DEFAULT NULL, |
||||
`updated_at` timestamp NULL DEFAULT NULL, |
||||
`deleted_at` timestamp NULL DEFAULT NULL, |
||||
PRIMARY KEY (`id`), |
||||
UNIQUE KEY `users_username_remote_unique` (`username`,`remote`) |
||||
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; |
||||
|
||||
INSERT INTO `users`(`id`,`username`,`password`,`remote`,`created_at`,`updated_at`,`deleted_at`) VALUES |
||||
(1,'sismica','268633d46fdf00502dba60facce2ba5eec6a5d86c843c19f3f3b1ef8c0342ada','192.168.15.*',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,NULL), |
||||
(2,'sismica','268633d46fdf00502dba60facce2ba5eec6a5d86c843c19f3f3b1ef8c0342ada','79.8.172.13',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,NULL); |
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; |
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; |
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; |
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; |
||||
@ -0,0 +1,22 @@
|
||||
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH |
||||
SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.3 |
||||
SSLHonorCipherOrder On |
||||
|
||||
# Disable preloading HSTS for now. You can use the commented out header line that includes |
||||
# the "preload" directive if you understand the implications. |
||||
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" |
||||
Header always set X-Frame-Options DENY |
||||
Header always set X-Content-Type-Options nosniff |
||||
|
||||
# Requires Apache >= 2.4 |
||||
SSLCompression off |
||||
SSLUseStapling on |
||||
SSLStaplingCache "shmcb:logs/stapling-cache(150000)" |
||||
|
||||
# Prevent browsers from failing if an OCSP server is temporarily broken. |
||||
SSLStaplingReturnResponderErrors off |
||||
SSLStaplingErrorCacheTimeout 60 |
||||
SSLStaplingStandardCacheTimeout 36000 |
||||
|
||||
# Requires Apache >= 2.4.11 |
||||
SSLSessionTickets Off |
||||
@ -0,0 +1,67 @@
|
||||
<?php |
||||
|
||||
//define('SERVER_NAME', 'autenticazione.lavoripubblici.sicilia.it'); |
||||
define('SERVER_NAME', 'auth.mwg.it'); |
||||
define('CLIENT_ID', 'https://' . SERVER_NAME); |
||||
define('CLIENT_NAME', 'Autenticazione Lavori Pubblici Sicilia'); |
||||
define('REDIRECT_URIS', ['https://' . SERVER_NAME . '/spid/callback/']); |
||||
define('JWKS_URI', 'https://' . SERVER_NAME . '/openidc/jwks.json'); |
||||
|
||||
$distinguished_names = [ |
||||
'countryName' => 'IT', |
||||
'stateOrProvinceName' => 'Sicilia', |
||||
"organizationName" => 'Regione Siciliana', |
||||
"organizationalUnitName" => 'Assessorato Infrastrutture, Trasporti e Mobilità', |
||||
"commonName" => SERVER_NAME, |
||||
"emailAddress" => 'info@lavoripubblici.sicilia.it', |
||||
]; |
||||
|
||||
define('OPENIDC_PATH', '/var/www/html/openidc'); |
||||
define('PRIVATE_KEY', 'private.pem'); |
||||
define('PUBLIC_KEY', 'public.pem'); |
||||
|
||||
if (file_exists(PRIVATE_KEY)) { |
||||
$private = openssl_pkey_get_private(file_get_contents(PRIVATE_KEY)); |
||||
} else { |
||||
$private = openssl_pkey_new([ |
||||
'private_key_bits' => 4096, |
||||
'private_key_type' => OPENSSL_KEYTYPE_RSA, |
||||
]); |
||||
openssl_pkey_export_to_file($private, 'private.pem'); |
||||
} |
||||
$details = openssl_pkey_get_details($private); |
||||
file_put_contents(PUBLIC_KEY, $details['key']); |
||||
// $csr = openssl_csr_new($distinguished_names, $private); |
||||
// $x509 = openssl_csr_sign($csr, null, $private, 3650, ['digest_alg' => 'sha512']); |
||||
// openssl_pkcs12_export_to_file($x509, 'privatekeys.pfx', $private, 'm4n1f'); |
||||
$jwks = [ |
||||
'keys' => [ |
||||
[ |
||||
'kty' => 'RSA', |
||||
'alg' => 'RS256', |
||||
'use' => 'sig', |
||||
'kid' => 'auth', |
||||
'n' => base64_encode($details['rsa']['n']), |
||||
'e' => base64_encode($details['rsa']['e']), |
||||
], |
||||
], |
||||
]; |
||||
if (!is_dir(OPENIDC_PATH)) { |
||||
mkdir(OPENIDC_PATH, 0777, true); |
||||
} |
||||
file_put_contents(OPENIDC_PATH . '/jwks.json', json_encode($jwks, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); |
||||
$metadata = json_encode([ |
||||
'client_id' => CLIENT_ID, |
||||
'client_name' => CLIENT_NAME, |
||||
'grant_types' => [ |
||||
'authorization_code', |
||||
'refresh_token', |
||||
], |
||||
'jwks_uri' => JWKS_URI, |
||||
'jwks' => $jwks, |
||||
'redirect_uris' => REDIRECT_URIS, |
||||
'response_types' => [ |
||||
'code', |
||||
], |
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); |
||||
file_put_contents(OPENIDC_PATH . '/metadata.json', $metadata); |
||||
@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY----- |
||||
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 |
||||
VUCvqPCuPs2rHHJ8y/0686d72gU3+gg= |
||||
-----END PRIVATE KEY----- |
||||
File binario non mostrato.
@ -0,0 +1,14 @@
|
||||
-----BEGIN PUBLIC KEY----- |
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0guv1uiJLOulgTJN7O4m |
||||
+Hrf9N80ByPnncssc7ule+3XtSdgSbUEG4ztZq+TsBoAmAwsE44LxY4FvYxy39n1 |
||||
cZrw9EeuGY62bMulh9qdScHyHoUQwPGz6xLDQGJ0orr5THcFfLISGJdXutND9bNs |
||||
xlPwC328Nbvym2SEp6NL8g77tGlg1dDGNybs6lAeUTUWS1qXbWEMl3VhJZa711BU |
||||
stCujZsL2WyEsupVr80tWYobeCxuys/XBnbWbuPLiFMXCaGUnEzaoc1N4bF9AO6L |
||||
rGphMG9JLAcPbNyF/DIFYn2Mlvy7eaXkyFIom7GJejpZexABhtKDMSLBHnDHaneL |
||||
rkwmy0WogJpVSuTYL0nJdfPT1bT8ONx8YGikWQS/b8gtk/u/QQRBGtsBTA5a4Beg |
||||
yo8LmqLzeXBilqopviyIHpJ3kOU2iZo4Fj5qSjnAMT2IGuKKDhrjCGjito40GtYQ |
||||
EqkxbZf+Zz8QSuf4EWQt4oXLVYqD1WiSUk1MQ93ZT2MwCyh+jDG7m67dkcikDJa7 |
||||
yQYi7knDEGKmhBCBu3u/q2042vlSUe/OJIeBpqB16pZUZxPAKr1LUjURCKeHA2R7 |
||||
f3N3oC4jjVYrdgCvrOV/ZcJpsXR4EpyChgRtK0owXFCs+981xbnlBLSBazJwUxB+ |
||||
LbRJoHRiUc+TuqFM38CQJ9MCAwEAAQ== |
||||
-----END PUBLIC KEY----- |
||||
@ -0,0 +1,77 @@
|
||||
#!/bin/sh -e |
||||
set -x |
||||
SERVER_NAME='autenticazione.lavoripubblici.sicilia.it' |
||||
CERTBOT_EMAIL='admin@mwg.it' |
||||
DOCUMENT_ROOT='/var/www/html' |
||||
|
||||
MARIADB_USERNAME='mwg' |
||||
MARIADB_PASSWORD='Aw42#1e_w.as' |
||||
MARIADB_DATABASE='autenticazione' |
||||
|
||||
FOLDER="$(dirname $(realpath $0))" |
||||
|
||||
apt update |
||||
apt -y dist-upgrade |
||||
apt install -y apache2 certbot cron libapache2-mod-auth-openidc mariadb-server php php-mysql python |
||||
|
||||
# OpenSSL |
||||
sed -i -e 's/^CipherString = .*/CipherString = DEFAULT@SECLEVEL=1/' /etc/ssl/openssl.cnf |
||||
|
||||
# MariaDB |
||||
# mysql -e "DROP DATABASE IF EXISTS \`$MARIADB_DATABASE\`;" |
||||
if [ "0" = "$(mysql -B -N -e "SHOW DATABASES LIKE '$MARIADB_DATABASE';" | wc -l)" ]; then |
||||
mysql < $FOLDER/file/autenticazione.sql |
||||
fi |
||||
if [ "0" = "$(mysql -B -N -e \ |
||||
"SELECT \`User\` FROM \`mysql\`.\`user\` WHERE \`User\`='$MARIADB_USERNAME' AND \`Host\`='localhost';" | \ |
||||
wc -l)" ]; then |
||||
mysql -e "GRANT ALL PRIVILEGES ON \`$MARIADB_DATABASE\`.* TO '$MARIADB_USERNAME'@'localhost' IDENTIFIED BY \ |
||||
'$MARIADB_PASSWORD'" |
||||
fi |
||||
sed -i -e "s/\\(\\s*'password'\\s*=>\\s*\\).*/\\1'$MARIADB_PASSWORD',/" /var/www/App/Config/database.php |
||||
|
||||
# Sshd |
||||
mkdir -p /etc/ssh/sshd_config.d |
||||
echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/mwg.conf |
||||
|
||||
# Autenticazione |
||||
cp $FOLDER/usr-local-bin/* /usr/local/bin |
||||
. /usr/local/bin/project_env.sh |
||||
echo "export SERVER_NAME=$SERVER_NAME" >> /usr/local/bin/project_env.sh |
||||
echo "export APPLICATION_URL=https://$SERVER_NAME:443" >> /usr/local/bin/project_env.sh |
||||
|
||||
# Apache |
||||
cp $FOLDER/file/ssl-params.conf /etc/apache2/conf-available/ |
||||
if [ "$(grep /usr/local/bin/project_env.sh /etc/apache2/envvars | wc -l)" = "0" ]; then |
||||
echo '. /usr/local/bin/project_env.sh' >> /etc/apache2/envvars |
||||
fi |
||||
a2enconf ssl-params |
||||
a2enmod headers |
||||
a2enmod rewrite |
||||
a2enmod ssl |
||||
cd /etc/apache2/sites-enabled |
||||
find /etc/apache2/sites-enabled -type l -exec sh -c 'a2dissite $(basename {})' \; |
||||
cp $FOLDER/file/0certbot.conf /etc/apache2/sites-available |
||||
a2ensite 0certbot |
||||
systemctl restart apache2 |
||||
|
||||
certbot certonly -d $SERVER_NAME --webroot --webroot-path /var/www/certbot -m $CERTBOT_EMAIL --agree-tos \ |
||||
--non-interactive --no-eff-email --expand |
||||
|
||||
mkdir -p /etc/apache2/keys |
||||
cp $FOLDER/metadata/private.pem $FOLDER/metadata/public.pem /etc/apache2/keys |
||||
cp $FOLDER/file/1autenticazione.conf /etc/apache2/sites-available |
||||
a2ensite 1autenticazione |
||||
|
||||
/usr/local/bin/auto-update-gov-certificates |
||||
|
||||
# Cronjob |
||||
cp $FOLDER/cron/* /etc/cron.d |
||||
|
||||
echo Installazione terminata |
||||
|
||||
# apt purge --auto-remove apache2 certbot cron libapache2-mod-auth-openidc mariadb-server php php-mysql python;rmdir /var/lib/apache2/;rm -Rf /etc/ssl/itaca/ |
||||
|
||||
# openssl req -key private.pem -new -x509 -days 3650 -subj /C=IT/ST=Sicilia/O=Regione Siciliana/OU=Autenticazione Lavori Pubblici/CN=Autenticazione Lavori Pubblici -out cert.pem |
||||
# openssl pkcs12 -export -inkey private.pem -in cert.pem -out keys.pfx -name autenticazione |
||||
# keytool -v -list -keystore keys.pfx |
||||
@ -0,0 +1,39 @@
|
||||
#!/bin/sh -e |
||||
|
||||
LOG_FILE="/var/log/auto-update-gov-certificates.log" |
||||
echo "$(date "+%FT%T") Start auto upgrade Gov Certificates..." >> "$LOG_FILE" |
||||
|
||||
. /usr/local/bin/project_env.sh |
||||
|
||||
SIM_DIR="/etc/ssl/itaca" |
||||
touch "$LOG_FILE" |
||||
TMP_CERT_PATH=`mktemp -d` |
||||
|
||||
echo "$(date "+%FT%T") Remove temporary certificates file from $TMP_CERT_PATH" >> "$LOG_FILE" |
||||
rm -Rf "$TMP_CERT_PATH"/* >> "$LOG_FILE" 2>&1 |
||||
|
||||
echo "$(date "+%FT%T") Downloading Gov Certificates in tmp path $TMP_CERT_PATH..." >> "$LOG_FILE" |
||||
/usr/local/bin/parse-gov-certs.py --output-folder "$TMP_CERT_PATH" --service-type-identifier "$GOV_TRUST_CERTS_SERVICE_TYPE_IDENTIFIER" >> "$LOG_FILE" 2>&1 |
||||
echo "$(date "+%FT%T") Downloading Gov Certificates...[END]" >> "$LOG_FILE" |
||||
|
||||
echo "$(date "+%FT%T") Save Gov Certificates into $GOV_TRUST_CERTS_OUTPUT_PATH" >> "$LOG_FILE" |
||||
mkdir -p "$GOV_TRUST_CERTS_OUTPUT_PATH" >> "$LOG_FILE" 2>&1 |
||||
rm -Rf "$GOV_TRUST_CERTS_OUTPUT_PATH"/* >> "$LOG_FILE" 2>&1 |
||||
mv "$TMP_CERT_PATH"/* "$GOV_TRUST_CERTS_OUTPUT_PATH" >> "$LOG_FILE" 2>&1 |
||||
rm -Rf "$TMP_CERT_PATH" >> "$LOG_FILE" 2>&1 |
||||
|
||||
echo "$(date "+%FT%T") Removing simlinks from $SIM_DIR ..." >> "$LOG_FILE" |
||||
mkdir -p "$SIM_DIR" >> "$LOG_FILE" 2>&1 |
||||
rm -Rf "$SIM_DIR"/* >> "$LOG_FILE" 2>&1 |
||||
|
||||
echo "$(date "+%FT%T") Creating simlinks into $SIM_DIR/" >> "$LOG_FILE" |
||||
find "$GOV_TRUST_CERTS_OUTPUT_PATH" -type f | xargs -I{} basename "{}" | xargs -I{} ln -s "$GOV_TRUST_CERTS_OUTPUT_PATH/{}" "$SIM_DIR/{}" >> "$LOG_FILE" 2>&1 |
||||
|
||||
echo "$(date "+%FT%T") Re-Hashing $SIM_DIR/..." >> "$LOG_FILE" |
||||
c_rehash "$SIM_DIR/" >> "$LOG_FILE" 2>&1 |
||||
|
||||
echo "$(date "+%FT%T") Start auto upgrade Gov Certificates...[END]" >> "$LOG_FILE" |
||||
|
||||
echo "$(date "+%FT%T") Restart Apache HTTP Service..." >> "$LOG_FILE" |
||||
systemctl restart apache2 >> "$LOG_FILE" 2>&1 |
||||
echo "$(date "+%FT%T") End auto upgrade Gov Certificates..." >> "$LOG_FILE" |
||||
@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python |
||||
# -*- coding: utf-8 -*- |
||||
# Copyright (C) Marco Trevisan |
||||
# |
||||
# Authors: |
||||
# Marco Trevisan <marco@trevisan.xyz> |
||||
# |
||||
# Revision for new URL: |
||||
# Andrea Costantino <costan@amg.it> |
||||
# |
||||
# Revision for new XPath Query (add a filter by service type identifier) |
||||
# Antonio Musarra <antonio.musarra@gmail.com> |
||||
# |
||||
# This program is free software; you can redistribute it and/or modify it under |
||||
# the terms of the GNU General Public License as published by the Free Software |
||||
# Foundation; version 3. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, but WITHOUTa |
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
||||
# details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License along with |
||||
# this program; if not, write to the Free Software Foundation, Inc., |
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
# |
||||
# Get Italian government Certification Authority certificates from used by |
||||
# by various National Service SmartCards (Carta Nazionale dei Servizi- CNS) |
||||
# |
||||
# Original URI: |
||||
# - http://www.agid.gov.it/agenda-digitale/infrastrutture-architetture/firme-elettroniche/certificati |
||||
# |
||||
# Current XML file: |
||||
# - https://eidas.agid.gov.it/TL/TSL-IT.xml |
||||
|
||||
import argparse |
||||
import re |
||||
import sys |
||||
import xml.etree.ElementTree as ET |
||||
import textwrap |
||||
import os |
||||
|
||||
DEFAULT_XML_URI = "https://eidas.agid.gov.it/TL/TSL-IT.xml" |
||||
EXTENSION = ".pem" |
||||
|
||||
def get_certs_xml(): |
||||
if sys.version_info[0] == 2: |
||||
import urllib2 |
||||
request = urllib2 |
||||
else: |
||||
import urllib.request |
||||
request = urllib.request |
||||
|
||||
return request.urlopen(DEFAULT_XML_URI) |
||||
|
||||
def write_certificate(f, x509_cert): |
||||
f.write('-----BEGIN CERTIFICATE-----\n') |
||||
for line in textwrap.wrap(x509_cert, 65): |
||||
f.write(line+'\n') |
||||
f.write('-----END CERTIFICATE-----\n') |
||||
|
||||
def get_service_info(service): |
||||
name = service.find("*/"+ns+"Name").text |
||||
x509_cert = service.find("*//"+ns+"X509Certificate").text |
||||
return {'name': name, 'x509_cert': x509_cert} |
||||
|
||||
parser = argparse.ArgumentParser() |
||||
action = parser.add_mutually_exclusive_group(required=True) |
||||
action.add_argument("--output-folder", help="Where to save the certs files") |
||||
action.add_argument("--output-file", help="File saving certificates") |
||||
parser.add_argument("--cert-file", help="Input Xml file, instead of %s" % DEFAULT_XML_URI) |
||||
parser.add_argument("--service-type-identifier", help="Save certs by Service Type Identifier, instead of all") |
||||
args = parser.parse_args() |
||||
|
||||
if args.output_folder: |
||||
if os.path.exists(args.output_folder): |
||||
if not os.path.isdir(args.output_folder): |
||||
print("Impossible to save certificates in `%s': file exists and is not a folder." % args.output_folder) |
||||
sys.exit(1) |
||||
else: |
||||
os.makedirs(args.output_folder) |
||||
elif args.output_file: |
||||
if os.path.exists(args.output_file): |
||||
if not os.path.isfile(args.output_file): |
||||
print("Impossible to write on `%s', it's not a file." % args.output_file) |
||||
sys.exit(1) |
||||
|
||||
print("File `%s' will be overwritten..." % args.output_file) |
||||
|
||||
|
||||
if args.cert_file: |
||||
tree = ET.parse(args.cert_file) |
||||
root = tree.getroot() |
||||
else: |
||||
root = ET.fromstring(get_certs_xml().read()) |
||||
|
||||
try: |
||||
[ns] = re.findall("({[^}]*}).*", root.tag) |
||||
except: |
||||
ns = "" |
||||
|
||||
print("Namespace: `%s`", ns) |
||||
|
||||
if args.service_type_identifier: |
||||
services = root.findall(ns+"TrustServiceProviderList//"+ns+"TSPService/"+ns+"ServiceInformation["+ns+"ServiceTypeIdentifier='"+args.service_type_identifier+"']") |
||||
else: |
||||
services = root.findall(ns+"TrustServiceProviderList//"+ns+"TSPService/"+ns+"ServiceInformation") |
||||
|
||||
if args.output_folder: |
||||
for service in services: |
||||
try: |
||||
info = get_service_info(service) |
||||
name = re.sub('[A-z]{1,2}=', '_', re.sub('[/\,\' "]', '_', info['name'])).replace('__', '_').strip('_- ') |
||||
filename = args.output_folder+os.path.sep+name |
||||
|
||||
idx = 1 |
||||
tmpname = filename |
||||
while os.path.exists(tmpname+EXTENSION): |
||||
tmpname = filename+str(idx) |
||||
idx += 1 |
||||
filename = tmpname+EXTENSION |
||||
|
||||
f = open(filename, 'w') |
||||
write_certificate(f, info['x509_cert']) |
||||
f.close() |
||||
print("Added certificate: %s" % filename) |
||||
|
||||
except Exception as e: |
||||
print("Impossible to add file: %s" % e) |
||||
pass |
||||
|
||||
else: |
||||
f = open(args.output_file, 'w') |
||||
|
||||
for service in services: |
||||
try: |
||||
info = get_service_info(service) |
||||
write_certificate(f, info['x509_cert']) |
||||
|
||||
print("Added certificate %s" % info['name']) |
||||
|
||||
except Exception as e: |
||||
print("Impossible to add certificate to file: %s" % e) |
||||
pass |
||||
|
||||
f.close() |
||||
@ -0,0 +1,12 @@
|
||||
export APACHE_SSL_VERIFY_CLIENT=optional |
||||
export APACHE_LOG_LEVEL=info |
||||
export GOV_TRUST_CERTS_OUTPUT_PATH=/usr/share/ca-certificates/it-gov |
||||
export APACHE_SSL_LOG_LEVEL=debug |
||||
export APACHE_SSL_PORT=443 |
||||
export APACHE_SSL_PRIVATE=privkey.pem |
||||
export GOV_TRUST_CERTS_SERVICE_TYPE_IDENTIFIER=http://uri.etsi.org/TrstSvc/Svctype/IdV |
||||
export APACHE_SSL_CERTS=fullchain.pem |
||||
export CLIENT_VERIFY_LANDING_PAGE=/errors/no-cns.php |
||||
export APACHE_SERVER_ADMIN=info@lavoripubblici.sicilia.it |
||||
export APACHE_RUN_USER=mwg |
||||
export APACHE_RUN_GROUP=mwg |
||||
Caricamento…
Reference in new issue