Skip to content

Commit bfb7740

Browse files
committed
Allow config of anonymous access
1 parent c645af0 commit bfb7740

File tree

8 files changed

+36
-13
lines changed

8 files changed

+36
-13
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,12 @@ You can tune the middleware behavior using middleware specific configuration par
161161
- "cors.allowMethods": The methods allowed in the CORS request ("OPTIONS, GET, PUT, POST, DELETE, PATCH")
162162
- "cors.allowCredentials": To allow credentials in the CORS request ("true")
163163
- "cors.maxAge": The time that the CORS grant is valid in seconds ("1728000")
164+
- "jwtAuth.mode": Set to "optional" if you want to allow anonymous access ("required")
164165
- "jwtAuth.leeway": The acceptable number of seconds of clock skew ("5")
165166
- "jwtAuth.ttl": The number of seconds the token is valid ("30")
166167
- "jwtAuth.secret": The shared secret used to sign the JWT token with ("")
168+
- "basicAuth.mode": Set to "optional" if you want to allow anonymous access ("required")
169+
- "basicAuth.realm": Text to prompt when showing login ("Username and password required")
167170
- "basicAuth.passwordFile": The file to read for username/password combinations (".htpasswd")
168171
- "authorization.tableHandler": Handler to implement table authorization rules ("")
169172
- "authorization.columnHandler": Handler to implement column authorization rules ("")
@@ -793,11 +796,12 @@ The following errors may be reported:
793796
- 1008: Cannot read HTTP message (422 UNPROCESSABLE ENTITY)
794797
- 1009: Duplicate key exception (409 CONFLICT)
795798
- 1010: Data integrity violation (409 CONFLICT)
796-
- 1011: Authorization required (401 UNAUTHORIZED)
797-
- 1012: Access denied (403 FORBIDDEN)
799+
- 1011: Authentication required (401 UNAUTHORIZED)
800+
- 1012: Authentication failed (403 FORBIDDEN)
798801
- 1013: Input validation failed (422 UNPROCESSABLE ENTITY)
799802
- 1014: Operation forbidden (403 FORBIDDEN)
800803
- 1015: Operation not supported (405 METHOD NOT ALLOWED)
804+
- 1016: Temporary or permanently blocked (403 FORBIDDEN)
801805
- 9999: Unknown error (500: INTERNAL SERVER ERROR)
802806

803807
The following JSON structure is used:

src/Tqdev/PhpCrudApi/Middleware/BasicAuthMiddleware.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,16 @@ public function handle(Request $request): Response
8585
$validUser = $this->getValidUsername($username, $password, $passwordFile);
8686
$_SESSION['username'] = $validUser;
8787
if (!$validUser) {
88-
return $this->responder->error(ErrorCode::ACCESS_DENIED, $username);
88+
return $this->responder->error(ErrorCode::AUTHENTICATION_FAILED, $username);
89+
}
90+
}
91+
if (!isset($_SESSION['username']) || !$_SESSION['username']) {
92+
$authenticationMode = $this->getProperty('mode', 'required');
93+
if ($authenticationMode == 'required') {
94+
$response = $this->responder->error(ErrorCode::AUTHENTICATION_REQUIRED, '');
95+
$realm = $this->getProperty('realm', 'Username and password required');
96+
$response->addHeader('WWW-Authenticate', "Basic realm=\"$realm\"");
97+
return $response;
8998
}
9099
}
91100
return $this->next->handle($request);

src/Tqdev/PhpCrudApi/Middleware/FirewallMiddleware.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function handle(Request $request): Response
4646
}
4747
$allowedIpAddresses = $this->getProperty('allowedIpAddresses', '');
4848
if (!$this->isIpAllowed($ipAddress, $allowedIpAddresses)) {
49-
$response = $this->responder->error(ErrorCode::ACCESS_DENIED, $ipAddress);
49+
$response = $this->responder->error(ErrorCode::TEMPORARY_OR_PERMANENTLY_BLOCKED, '');
5050
} else {
5151
$response = $this->next->handle($request);
5252
}

