php-fabiang-sasl_1.0.0.orig.tar.gz
mirabilos authored 5 years ago
mirabilos committed 5 years ago
0 | Modified BSD License | |
1 | ==================== | |
2 | ||
3 | Copyright (c) 2002-2003 Richard Heyes, | |
4 | 2014 Jaussoin Timothée, | |
5 | 2014 Fabian Grutschus | |
6 | All rights reserved. | |
7 | ||
8 | Redistribution and use in source and binary forms, with or without modification, | |
9 | are permitted provided that the following conditions are met: | |
10 | ||
11 | 1. Redistributions of source code must retain the above copyright notice, this | |
12 | list of conditions and the following disclaimer. | |
13 | ||
14 | 2. Redistributions in binary form must reproduce the above copyright notice, | |
15 | this list of conditions and the following disclaimer in the documentation | |
16 | and/or other materials provided with the distribution. | |
17 | ||
18 | 3. The names of the authors may not be used to endorse or promote | |
19 | products derived from this software without specific prior written | |
20 | permission | |
21 | ||
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | |
26 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
29 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
0 | # fabiang/sasl | |
1 | ||
2 | The PHP SASL Authentification Library. | |
3 | ||
4 | [![Latest Stable Version](https://poser.pugx.org/fabiang/sasl/v/stable.svg)](https://packagist.org/packages/fabiang/sasl) [![Total Downloads](https://poser.pugx.org/fabiang/sasl/downloads.svg)](https://packagist.org/packages/fabiang/sasl) [![Latest Unstable Version](https://poser.pugx.org/fabiang/sasl/v/unstable.svg)](https://packagist.org/packages/fabiang/sasl) [![License](https://poser.pugx.org/fabiang/sasl/license.svg)](https://packagist.org/packages/fabiang/sasl) [![HHVM Status](http://hhvm.h4cc.de/badge/fabiang/sasl.svg)](http://hhvm.h4cc.de/package/fabiang/sasl) | |
5 | [![Build Status](https://travis-ci.org/fabiang/sasl.svg?branch=master)](https://travis-ci.org/fabiang/sasl) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/fabiang/sasl/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/fabiang/sasl/?branch=master) [![Code Climate](https://codeclimate.com/github/fabiang/sasl/badges/gpa.svg)](https://codeclimate.com/github/fabiang/sasl) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/e81e1e30-c545-420a-8a0c-59b60976f54b/mini.png)](https://insight.sensiolabs.com/projects/e81e1e30-c545-420a-8a0c-59b60976f54b) [![Coverage Status](https://img.shields.io/coveralls/fabiang/sasl.svg)](https://coveralls.io/r/fabiang/sasl) [![Dependency Status](https://gemnasium.com/fabiang/sasl.svg)](https://gemnasium.com/fabiang/sasl) | |
6 | ||
7 | Provides code to generate responses to common SASL mechanisms, including: | |
8 | * Digest-MD5 | |
9 | * Cram-MD5 | |
10 | * Plain | |
11 | * Anonymous | |
12 | * Login (Pseudo mechanism) | |
13 | * SCRAM | |
14 | ||
15 | Full refactored version of the the original [Auth_SASL2 Pear package](http://pear.php.net/package/Auth_SASL2/). | |
16 | ||
17 | ## Installation | |
18 | ||
19 | The easiest way to install fabiang/sasl is by using Composer: | |
20 | ||
21 | ``` | |
22 | curl -sS https://getcomposer.org/installer | php | |
23 | php composer.phar require fabiang/sasl='1.0.x-dev' | |
24 | ``` | |
25 | ||
26 | ## Usage | |
27 | ||
28 | Use the factory method to create a authentication mechanism object: | |
29 | ||
30 | ```php | |
31 | use Fabiang\Sasl\Sasl; | |
32 | ||
33 | $factory = new Sasl; | |
34 | ||
35 | $mechanism = $factory->factory('SCRAM-SHA-1', array( | |
36 | 'authcid' => 'username', | |
37 | 'secret' => 'password', | |
38 | 'authzid' => 'authzid', // optional. Username to proxy as | |
39 | 'service' => 'servicename', // optional. Name of the service | |
40 | 'hostname' => 'hostname', // optional. Hostname of the service | |
41 | )); | |
42 | ||
43 | $response = $mechanism->createResponse(); | |
44 | ``` | |
45 | ||
46 | Challenge-based authentication mechanisms implement the interface | |
47 | `Fabiang\Sasl\Authentication\ChallengeAuthenticationInterface`. | |
48 | For those mechanisms call the method again with the challenge: | |
49 | ||
50 | ```php | |
51 | $response = $mechanism->createResponse($challenge); | |
52 | ``` | |
53 | ||
54 | **Note**: The challenge must be Base64 decoded. | |
55 | ||
56 | ### SCRAM verification | |
57 | ||
58 | To verify the data returned by the server for SCRAM you can call: | |
59 | ||
60 | ```php | |
61 | $mechanism->verify($data); | |
62 | ``` | |
63 | ||
64 | If the method returns false you should disconnect. | |
65 | ||
66 | ### Required options | |
67 | ||
68 | List of options required by authentication mechanisms. | |
69 | For mechanisms that are challenge-based you'll need to call `createResponse()` | |
70 | again and send the returned value to the server. | |
71 | ||
72 | | Mechanism | Authcid | Secret | Authzid | Service | Hostname | Challenge | | |
73 | | --------- | ------- | ------ | -------- | ------- | -------- | --------- | | |
74 | | Anonymous | yes | no | no | no | no | no | | |
75 | | CramMD5 | yes | yes | no | no | no | yes | | |
76 | | DigestMD5 | yes | yes | optional | yes | yes | yes | | |
77 | | External | no | no | yes | no | no | no | | |
78 | | Login | yes | yes | no | no | no | no | | |
79 | | Plain | yes | yes | optional | no | no | no | | |
80 | | SCRAM-* | yes | yes | optional | no | no | yes | | |
81 | ||
82 | ## Developing | |
83 | ||
84 | If you like this library and you want to contribute, make sure the unit tests | |
85 | and integration tests are running. Composer will help you to install the right | |
86 | version of PHPUnit and Behat. | |
87 | ||
88 | ``` | |
89 | composer install --dev | |
90 | ``` | |
91 | ||
92 | After that run the unit tests: | |
93 | ||
94 | ``` | |
95 | ./vendor/bin/phpunit -c tests | |
96 | ``` | |
97 | ||
98 | The integration tests verify the authentication methods against an Ejabberd and Dovecot server. | |
99 | To launch the servers you can use the provided Vagrant box. | |
100 | Just [install Vagrant](https://www.vagrantup.com/downloads.html) and run: | |
101 | ||
102 | ``` | |
103 | vagrant up | |
104 | ``` | |
105 | ||
106 | After some minutes you'll have the runnig server instances inside of a virtual machine. | |
107 | Now you can run the integration tests: | |
108 | ||
109 | ``` | |
110 | ./vendor/bin/behat -c tests/behat.yml.dist | |
111 | ``` | |
112 | ||
113 | ## License | |
114 | ||
115 | BSD-3-Clause. See the [LICENSE.md](LICENSE.md). |
0 | { | |
1 | "name": "fabiang/sasl", | |
2 | "description": "Abstraction of various SASL mechanism responses.", | |
3 | "license": "BSD-3-Clause", | |
4 | "homepage": "https://github.com/fabiang/sasl", | |
5 | "keywords": ["sasl", "authentication", "scram", "auth"], | |
6 | "type": "library", | |
7 | "authors": [ | |
8 | { | |
9 | "name": "Fabian Grutschus", | |
10 | "email": "f.grutschus@lubyte.de" | |
11 | }, | |
12 | { | |
13 | "name": "Anish Mistry", | |
14 | "email": "amistry@am-productions.biz" | |
15 | }, | |
16 | { | |
17 | "name": "Richard Heyes", | |
18 | "email": "richard@php.net" | |
19 | }, | |
20 | { | |
21 | "name": "Michael Bretterklieber", | |
22 | "email": "michael@bretterklieber.com" | |
23 | } | |
24 | ], | |
25 | "autoload": { | |
26 | "psr-4": { | |
27 | "Fabiang\\Sasl\\": "src/" | |
28 | } | |
29 | }, | |
30 | "autoload-dev": { | |
31 | "psr-4": { | |
32 | "Fabiang\\Sasl\\Behat\\": "tests/features/bootstrap" | |
33 | } | |
34 | }, | |
35 | "require": { | |
36 | "php": ">=5.3.0" | |
37 | }, | |
38 | "require-dev": { | |
39 | "phpunit/phpunit": "~4.4", | |
40 | "satooshi/php-coveralls": "~0.6", | |
41 | "behat/behat": "~3.0", | |
42 | "codeclimate/php-test-reporter": "@dev" | |
43 | }, | |
44 | "extra": { | |
45 | "branch-alias": { | |
46 | "dev-master": "1.0.x-dev" | |
47 | } | |
48 | } | |
49 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Richard Heyes <richard@php.net> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | use Fabiang\Sasl\Options; | |
40 | ||
41 | /** | |
42 | * Common functionality to SASL mechanisms | |
43 | * | |
44 | * @author Richard Heyes <richard@php.net> | |
45 | */ | |
46 | abstract class AbstractAuthentication | |
47 | { | |
48 | ||
49 | /** | |
50 | * Use random devices. | |
51 | * | |
52 | * @var bool | |
53 | */ | |
54 | public static $useDevRandom = true; | |
55 | ||
56 | /** | |
57 | * Options object. | |
58 | * | |
59 | * @var Options | |
60 | */ | |
61 | protected $options; | |
62 | ||
63 | /** | |
64 | * | |
65 | * @param Options $options | |
66 | */ | |
67 | public function __construct(Options $options) | |
68 | { | |
69 | $this->options = $options; | |
70 | } | |
71 | ||
72 | /** | |
73 | * Get options object. | |
74 | * | |
75 | * @return Options | |
76 | */ | |
77 | public function getOptions() | |
78 | { | |
79 | return $this->options; | |
80 | } | |
81 | ||
82 | /** | |
83 | * Creates the client nonce for the response | |
84 | * | |
85 | * @return string The cnonce value | |
86 | */ | |
87 | protected function generateCnonce() | |
88 | { | |
89 | foreach (array('/dev/urandom', '/dev/random') as $file) { | |
90 | if (true === static::$useDevRandom && is_readable($file)) { | |
91 | return base64_encode(file_get_contents($file, false, null, -1, 32)); | |
92 | } | |
93 | } | |
94 | ||
95 | $cnonce = ''; | |
96 | for ($i = 0; $i < 32; $i++) { | |
97 | $cnonce .= chr(mt_rand(0, 255)); | |
98 | } | |
99 | ||
100 | return base64_encode($cnonce); | |
101 | } | |
102 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Richard Heyes <richard@php.net> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | /** | |
40 | * Implmentation of ANONYMOUS SASL mechanism | |
41 | * | |
42 | * @author Richard Heyes <richard@php.net> | |
43 | */ | |
44 | class Anonymous extends AbstractAuthentication implements AuthenticationInterface | |
45 | { | |
46 | ||
47 | /** | |
48 | * Not much to do here except return the token supplied. | |
49 | * No encoding, hashing or encryption takes place for this | |
50 | * mechanism, simply one of: | |
51 | * o An email address | |
52 | * o An opaque string not containing "@" that can be interpreted | |
53 | * by the sysadmin | |
54 | * o Nothing | |
55 | * | |
56 | * We could have some logic here for the second option, but this | |
57 | * would by no means create something interpretable. | |
58 | * @param string $challenge | |
59 | * @return string The unaltered input token | |
60 | */ | |
61 | public function createResponse($challenge = null) | |
62 | { | |
63 | return $this->options->getAuthcid(); | |
64 | } | |
65 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | /** | |
40 | * Interface for Sasl authentication classes. | |
41 | * | |
42 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
43 | */ | |
44 | interface AuthenticationInterface | |
45 | { | |
46 | ||
47 | /** | |
48 | * Create response. | |
49 | * | |
50 | * @param string $challenge Response challenge. Not every authentication method requires this value. | |
51 | */ | |
52 | public function createResponse($challenge = null); | |
53 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | /** | |
40 | * Authentication mechaisms based on challenge responses. | |
41 | * | |
42 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
43 | */ | |
44 | interface ChallengeAuthenticationInterface extends AuthenticationInterface | |
45 | { | |
46 | ||
47 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Richard Heyes <richard@php.net> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | use Fabiang\Sasl\Authentication\AbstractAuthentication; | |
40 | ||
41 | /** | |
42 | * Implmentation of CRAM-MD5 SASL mechanism | |
43 | * | |
44 | * @author Richard Heyes <richard@php.net> | |
45 | */ | |
46 | class CramMD5 extends AbstractAuthentication implements ChallengeAuthenticationInterface | |
47 | { | |
48 | ||
49 | /** | |
50 | * Implements the CRAM-MD5 SASL mechanism | |
51 | * This DOES NOT base64 encode the return value, | |
52 | * you will need to do that yourself. | |
53 | * | |
54 | * @param string $challenge The challenge supplied by the server. | |
55 | * this should be already base64_decoded. | |
56 | * | |
57 | * @return string The string to pass back to the server, of the form | |
58 | * "<user> <digest>". This is NOT base64_encoded. | |
59 | */ | |
60 | public function createResponse($challenge = null) | |
61 | { | |
62 | return $this->options->getAuthcid() . ' ' . hash_hmac('md5', $challenge, $this->options->getSecret()); | |
63 | } | |
64 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Richard Heyes <richard@php.net> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | use Fabiang\Sasl\Exception\InvalidArgumentException; | |
40 | use Fabiang\Sasl\Exception\RuntimeException; | |
41 | ||
42 | /** | |
43 | * Implmentation of DIGEST-MD5 SASL mechanism | |
44 | * | |
45 | * @author Richard Heyes <richard@php.net> | |
46 | */ | |
47 | class DigestMD5 extends AbstractAuthentication implements ChallengeAuthenticationInterface | |
48 | { | |
49 | ||
50 | /** | |
51 | * Provides the (main) client response for DIGEST-MD5 | |
52 | * requires a few extra parameters than the other | |
53 | * mechanisms, which are unavoidable. | |
54 | * | |
55 | * @param string $challenge The digest challenge sent by the server | |
56 | * @return string The digest response (NOT base64 encoded) | |
57 | */ | |
58 | public function createResponse($challenge = null) | |
59 | { | |
60 | $parsedChallenge = $this->parseChallenge($challenge); | |
61 | $authzidString = ''; | |
62 | ||
63 | $authcid = $this->options->getAuthcid(); | |
64 | $pass = $this->options->getSecret(); | |
65 | $authzid = $this->options->getAuthzid(); | |
66 | $service = $this->options->getService(); | |
67 | $hostname = $this->options->getHostname(); | |
68 | if (!empty($authzid)) { | |
69 | $authzidString = 'authzid="' . $authzid . '",'; | |
70 | } | |
71 | ||
72 | if (!empty($parsedChallenge)) { | |
73 | $cnonce = $this->generateCnonce(); | |
74 | $digestUri = sprintf('%s/%s', $service, $hostname); | |
75 | $responseValue = $this->getResponseValue( | |
76 | $authcid, | |
77 | $pass, | |
78 | $parsedChallenge['realm'], | |
79 | $parsedChallenge['nonce'], | |
80 | $cnonce, | |
81 | $digestUri, | |
82 | $authzid | |
83 | ); | |
84 | ||
85 | $realm = ''; | |
86 | if ($parsedChallenge['realm']) { | |
87 | $realm = 'realm="' . $parsedChallenge['realm'] . '",'; | |
88 | } | |
89 | ||
90 | return sprintf( | |
91 | 'username="%s",%s%snonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",' | |
92 | . 'response=%s,maxbuf=%d', | |
93 | $authcid, | |
94 | $realm, | |
95 | $authzidString, | |
96 | $parsedChallenge['nonce'], | |
97 | $cnonce, | |
98 | $digestUri, | |
99 | $responseValue, | |
100 | $parsedChallenge['maxbuf'] | |
101 | ); | |
102 | } | |
103 | ||
104 | throw new InvalidArgumentException('Invalid digest challenge'); | |
105 | } | |
106 | ||
107 | /** | |
108 | * Parses and verifies the digest challenge* | |
109 | * | |
110 | * @param string $challenge The digest challenge | |
111 | * @return array The parsed challenge as an assoc | |
112 | * array in the form "directive => value". | |
113 | * @access private | |
114 | */ | |
115 | private function parseChallenge($challenge) | |
116 | { | |
117 | /** | |
118 | * Defaults and required directives | |
119 | */ | |
120 | $tokens = array( | |
121 | 'realm' => '', | |
122 | 'maxbuf' => 65536, | |
123 | ); | |
124 | ||
125 | $matches = array(); | |
126 | while (preg_match('/^(?<key>[a-z-]+)=(?<value>"[^"]+(?<!\\\)"|[^,]+)/i', $challenge, $matches)) { | |
127 | $match = $matches[0]; | |
128 | $key = $matches['key']; | |
129 | $value = $matches['value']; | |
130 | ||
131 | $this->checkToken($tokens, $key, $value); | |
132 | ||
133 | // Remove the just parsed directive from the challenge | |
134 | $challenge = substr($challenge, strlen($match) + 1); | |
135 | } | |
136 | ||
137 | // Required: nonce, algorithm | |
138 | if (empty($tokens['nonce']) || empty($tokens['algorithm'])) { | |
139 | return array(); | |
140 | } | |
141 | ||
142 | return $tokens; | |
143 | } | |
144 | ||
145 | /** | |
146 | * Check found token. | |
147 | * | |
148 | * @param array $tokens | |
149 | * @param string $key | |
150 | * @param string $value | |
151 | */ | |
152 | private function checkToken(array &$tokens, $key, $value) | |
153 | { | |
154 | // Ignore these as per rfc2831 | |
155 | if ($key !== 'opaque' && $key !== 'domain') { | |
156 | if (!empty($tokens[$key])) { | |
157 | // Allowed multiple "realm" and "auth-param" | |
158 | if ('realm' === $key || 'auth-param' === $key) { | |
159 | ||
160 | // we don't support multiple realms yet | |
161 | if ('realm' === $key) { | |
162 | throw new RuntimeException('Multiple realms are not supported'); | |
163 | } | |
164 | ||
165 | $tokens[$key] = (array) $tokens[$key]; | |
166 | $tokens[$key][] = $this->trim($value); | |
167 | ||
168 | // Any other multiple instance = failure | |
169 | } else { | |
170 | return array(); | |
171 | } | |
172 | } else { | |
173 | $tokens[$key] = $this->trim($value); | |
174 | } | |
175 | } | |
176 | } | |
177 | ||
178 | /** | |
179 | * | |
180 | * @param string $string | |
181 | * @return string | |
182 | */ | |
183 | private function trim($string) | |
184 | { | |
185 | return trim($string, '"'); | |
186 | } | |
187 | ||
188 | /** | |
189 | * Creates the response= part of the digest response | |
190 | * | |
191 | * @param string $authcid Authentication id (username) | |
192 | * @param string $pass Password | |
193 | * @param string $realm Realm as provided by the server | |
194 | * @param string $nonce Nonce as provided by the server | |
195 | * @param string $cnonce Client nonce | |
196 | * @param string $digest_uri The digest-uri= value part of the response | |
197 | * @param string $authzid Authorization id | |
198 | * @return string The response= part of the digest response | |
199 | * @access private | |
200 | */ | |
201 | private function getResponseValue($authcid, $pass, $realm, $nonce, $cnonce, $digest_uri, $authzid = '') | |
202 | { | |
203 | if ($authzid == '') { | |
204 | $A1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce); | |
205 | } else { | |
206 | $A1 = sprintf('%s:%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce, $authzid); | |
207 | } | |
208 | $A2 = 'AUTHENTICATE:' . $digest_uri; | |
209 | return md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($A1), $nonce, $cnonce, md5($A2))); | |
210 | } | |
211 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Christoph Schulz <develop@kristov.de> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | /** | |
40 | * Implementation of EXTERNAL SASL mechanism | |
41 | * | |
42 | * @author Christoph Schulz <develop@kristov.de> | |
43 | */ | |
44 | class External extends AbstractAuthentication implements AuthenticationInterface | |
45 | { | |
46 | ||
47 | /** | |
48 | * Returns EXTERNAL response | |
49 | * | |
50 | * @param string $challenge | |
51 | * @return stringEXTERNAL Response | |
52 | */ | |
53 | public function createResponse($challenge = null) | |
54 | { | |
55 | return $this->options->getAuthcid(); | |
56 | } | |
57 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Richard Heyes <richard@php.net> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | /** | |
40 | * This is technically not a SASL mechanism, however | |
41 | * it's used by Net_Sieve, Net_Cyrus and potentially | |
42 | * other protocols , so here is a good place to abstract | |
43 | * it. | |
44 | * | |
45 | * @author Richard Heyes <richard@php.net> | |
46 | */ | |
47 | class Login extends AbstractAuthentication implements AuthenticationInterface | |
48 | { | |
49 | ||
50 | /** | |
51 | * Pseudo SASL LOGIN mechanism | |
52 | * | |
53 | * @return string LOGIN string | |
54 | */ | |
55 | public function createResponse($challenge = null) | |
56 | { | |
57 | return sprintf('LOGIN %s %s', $this->options->getAuthcid(), $this->options->getSecret()); | |
58 | } | |
59 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Richard Heyes <richard@php.net> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | /** | |
40 | * Implmentation of PLAIN SASL mechanism | |
41 | * | |
42 | * @author Richard Heyes <richard@php.net> | |
43 | */ | |
44 | class Plain extends AbstractAuthentication implements AuthenticationInterface | |
45 | { | |
46 | ||
47 | /** | |
48 | * Returns PLAIN response | |
49 | ||
50 | * @return string PLAIN Response | |
51 | */ | |
52 | public function createResponse($challenge = null) | |
53 | { | |
54 | return $this->options->getAuthzid() . chr(0) | |
55 | . $this->options->getAuthcid() . chr(0) . $this->options->getSecret(); | |
56 | } | |
57 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Jehan <jehan.marmottard@gmail.com> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | use Fabiang\Sasl\Authentication\AbstractAuthentication; | |
40 | use Fabiang\Sasl\Options; | |
41 | use Fabiang\Sasl\Exception\InvalidArgumentException; | |
42 | ||
43 | /** | |
44 | * Implementation of SCRAM-* SASL mechanisms. | |
45 | * SCRAM mechanisms have 3 main steps (initial response, response to the server challenge, then server signature | |
46 | * verification) which keep state-awareness. Therefore a single class instanciation must be done and reused for the whole | |
47 | * authentication process. | |
48 | * | |
49 | * @author Jehan <jehan.marmottard@gmail.com> | |
50 | */ | |
51 | class SCRAM extends AbstractAuthentication implements ChallengeAuthenticationInterface, VerificationInterface | |
52 | { | |
53 | ||
54 | private $hashAlgo; | |
55 | private $hash; | |
56 | private $hmac; | |
57 | private $gs2Header; | |
58 | private $cnonce; | |
59 | private $firstMessageBare; | |
60 | private $saltedPassword; | |
61 | private $authMessage; | |
62 | ||
63 | /** | |
64 | * Construct a SCRAM-H client where 'H' is a cryptographic hash function. | |
65 | * | |
66 | * @param Options $options | |
67 | * @param string $hash The name cryptographic hash function 'H' as registered by IANA in the "Hash Function Textual | |
68 | * Names" registry. | |
69 | * @link http://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml "Hash Function Textual | |
70 | * Names" | |
71 | * format of core PHP hash function. | |
72 | * @throws InvalidArgumentException | |
73 | */ | |
74 | public function __construct(Options $options, $hash) | |
75 | { | |
76 | parent::__construct($options); | |
77 | ||
78 | // Though I could be strict, I will actually also accept the naming used in the PHP core hash framework. | |
79 | // For instance "sha1" is accepted, while the registered hash name should be "SHA-1". | |
80 | $normalizedHash = str_replace('-', '', strtolower($hash)); | |
81 | ||
82 | $hashAlgos = hash_algos(); | |
83 | if (!in_array($normalizedHash, $hashAlgos)) { | |
84 | throw new InvalidArgumentException("Invalid SASL mechanism type '$hash'"); | |
85 | } | |
86 | ||
87 | $this->hash = function ($data) use ($normalizedHash) { | |
88 | return hash($normalizedHash, $data, true); | |
89 | }; | |
90 | ||
91 | $this->hmac = function ($key, $str, $raw) use ($normalizedHash) { | |
92 | return hash_hmac($normalizedHash, $str, $key, $raw); | |
93 | }; | |
94 | ||
95 | $this->hashAlgo = $normalizedHash; | |
96 | } | |
97 | ||
98 | /** | |
99 | * Provides the (main) client response for SCRAM-H. | |
100 | * | |
101 | * @param string $challenge The challenge sent by the server. | |
102 | * If the challenge is null or an empty string, the result will be the "initial response". | |
103 | * @return string|false The response (binary, NOT base64 encoded) | |
104 | */ | |
105 | public function createResponse($challenge = null) | |
106 | { | |
107 | $authcid = $this->formatName($this->options->getAuthcid()); | |
108 | if (empty($authcid)) { | |
109 | return false; | |
110 | } | |
111 | ||
112 | $authzid = $this->options->getAuthzid(); | |
113 | if (!empty($authzid)) { | |
114 | $authzid = $this->formatName($authzid); | |
115 | } | |
116 | ||
117 | if (empty($challenge)) { | |
118 | return $this->generateInitialResponse($authcid, $authzid); | |
119 | } else { | |
120 | return $this->generateResponse($challenge, $this->options->getSecret()); | |
121 | } | |
122 | } | |
123 | ||
124 | /** | |
125 | * Prepare a name for inclusion in a SCRAM response. | |
126 | * | |
127 | * @param string $username a name to be prepared. | |
128 | * @return string the reformated name. | |
129 | */ | |
130 | private function formatName($username) | |
131 | { | |
132 | return str_replace(array('=', ','), array('=3D', '=2C'), $username); | |
133 | } | |
134 | ||
135 | /** | |
136 | * Generate the initial response which can be either sent directly in the first message or as a response to an empty | |
137 | * server challenge. | |
138 | * | |
139 | * @param string $authcid Prepared authentication identity. | |
140 | * @param string $authzid Prepared authorization identity. | |
141 | * @return string The SCRAM response to send. | |
142 | */ | |
143 | private function generateInitialResponse($authcid, $authzid) | |
144 | { | |
145 | $gs2CbindFlag = 'n,'; | |
146 | $this->gs2Header = $gs2CbindFlag . (!empty($authzid) ? 'a=' . $authzid : '') . ','; | |
147 | ||
148 | // I must generate a client nonce and "save" it for later comparison on second response. | |
149 | $this->cnonce = $this->generateCnonce(); | |
150 | ||
151 | $this->firstMessageBare = 'n=' . $authcid . ',r=' . $this->cnonce; | |
152 | return $this->gs2Header . $this->firstMessageBare; | |
153 | } | |
154 | ||
155 | /** | |
156 | * Parses and verifies a non-empty SCRAM challenge. | |
157 | * | |
158 | * @param string $challenge The SCRAM challenge | |
159 | * @return string|false The response to send; false in case of wrong challenge or if an initial response has not | |
160 | * been generated first. | |
161 | */ | |
162 | private function generateResponse($challenge, $password) | |
163 | { | |
164 | $matches = array(); | |
165 | ||
166 | $serverMessageRegexp = "#^r=([\x21-\x2B\x2D-\x7E/]+)" | |
167 | . ",s=((?:[A-Za-z0-9/+]{4})*(?:[A-Za-z0-9/+]{3}=|[A-Za-z0-9/+]{2}==)?)" | |
168 | . ",i=([0-9]*)(,[A-Za-z]=[^,])*$#"; | |
169 | if (!isset($this->cnonce, $this->gs2Header) || !preg_match($serverMessageRegexp, $challenge, $matches)) { | |
170 | return false; | |
171 | } | |
172 | $nonce = $matches[1]; | |
173 | $salt = base64_decode($matches[2]); | |
174 | if (!$salt) { | |
175 | // Invalid Base64. | |
176 | return false; | |
177 | } | |
178 | $i = intval($matches[3]); | |
179 | ||
180 | $cnonce = substr($nonce, 0, strlen($this->cnonce)); | |
181 | if ($cnonce !== $this->cnonce) { | |
182 | // Invalid challenge! Are we under attack? | |
183 | return false; | |
184 | } | |
185 | ||
186 | $channelBinding = 'c=' . base64_encode($this->gs2Header); | |
187 | $finalMessage = $channelBinding . ',r=' . $nonce; | |
188 | $saltedPassword = $this->hi($password, $salt, $i); | |
189 | $this->saltedPassword = $saltedPassword; | |
190 | $clientKey = call_user_func($this->hmac, $saltedPassword, "Client Key", true); | |
191 | $storedKey = call_user_func($this->hash, $clientKey, true); | |
192 | $authMessage = $this->firstMessageBare . ',' . $challenge . ',' . $finalMessage; | |
193 | $this->authMessage = $authMessage; | |
194 | $clientSignature = call_user_func($this->hmac, $storedKey, $authMessage, true); | |
195 | $clientProof = $clientKey ^ $clientSignature; | |
196 | $proof = ',p=' . base64_encode($clientProof); | |
197 | ||
198 | return $finalMessage . $proof; | |
199 | } | |
200 | ||
201 | /** | |
202 | * Hi() call, which is essentially PBKDF2 (RFC-2898) with HMAC-H() as the pseudorandom function. | |
203 | * | |
204 | * @param string $str The string to hash. | |
205 | * @param string $salt The salt value. | |
206 | * @param int $i The iteration count. | |
207 | */ | |
208 | private function hi($str, $salt, $i) | |
209 | { | |
210 | $int1 = "\0\0\0\1"; | |
211 | $ui = call_user_func($this->hmac, $str, $salt . $int1, true); | |
212 | $result = $ui; | |
213 | for ($k = 1; $k < $i; $k++) { | |
214 | $ui = call_user_func($this->hmac, $str, $ui, true); | |
215 | $result = $result ^ $ui; | |
216 | } | |
217 | return $result; | |
218 | } | |
219 | ||
220 | /** | |
221 | * SCRAM has also a server verification step. On a successful outcome, it will send additional data which must | |
222 | * absolutely be checked against this function. If this fails, the entity which we are communicating with is probably | |
223 | * not the server as it has not access to your ServerKey. | |
224 | * | |
225 | * @param string $data The additional data sent along a successful outcome. | |
226 | * @return bool Whether the server has been authenticated. | |
227 | * If false, the client must close the connection and consider to be under a MITM attack. | |
228 | */ | |
229 | public function verify($data) | |
230 | { | |
231 | $verifierRegexp = '#^v=((?:[A-Za-z0-9/+]{4})*(?:[A-Za-z0-9/+]{3}=|[A-Za-z0-9/+]{2}==)?)$#'; | |
232 | ||
233 | $matches = array(); | |
234 | if (!isset($this->saltedPassword, $this->authMessage) || !preg_match($verifierRegexp, $data, $matches)) { | |
235 | // This cannot be an outcome, you never sent the challenge's response. | |
236 | return false; | |
237 | } | |
238 | ||
239 | $verifier = $matches[1]; | |
240 | $proposedServerSignature = base64_decode($verifier); | |
241 | $serverKey = call_user_func($this->hmac, $this->saltedPassword, "Server Key", true); | |
242 | $serverSignature = call_user_func($this->hmac, $serverKey, $this->authMessage, true); | |
243 | ||
244 | return $proposedServerSignature === $serverSignature; | |
245 | } | |
246 | ||
247 | /** | |
248 | * @return string | |
249 | */ | |
250 | public function getCnonce() | |
251 | { | |
252 | return $this->cnonce; | |
253 | } | |
254 | ||
255 | public function getSaltedPassword() | |
256 | { | |
257 | return $this->saltedPassword; | |
258 | } | |
259 | ||
260 | public function getAuthMessage() | |
261 | { | |
262 | return $this->authMessage; | |
263 | } | |
264 | ||
265 | public function getHashAlgo() | |
266 | { | |
267 | return $this->hashAlgo; | |
268 | } | |
269 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Jehan <jehan.marmottard@gmail.com> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Authentication; | |
38 | ||
39 | /** | |
40 | * | |
41 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
42 | */ | |
43 | interface VerificationInterface | |
44 | { | |
45 | ||
46 | /** | |
47 | * Varify connection. | |
48 | * | |
49 | * @param string $data | |
50 | */ | |
51 | public function verify($data); | |
52 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Exception; | |
38 | ||
39 | /** | |
40 | * Exception interface. | |
41 | * | |
42 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
43 | */ | |
44 | interface ExceptionInterface | |
45 | { | |
46 | ||
47 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Exception; | |
38 | ||
39 | use Fabiang\Sasl\Exception\ExceptionInterface; | |
40 | ||
41 | /** | |
42 | * InvalidArgumentException | |
43 | * | |
44 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
45 | */ | |
46 | class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface | |
47 | { | |
48 | ||
49 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl\Exception; | |
38 | ||
39 | use Fabiang\Sasl\Exception\ExceptionInterface; | |
40 | ||
41 | /** | |
42 | * RuntimeException | |
43 | * | |
44 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
45 | */ | |
46 | class RuntimeException extends \RuntimeException implements ExceptionInterface | |
47 | { | |
48 | ||
49 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl; | |
38 | ||
39 | /** | |
40 | * Options object for Sasl. | |
41 | * | |
42 | * @author Fabian Grutschus <f.grutschus@lubyte.de> | |
43 | */ | |
44 | class Options | |
45 | { | |
46 | ||
47 | /** | |
48 | * Authentication identity (e.g. username). | |
49 | * | |
50 | * @var string | |
51 | */ | |
52 | protected $authcid; | |
53 | ||
54 | /** | |
55 | * Authentication secret (e.g. password) | |
56 | * | |
57 | * @var string | |
58 | */ | |
59 | protected $secret; | |
60 | ||
61 | /** | |
62 | * Authorization identity | |
63 | * | |
64 | * @var string | |
65 | */ | |
66 | protected $authzid; | |
67 | ||
68 | /** | |
69 | * Service name. | |
70 | * | |
71 | * @var string | |
72 | */ | |
73 | protected $service; | |
74 | ||
75 | /** | |
76 | * Service hostname. | |
77 | * | |
78 | * @var string | |
79 | */ | |
80 | protected $hostname; | |
81 | ||
82 | /** | |
83 | * Constructor. | |
84 | * | |
85 | * @param string $authcid authentication identity (e.g. username) | |
86 | * @param string $secret authentication secret (e.g. password) | |
87 | * @param string $authzid authorization identity (username to proxy as) | |
88 | * @param string $service service name | |
89 | * @param string $hostname service hostname | |
90 | */ | |
91 | public function __construct($authcid, $secret = null, $authzid = null, $service = null, $hostname = null) | |
92 | { | |
93 | $this->authcid = $authcid; | |
94 | $this->secret = $secret; | |
95 | $this->authzid = $authzid; | |
96 | $this->service = $service; | |
97 | $this->hostname = $hostname; | |
98 | } | |
99 | ||
100 | public function getAuthcid() | |
101 | { | |
102 | return $this->authcid; | |
103 | } | |
104 | ||
105 | public function getSecret() | |
106 | { | |
107 | return $this->secret; | |
108 | } | |
109 | ||
110 | public function getAuthzid() | |
111 | { | |
112 | return $this->authzid; | |
113 | } | |
114 | ||
115 | public function getService() | |
116 | { | |
117 | return $this->service; | |
118 | } | |
119 | ||
120 | public function getHostname() | |
121 | { | |
122 | return $this->hostname; | |
123 | } | |
124 | } |
0 | <?php | |
1 | ||
2 | /** | |
3 | * Sasl library. | |
4 | * | |
5 | * Copyright (c) 2002-2003 Richard Heyes, | |
6 | * 2014 Fabian Grutschus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution.| | |
18 | * o The names of the authors may not be used to endorse or promote | |
19 | * products derived from this software without specific prior written | |
20 | * permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * @author Richard Heyes <richard@php.net> | |
35 | */ | |
36 | ||
37 | namespace Fabiang\Sasl; | |
38 | ||
39 | use Fabiang\Sasl\Exception\InvalidArgumentException; | |
40 | ||
41 | /** | |
42 | * Client implementation of various SASL mechanisms | |
43 | * | |
44 | * @author Richard Heyes <richard@php.net> | |
45 | */ | |
46 | class Sasl | |
47 | { | |
48 | ||
49 | /** | |
50 | * Known authentication mechanisms classes. | |
51 | * | |
52 | * @var array | |
53 | */ | |
54 | protected $mechanisms = array( | |
55 | 'anonymous' => 'Fabiang\\Sasl\Authentication\\Anonymous', | |
56 | 'login' => 'Fabiang\\Sasl\Authentication\\Login', | |
57 | 'plain' => 'Fabiang\\Sasl\Authentication\\Plain', | |
58 | 'external' => 'Fabiang\\Sasl\Authentication\\External', | |
59 | 'crammd5' => 'Fabiang\\Sasl\Authentication\\CramMD5', | |
60 | 'digestmd5' => 'Fabiang\\Sasl\Authentication\\DigestMD5', | |
61 | ); | |
62 | ||
63 | /** | |
64 | * Factory class. Returns an object of the request | |
65 | * type. | |
66 | * | |
67 | * @param string $type One of: Anonymous | |
68 | * Plain | |
69 | * CramMD5 | |
70 | * DigestMD5 | |
71 | * SCRAM-* (any mechanism of the SCRAM family) | |
72 | * Types are not case sensitive | |
73 | * @param Options|array Options for authentication | |
74 | * @return Authentication\AuthenticationInterface | |
75 | */ | |
76 | public function factory($type, $options = array()) | |
77 | { | |
78 | $className = null; | |
79 | $parameter = null; | |
80 | $matches = array(); | |
81 | $options = $this->createOptionsObject($options); | |
82 | ||
83 | $formatedType = strtolower(str_replace('-', '', $type)); | |
84 | ||
85 | if (isset($this->mechanisms[$formatedType])) { | |
86 | $className = $this->mechanisms[$formatedType]; | |
87 | } elseif (preg_match('/^scram(?<algo>.{1,9})$/i', $formatedType, $matches)) { | |
88 | $className = 'Fabiang\\Sasl\Authentication\\SCRAM'; | |
89 | $parameter = $matches['algo']; | |
90 | } | |
91 | ||
92 | if (null === $className) { | |
93 | throw new InvalidArgumentException("Invalid SASL mechanism type '$type'"); | |
94 | } | |
95 | ||
96 | $object = new $className($options, $parameter); | |
97 | return $object; | |
98 | } | |
99 | ||
100 | /** | |
101 | * | |
102 | * @param Options|array $options | |
103 | * @return \Fabiang\Sasl\Options | |
104 | * @throws InvalidArgumentException | |
105 | */ | |
106 | private function createOptionsObject($options) | |
107 | { | |
108 | $optionsObject = $options; | |
109 | ||
110 | if (is_array($options)) { | |
111 | $optionsObject = new Options( | |
112 | $this->checkEmpty($options, 'authcid'), | |
113 | $this->checkEmpty($options, 'secret'), | |
114 | $this->checkEmpty($options, 'authzid'), | |
115 | $this->checkEmpty($options, 'service'), | |
116 | $this->checkEmpty($options, 'hostname') | |
117 | ); | |
118 | } | |
119 | ||
120 | if (!($optionsObject instanceof Options)) { | |
121 | throw new InvalidArgumentException( | |
122 | 'Invalid options passed. Argument must be either of type "Fabiang\Sasl\Options" or "array", "' | |
123 | . (is_object($options) ? get_class($options) : gettype($options)) | |
124 | . '" given.' | |
125 | ); | |
126 | } | |
127 | ||
128 | return $optionsObject; | |
129 | } | |
130 | ||
131 | /** | |
132 | * | |
133 | * @param array $array | |
134 | * @param string $key | |
135 | * @return mixed | |
136 | */ | |
137 | private function checkEmpty(array $array, $key) | |
138 | { | |
139 | if (!empty($array[$key])) { | |
140 | return $array[$key]; | |
141 | } | |
142 | ||
143 | return null; | |
144 | } | |
145 | } |