Codebase list php-fabiang-sasl / 33dda12
php-fabiang-sasl_1.0.0.orig.tar.gz mirabilos authored 5 years ago mirabilos committed 5 years ago
19 changed file(s) with 1664 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
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 }