src/Tqdev/PhpCrudApi/Middleware/JwtAuthMiddleware.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,13 @@ public function handle(Request $request): Response
8787
$claims = $this->getClaims($token);
8888
$_SESSION['claims'] = $claims;
8989
if (empty($claims)) {
90-
return $this->responder->error(ErrorCode::ACCESS_DENIED, 'JWT');
90+
return $this->responder->error(ErrorCode::AUTHENTICATION_FAILED, 'JWT');
91+
}
92+
}
93+
if (empty($_SESSION['claims'])) {
94+
$authenticationMode = $this->getProperty('mode', 'required');
95+
if ($authenticationMode == 'required') {
96+
return $this->responder->error(ErrorCode::AUTHENTICATION_REQUIRED, '');
9197
}
9298
}
9399
return $this->next->handle($request);

src/Tqdev/PhpCrudApi/Record/ErrorCode.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ class ErrorCode
2222
const HTTP_MESSAGE_NOT_READABLE = 1008;
2323
const DUPLICATE_KEY_EXCEPTION = 1009;
2424
const DATA_INTEGRITY_VIOLATION = 1010;
25-
const AUTHORIZATION_REQUIRED = 1011;
26-
const ACCESS_DENIED = 1012;
25+
const AUTHENTICATION_REQUIRED = 1011;
26+
const AUTHENTICATION_FAILED = 1012;
2727
const INPUT_VALIDATION_FAILED = 1013;
2828
const OPERATION_FORBIDDEN = 1014;
2929
const OPERATION_NOT_SUPPORTED = 1015;
30+
const TEMPORARY_OR_PERMANENTLY_BLOCKED = 1016;
3031

3132
private $values = [
3233
9999 => ["%s", Response::INTERNAL_SERVER_ERROR],
@@ -41,11 +42,12 @@ class ErrorCode
4142
1008 => ["Cannot read HTTP message", Response::UNPROCESSABLE_ENTITY],
4243
1009 => ["Duplicate key exception", Response::CONFLICT],
4344
1010 => ["Data integrity violation", Response::CONFLICT],
44-
1011 => ["Authorization required", Response::UNAUTHORIZED],
45-
1012 => ["Access denied for '%s'", Response::FORBIDDEN],
45+
1011 => ["Authentication required", Response::UNAUTHORIZED],
46+
1012 => ["Authentication failed for '%s'", Response::FORBIDDEN],
4647
1013 => ["Input validation failed for '%s'", Response::UNPROCESSABLE_ENTITY],
4748
1014 => ["Operation forbidden", Response::FORBIDDEN],
4849
1015 => ["Operation '%s' not supported", Response::METHOD_NOT_ALLOWED],
50+
1016 => ["Temporary or permanently blocked", Response::FORBIDDEN],
4951
];
5052

5153
public function __construct(int $code)

tests/config/base.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
'password' => 'php-crud-api',
66
'controllers' => 'records,columns,cache,openapi',
77
'middlewares' => 'cors,jwtAuth,basicAuth,authorization,validation,sanitation,multiTenancy,customization',
8+
'jwtAuth.mode' => 'optional',
89
'jwtAuth.time' => '1538207605',
910
'jwtAuth.secret' => 'axpIrCGNGqxzx2R9dtXLIPUSqPo778uhb8CA0F4Hx',
11+
'basicAuth.mode' => 'optional',
1012
'basicAuth.passwordFile' => __DIR__ . DIRECTORY_SEPARATOR . '.htpasswd',
1113
'authorization.tableHandler' => function ($operation, $tableName) {
1214
return !($tableName == 'invisibles' && !isset($_SESSION['claims']['name']) && empty($_SESSION['username']));

tests/functional/002_auth/001_jwt_auth.log

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ Authorization: Bearer invalid
2020
===
2121
403
2222
Content-Type: application/json
23-
Content-Length: 49
23+
Content-Length: 57
2424

25-
{"code":1012,"message":"Access denied for 'JWT'"}
25+
{"code":1012,"message":"Authentication failed for 'JWT'"}
2626
===
2727
GET /records/invisibles/e42c77c6-06a4-4502-816c-d112c7142e6d
2828
===

tests/functional/002_auth/002_basic_auth.log

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ Authorization: Basic aW52YWxpZHVzZXI6aW52YWxpZHBhc3M
2020
===
2121
403
2222
Content-Type: application/json
23-
Content-Length: 57
23+
Content-Length: 65
2424

25-
{"code":1012,"message":"Access denied for 'invaliduser'"}
25+
{"code":1012,"message":"Authentication failed for 'invaliduser'"}
2626
===
2727
GET /records/invisibles/e42c77c6-06a4-4502-816c-d112c7142e6d
2828
===

0 commit comments

Comments
 (0)