Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit a12f650

Browse files
committed
Merge branch 'develop'
2 parents cbfec9c + 8a0edbd commit a12f650

File tree

11 files changed

+296
-33
lines changed

11 files changed

+296
-33
lines changed

.travis.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
sudo: false
2-
31
language: php
42

53
cache:
@@ -54,6 +52,15 @@ matrix:
5452
- php: 7.2
5553
env:
5654
- DEPS=latest
55+
- php: 7.3
56+
env:
57+
- DEPS=lowest
58+
- php: 7.3
59+
env:
60+
- DEPS=locked
61+
- php: 7.3
62+
env:
63+
- DEPS=latest
5764

5865
before_install:
5966
- if [[ $TEST_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,33 @@
22

33
All notable changes to this project will be documented in this file, in reverse chronological order by release.
44

5+
## 2.7.0 - TBD
6+
7+
### Added
8+
9+
- [#44](https://github.com/zendframework/zend-authentication/pull/44) adds support for PHP 7.3.
10+
- [#47](https://github.com/zendframework/zend-authentication/pull/47) adds
11+
configuration option to `Zend\Authentication\Validator\Authentication` for
12+
mapping custom authentication result codes to existing and new validation
13+
message types.
14+
15+
### Changed
16+
17+
- [#42](https://github.com/zendframework/zend-authentication/pull/42) Changes authentication using Basic scheme
18+
to re-challenge the client when credentials in Authorization header can not be base64 decoded.
19+
20+
### Deprecated
21+
22+
- Nothing.
23+
24+
### Removed
25+
26+
- [#44](https://github.com/zendframework/zend-authentication/pull/44) removes support for zend-stdlib v2 releases.
27+
28+
### Fixed
29+
30+
- Nothing.
31+
532
## 2.6.1 - TBD
633

734
### Added

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
},
1818
"require": {
1919
"php": "^5.6 || ^7.0",
20-
"zendframework/zend-stdlib": "^2.7.7 || ^3.1"
20+
"zendframework/zend-stdlib": "^3.2.1"
2121
},
2222
"require-dev": {
2323
"phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2",

composer.lock

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

docs/book/validator.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The available configuration options include:
1313
- `identity`: the identity or name of the identity field in the provided context.
1414
- `credential`: credential or the name of the credential field in the provided context.
1515
- `service`: an instance of `Zend\Authentication\AuthenticationService`.
16+
- `code_map`: map of `Zend\Authentication\Result` codes to validator message identifiers.
1617

1718
## Usage
1819

@@ -33,3 +34,65 @@ $validator->isValid('myIdentity', [
3334
'myCredentialContext' => 'myCredential',
3435
]);
3536
```
37+
38+
## Validation messages
39+
40+
The authentication validator defines five failure message types; identifiers
41+
for them are available as constants for convenience.
42+
Common authentication failure codes, defined as constants in
43+
`Zend\Authentication\Result`, are mapped to validation messages
44+
using a map in `CODE_MAP` constant. Other authentication codes default to the
45+
`general` message type.
46+
47+
```php
48+
namespace Zend\Authentication\Validator;
49+
50+
use Zend\Authentication\Result;
51+
52+
class Authentication
53+
{
54+
const IDENTITY_NOT_FOUND = 'identityNotFound';
55+
const IDENTITY_AMBIGUOUS = 'identityAmbiguous';
56+
const CREDENTIAL_INVALID = 'credentialInvalid';
57+
const UNCATEGORIZED = 'uncategorized';
58+
const GENERAL = 'general';
59+
60+
const CODE_MAP = [
61+
Result::FAILURE_IDENTITY_NOT_FOUND => self::IDENTITY_NOT_FOUND,
62+
Result::FAILURE_CREDENTIAL_INVALID => self::CREDENTIAL_INVALID,
63+
Result::FAILURE_IDENTITY_AMBIGUOUS => self::IDENTITY_AMBIGUOUS,
64+
Result::FAILURE_UNCATEGORIZED => self::UNCATEGORIZED,
65+
];
66+
}
67+
```
68+
69+
The authentication validator extends `Zend\Validator\AbstractValidator`, providing
70+
a way common for all framework validators to access, change or translate message templates.
71+
More information is available in the
72+
[zend-validator documentation](https://docs.zendframework.com/zend-validator/messages/)
73+
74+
## Configure validation messages for custom authentication result codes
75+
76+
The constructor configuration option `code_map` allows mapping custom codes
77+
from `Zend\Authentication\Result` to validation message identifiers.
78+
`code_map` is an array of integer code => string message identifier pairs
79+
80+
A new custom message identifier can be specified in `code_map` which will then
81+
be registered as a new message type with the template value set to the `general` message.
82+
Once registered, the message template for the new identifier can be changed
83+
as described in the [zend-validator documentation](https://docs.zendframework.com/zend-validator/messages/).
84+
85+
```php
86+
use Zend\Authentication\Validator\Authentication as AuthenticationValidator;
87+
88+
$validator = new AuthenticationValidator([
89+
'code_map' => [
90+
// map custom result code to existing message
91+
-990 => AuthenticationValidator::IDENTITY_NOT_FOUND,
92+
// map custom result code to a new message type
93+
-991 => 'custom_failure_identifier',
94+
],
95+
]);
96+
97+
$validator->setMessage('Custom Error Happened', 'custom_failure_identifier');
98+
```

src/Adapter/DbTable/AbstractAdapter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ protected function authenticateQuerySelect(Sql\Select $dbSelect)
348348
*/
349349
protected function authenticateValidateResultSet(array $resultIdentities)
350350
{
351-
if (count($resultIdentities) < 1) {
351+
if (! $resultIdentities) {
352352
$this->authenticateResultInfo['code'] = AuthenticationResult::FAILURE_IDENTITY_NOT_FOUND;
353353
$this->authenticateResultInfo['messages'][] = 'A record with the supplied identity could not be found.';
354354
return $this->authenticateCreateAuthResult();

src/Adapter/Digest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ public function authenticate()
162162
}
163163

164164
$id = "$this->identity:$this->realm";
165-
$idLength = strlen($id);
166165

167166
$result = [
168167
'code' => AuthenticationResult::FAILURE,
@@ -178,7 +177,7 @@ public function authenticate()
178177
if (empty($line)) {
179178
break;
180179
}
181-
if (substr($line, 0, $idLength) === $id) {
180+
if (0 === strpos($line, $id)) {
182181
if (CryptUtils::compareStrings(
183182
substr($line, -32),
184183
md5("$this->identity:$this->realm:$this->credential")

src/Adapter/Http.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ protected function _basicAuth($header)
484484
$auth = substr($header, strlen('Basic '));
485485
$auth = base64_decode($auth);
486486
if (! $auth) {
487-
throw new Exception\RuntimeException('Unable to base64_decode Authorization header value');
487+
return $this->challengeClient();
488488
}
489489

490490
// See ZF-1253. Validate the credentials the same way the digest

src/Validator/Authentication.php

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
33
* @see https://github.com/zendframework/zend-authentication for the canonical source repository
4-
* @copyright Copyright (c) 2013-2018 Zend Technologies USA Inc. (https://www.zend.com)
4+
* @copyright Copyright (c) 2013-2019 Zend Technologies USA Inc. (https://www.zend.com)
55
* @license https://github.com/zendframework/zend-authentication/blob/master/LICENSE.md New BSD License
66
*/
77

@@ -15,6 +15,9 @@
1515
use Zend\Stdlib\ArrayUtils;
1616
use Zend\Validator\AbstractValidator;
1717

18+
use function is_array;
19+
use function is_string;
20+
1821
/**
1922
* Authentication Validator
2023
*/
@@ -41,6 +44,12 @@ class Authentication extends AbstractValidator
4144
Result::FAILURE_UNCATEGORIZED => self::UNCATEGORIZED,
4245
];
4346

47+
/**
48+
* Authentication\Result codes mapping configurable overrides
49+
* @var string[]
50+
*/
51+
protected $codeMap = [];
52+
4453
/**
4554
* Error Messages
4655
* @var array
@@ -89,18 +98,31 @@ public function __construct($options = null)
8998
}
9099

91100
if (is_array($options)) {
92-
if (array_key_exists('adapter', $options)) {
101+
if (isset($options['adapter'])) {
93102
$this->setAdapter($options['adapter']);
94103
}
95-
if (array_key_exists('identity', $options)) {
104+
if (isset($options['identity'])) {
96105
$this->setIdentity($options['identity']);
97106
}
98-
if (array_key_exists('credential', $options)) {
107+
if (isset($options['credential'])) {
99108
$this->setCredential($options['credential']);
100109
}
101-
if (array_key_exists('service', $options)) {
110+
if (isset($options['service'])) {
102111
$this->setService($options['service']);
103112
}
113+
if (isset($options['code_map'])) {
114+
foreach ($options['code_map'] as $code => $template) {
115+
if (empty($template) || ! is_string($template)) {
116+
throw new Exception\InvalidArgumentException(
117+
'Message key in code_map option must be a non-empty string'
118+
);
119+
}
120+
if (! isset($this->messageTemplates[$template])) {
121+
$this->messageTemplates[$template] = $this->messageTemplates[static::GENERAL];
122+
}
123+
$this->codeMap[(int) $code] = $template;
124+
}
125+
}
104126
}
105127
parent::__construct($options);
106128
}
@@ -244,15 +266,27 @@ public function isValid($value = null, $context = null)
244266
return true;
245267
}
246268

247-
$code = self::GENERAL;
248-
if (array_key_exists($result->getCode(), self::CODE_MAP)) {
249-
$code = self::CODE_MAP[$result->getCode()];
250-
}
251-
$this->error($code);
269+
$messageKey = $this->mapResultCodeToMessageKey($result->getCode());
270+
$this->error($messageKey);
252271

253272
return false;
254273
}
255274

275+
/**
276+
* @param int $code Authentication result code
277+
* @return string Message key that should be used for the code
278+
*/
279+
protected function mapResultCodeToMessageKey($code)
280+
{
281+
if (isset($this->codeMap[$code])) {
282+
return $this->codeMap[$code];
283+
}
284+
if (array_key_exists($code, static::CODE_MAP)) {
285+
return static::CODE_MAP[$code];
286+
}
287+
return self::GENERAL;
288+
}
289+
256290
/**
257291
* @return ValidatableAdapterInterface
258292
* @throws Exception\RuntimeException if no adapter present in

test/Adapter/Http/AuthTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,21 @@ public function testBasicAuthBadPassword()
215215
$this->_checkUnauthorized($data, $basic);
216216
}
217217

218+
public function testBasicAuthTokenIsNotBase64()
219+
{
220+
// Attempt Basic Authentication with a valid username, but invalid
221+
// password
222+
223+
// The expected Basic Www-Authenticate header value
224+
$basic = [
225+
'type' => 'Basic ',
226+
'realm' => 'realm="' . $this->_basicConfig['realm'] . '"',
227+
];
228+
229+
$data = $this->_doAuth('Basic', 'basic');
230+
$this->_checkUnauthorized($data, $basic);
231+
}
232+
218233
public function testDigestAuthValidCreds()
219234
{
220235
// Attempt Digest Authentication with a valid username and password

0 commit comments

Comments
 (0)