Skip to content

Commit 0f5ae2b

Browse files
Guido Gröönmrts
authored andcommitted
Review commit
1 parent 457a0ba commit 0f5ae2b

File tree

67 files changed

+749
-788
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+749
-788
lines changed

README.md

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,26 @@ Add the following lines to `composer.json` to include the Web eID authentication
3535
]
3636
```
3737

38-
### Configure the log file location
38+
### Logging
3939

40-
By default, log entries are written to the server log. If there is a need to collect log entries in a separate file, define the constant `LOGFILE` for the log file location.
40+
For logging, you have to create `LoggerInterface` and use it on `AuthTokenValidatorBuilder` initialization.
4141

42-
Example:
42+
Example logger interface with Monolog:
4343
```php
44-
define("LOGFILE", dirname(__FILE__) . "/../log/web-eid-authtoken-validation-php.log");
45-
```
44+
use Monolog\Level;
45+
use Monolog\Logger;
46+
use Monolog\Handler\StreamHandler;
4647

47-
It is essential, that your log file directory has write access.
48+
...
49+
$log = new Logger("general");
50+
$log->pushHandler(new StreamHandler("/some/path/app.log", Level::Debug));
51+
52+
return (new AuthTokenValidatorBuilder($log))
53+
->withSiteOrigin(new Uri("https://example.org"))
54+
->withTrustedCertificateAuthorities(...self::trustedIntermediateCACertificates())
55+
->build();
56+
```
57+
Read more about [LoggerInterface](https://www.php-fig.org/psr/psr-3/) and take a look from examples directory.
4858

4959
## 2. Configure the challenge nonce store
5060

@@ -90,15 +100,15 @@ public function trustedIntermediateCACertificates(): array
90100
Once the prerequisites have been met, the authentication token validator itself can be configured. The mandatory parameters are the website origin and trusted certificate authorities. The authentication token validator will be used in the login processing component of your web application authentication framework
91101

92102
```php
93-
use web_eid\web_eid_authtoken_validation_php\util\Uri;
103+
use GuzzleHttp\Psr7\Uri;
94104
use web_eid\web_eid_authtoken_validation_php\validator\AuthTokenValidator;
95105
use web_eid\web_eid_authtoken_validation_php\validator\AuthTokenValidatorBuilder;
96106

97107
...
98108
public function tokenValidator(): AuthTokenValidator
99109
{
100110
return (new AuthTokenValidatorBuilder())
101-
->withSiteOrigin(new Uri('https://example.org'))
111+
->withSiteOrigin(new Uri("https://example.org"))
102112
->withTrustedCertificateAuthorities(...self::trustedIntermediateCACertificates())
103113
->build();
104114
}
@@ -118,24 +128,24 @@ class Router
118128
{
119129

120130
$router = new AltoRouter();
121-
$router->setBasePath('');
131+
$router->setBasePath("");
122132

123-
$router->map('GET', '', ['controller' => 'Pages', 'method' => 'login']);
124-
$router->map('GET', '/nonce', ['controller' => 'Auth', 'method' => 'getNonce']);
133+
$router->map("GET", "/", ["controller" => "Pages", "method" => "login"]);
134+
$router->map("GET", "/nonce", ["controller" => "Auth", "method" => "getNonce"]);
125135

126136
$match = $router->match();
127137

128138
if (!$match) {
129139
// Redirect to main
130-
header("location:/");
140+
header('Location: /');
131141
return;
132142
}
133143

134144

135-
$controller = new $match['target']['controller'];
136-
$method = $match['target']['method'];
145+
$controller = new $match["target"]["controller"];
146+
$method = $match["target"]["method"];
137147

138-
call_user_func([$controller, $method], $match['params'], []);
148+
call_user_func([$controller, $method], $match["params"], []);
139149

140150
}
141151
}
@@ -147,14 +157,13 @@ class Auth
147157
{
148158

149159
try {
150-
header('Content-Type: application/json; charset=utf-8');
160+
header("Content-Type: application/json; charset=utf-8");
151161
$generator = $this->generator();
152162
$challengeNonce = $generator->generateAndStoreNonce();
153-
$responseArr = [];
154-
$responseArr["nonce"] = $challengeNonce->getBase64EncodedNonce();
163+
$responseArr["nonce" => $challengeNonce->getBase64EncodedNonce()];
155164
echo json_encode($responseArr);
156165
} catch (Exception $e) {
157-
header("HTTP/1.0 400 Bad Request");
166+
header("HTTP/1.0 500 Internal Server Error");
158167
echo $e->getMessage();
159168
}
160169
}
@@ -222,6 +231,7 @@ See the complete example from the ***examples*** directory.
222231
- [Basic usage](#basic-usage-1)
223232
- [Extended configuration](#extended-configuration-1)
224233
- [Example implementation](#example-implementation)
234+
- [Code formatting](#code-formatting)
225235
- [Testing](#testing)
226236

227237
# Introduction
@@ -371,6 +381,18 @@ composer dump-autoload
371381

372382
Please note, that there are no certificate files included in this example. You can find certificates from [here](https://www.skidsolutions.eu/en/repository/certs)
373383

384+
# Code formatting
385+
386+
We are using `Prettier` for code formatting. To install Prettier, use following command:
387+
388+
```
389+
npm install --global prettier @prettier/plugin-php
390+
```
391+
Run command for code formatting:
392+
```
393+
composer fix-php
394+
```
395+
374396
# Testing
375397

376398
Run phpunit in the root directory to run all unit tests.

composer.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
],
3434
"require": {
3535
"phpseclib/phpseclib": "3.0.14",
36-
"web_eid/ocsp_php": "dev-main"
36+
"guzzlehttp/psr7": "2.4.3",
37+
"web_eid/ocsp_php": "dev-development",
38+
"psr/log": "^3.0"
39+
},
40+
"scripts": {
41+
"fix-php": ["prettier src/**/* --write", "prettier examples/src/* --write"]
3742
}
3843
}

examples/composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
"php": ">=7.4",
1414
"web_eid/web_eid_authtoken_validation_php": "dev-main",
1515
"web_eid/ocsp_php": "dev-main",
16-
"altorouter/altorouter": "1.1.0"
16+
"altorouter/altorouter": "1.1.0",
17+
"guzzlehttp/psr7": "2.4.3",
18+
"psr/log": "^3.0"
1719
},
1820
"autoload": {
1921
"classmap": ["src"]

examples/public/css/bootstrap.min.css

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/public/css/bootstrap.min.css.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/src/Auth.php

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
use web_eid\web_eid_authtoken_validation_php\challenge\ChallengeNonceGeneratorBuilder;
3030
use web_eid\web_eid_authtoken_validation_php\challenge\ChallengeNonceStore;
3131
use web_eid\web_eid_authtoken_validation_php\exceptions\ChallengeNonceExpiredException;
32-
use web_eid\web_eid_authtoken_validation_php\util\Uri;
32+
use GuzzleHttp\Psr7\Uri;
3333
use web_eid\web_eid_authtoken_validation_php\validator\AuthTokenValidator;
3434
use web_eid\web_eid_authtoken_validation_php\validator\AuthTokenValidatorBuilder;
3535

@@ -53,8 +53,11 @@ public function generator(): ChallengeNonceGenerator
5353

5454
public function tokenValidator(): AuthTokenValidator
5555
{
56-
return (new AuthTokenValidatorBuilder())
57-
->withSiteOrigin(new Uri('https://localhost:8443'))
56+
$logger = new Logger();
57+
58+
return (new AuthTokenValidatorBuilder($logger))
59+
// Change the URL when you run the example in your own machine.
60+
->withSiteOrigin(new Uri("https://localhost:8443"))
5861
->withTrustedCertificateAuthorities(...self::trustedIntermediateCACertificates())
5962
->build();
6063
}
@@ -67,13 +70,12 @@ public function tokenValidator(): AuthTokenValidator
6770
public function getNonce()
6871
{
6972
try {
70-
header('Content-Type: application/json; charset=utf-8');
73+
header("Content-Type: application/json; charset=utf-8");
7174
$challengeNonce = $this->generator()->generateAndStoreNonce();
72-
$responseArr = [];
7375
$responseArr = ["nonce" => $challengeNonce->getBase64EncodedNonce()];
7476
echo json_encode($responseArr);
7577
} catch (Exception $e) {
76-
header("HTTP/1.0 400 Bad Request");
78+
header("HTTP/1.0 500 Internal Server Error");
7779
echo "Nonce generation failed";
7880
}
7981
}
@@ -88,11 +90,11 @@ public function validate()
8890
$headers = getallheaders();
8991
if (!isset($headers["X-CSRF-TOKEN"]) || ($headers["X-CSRF-TOKEN"] != $_SESSION["csrf-token"])) {
9092
header("HTTP/1.0 405 Method Not Allowed");
91-
echo "Unable to process your request";
93+
echo "CSRF token missing, unable to process your request";
9294
return;
9395
}
9496

95-
$authToken = file_get_contents('php://input');
97+
$authToken = file_get_contents("php://input");
9698

9799
try {
98100

@@ -108,7 +110,7 @@ public function validate()
108110

109111
$subjectName = CertificateData::getSubjectGivenName($cert) . " " . CertificateData::getSubjectSurname($cert);
110112
$result = [
111-
'sub' => $subjectName
113+
"sub" => $subjectName
112114
];
113115

114116
$_SESSION["auth-user"] = $subjectName;
@@ -133,6 +135,6 @@ public function logout()
133135
unset($_SESSION["auth-user"]);
134136
session_regenerate_id();
135137
// Redirect to login
136-
header("location:/");
138+
header("Location: /");
137139
}
138140
}

examples/src/Logger.php

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
/*
4+
* Copyright (c) 2020-2021 Estonian Information System Authority
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
use Psr\Log\LoggerInterface;
26+
use Psr\Log\LogLevel;
27+
28+
class Logger implements LoggerInterface
29+
{
30+
public function emergency(string|\Stringable $message, array $context = []): void
31+
{
32+
$this->log(LogLevel::EMERGENCY, $message, $context);
33+
}
34+
35+
public function alert(string|\Stringable $message, array $context = []): void
36+
{
37+
$this->log(LogLevel::ALERT, $message, $context);
38+
}
39+
40+
public function critical(string|\Stringable $message, array $context = []): void
41+
{
42+
$this->log(LogLevel::CRITICAL, $message, $context);
43+
}
44+
45+
public function error(string|\Stringable $message, array $context = []): void
46+
{
47+
$this->log(LogLevel::ERROR, $message, $context);
48+
}
49+
50+
public function warning(string|\Stringable $message, array $context = []): void
51+
{
52+
$this->log(LogLevel::WARNING, $message, $context);
53+
}
54+
55+
public function notice(string|\Stringable $message, array $context = []): void
56+
{
57+
$this->log(LogLevel::NOTICE, $message, $context);
58+
}
59+
60+
public function info(string|\Stringable $message, array $context = []): void
61+
{
62+
$this->log(LogLevel::INFO, $message, $context);
63+
}
64+
65+
public function debug(string|\Stringable $message, array $context = []): void
66+
{
67+
$this->log(LogLevel::DEBUG, $message, $context);
68+
}
69+
70+
public function log($level, string|\Stringable $message, array $context = []): void
71+
{
72+
// Build the message with the current date, log level,
73+
// and the string from the arguments
74+
$message = sprintf(
75+
'%s: %s%s',
76+
$level,
77+
$message,
78+
PHP_EOL // Line break
79+
);
80+
81+
error_log($message, 0);
82+
}
83+
}

examples/src/Pages.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function __construct()
3232
$this->template = new Template();
3333
}
3434

35-
private function _generateToken()
35+
private function _generateCsrfToken()
3636
{
3737
// Store token to session
3838
$_SESSION["csrf-token"] = bin2hex(random_bytes(32));
@@ -48,7 +48,6 @@ public function login()
4848

4949
public function welcome()
5050
{
51-
$data = [];
5251
$data = ["auth_user" => $_SESSION["auth-user"]];
5352
$this->data = [
5453
"content" => $this->template->getHtml(__DIR__ . '/../tpl/welcome.phtml', $data)
@@ -57,7 +56,7 @@ public function welcome()
5756

5857
public function __destruct()
5958
{
60-
$this->data["token"] = $this->_generateToken();;
59+
$this->data["token"] = $this->_generateCsrfToken();;
6160
echo $this->template->getHtml(__DIR__ . '/../tpl/site.phtml', $this->data);
6261
}
6362
}

examples/src/Router.php

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,34 +30,33 @@ public function init()
3030
{
3131

3232
$router = new AltoRouter();
33-
$router->setBasePath('');
33+
$router->setBasePath("");
3434

3535
// Page routes
36-
//$router->map('GET', '', ['controller' => 'Pages', 'method' => 'login']);
37-
$router->map('GET', '/', ['controller' => 'Pages', 'method' => 'login']);
38-
$router->map('GET', '/logout', ['controller' => 'Auth', 'method' => 'logout']);
36+
$router->map("GET", "/", ["controller" => "Pages", "method" => "login"]);
37+
$router->map("GET", "/logout", ["controller" => "Auth", "method" => "logout"]);
3938

4039
// Web eID routes
41-
$router->map('GET', '/nonce', ['controller' => 'Auth', 'method' => 'getNonce']);
42-
$router->map('POST', '/validate', ['controller' => 'Auth', 'method' => 'validate']);
40+
$router->map("GET", "/nonce", ["controller" => "Auth", "method" => "getNonce"]);
41+
$router->map("POST", "/validate", ["controller" => "Auth", "method" => "validate"]);
4342

4443
// Allow route only for authenticated users
4544
if (isset($_SESSION["auth-user"])) {
46-
$router->map('GET', '/welcome', ['controller' => 'Pages', 'method' => 'welcome']);
45+
$router->map("GET", "/welcome", ["controller" => "Pages", "method" => "welcome"]);
4746
}
4847

4948
$match = $router->match();
5049

5150
if (!$match) {
5251
// Redirect to login
53-
header("location:/");
52+
header("Location: /");
5453
return;
5554
}
5655

5756

58-
$controller = new $match['target']['controller'];
59-
$method = $match['target']['method'];
57+
$controller = new $match["target"]["controller"];
58+
$method = $match["target"]["method"];
6059

61-
call_user_func([$controller, $method], $match['params'], []);
60+
call_user_func([$controller, $method], $match["params"], []);
6261
}
6362
}

0 commit comments

Comments
 (0)