Completed
Pull Request — 2.x (#80)
by
unknown
02:00
created

LdapAdapter::escape()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 18
ccs 16
cts 16
cp 1
rs 9.4285
cc 1
eloc 15
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 *
4
 * This file is part of Aura for PHP.
5
 *
6
 * @license http://opensource.org/licenses/bsd-license.php BSD
7
 *
8
 */
9
namespace Aura\Auth\Adapter;
10
11
use Aura\Auth\Exception;
12
use Aura\Auth\Phpfunc;
13
14
/**
15
 *
16
 * Authenticate against an LDAP server.
17
 *
18
 * @package Aura.Auth
19
 *
20
 */
21
class LdapAdapter extends AbstractAdapter
22
{
23
    /**
24
     *
25
     * An LDAP server connection string.
26
     *
27
     * @var string
28
     *
29
     */
30
    protected $server;
31
32
    /**
33
     *
34
     * An sprintf() format string for the LDAP query.
35
     *
36
     * @var string
37
     *
38
     */
39
    protected $dnformat = null;
40
41
    /**
42
     *
43
     * Set these options after the LDAP connection.
44
     *
45
     * @var array
46
     *
47
     */
48
    protected $options = array();
49
50
    /**
51
     *
52
     * An object to intercept PHP calls.
53
     *
54
     * @var Phpfunc
55
     *
56
     */
57
    protected $phpfunc;
58
59
    /**
60
     *
61
     * Constructor.
62
     *
63
     * @param Phpfunc $phpfunc An object to intercept PHP calls.
64
     *
65
     * @param string $server An LDAP server connection string.
66
     *
67
     * @param string $dnformat An sprintf() format string for the LDAP query.
68
     *
69
     * @param array $options Set these options after the LDAP connection.
70
     *
71
     */
72 6
    public function __construct(
73
        Phpfunc $phpfunc,
74
        $server,
75
        $dnformat,
76
        array $options = array()
77
    ) {
78 6
        $this->phpfunc = $phpfunc;
79 6
        $this->server = $server;
80 6
        $this->dnformat = $dnformat;
81 6
        $this->options = $options;
82 6
    }
83
84
    /**
85
     *
86
     * Verifies a set of credentials.
87
     *
88
     * @param array $input The 'username' and 'password' to verify.
89
     *
90
     * @return mixed An array of verified user information, or boolean false
91
     * if verification failed.
92
     *
93
     */
94 3
    public function login(array $input)
95
    {
96 3
        $this->checkInput($input);
97 3
        $username = $input['username'];
98 3
        $password = $input['password'];
99
100 3
        $conn = $this->connect();
101 2
        $this->bind($conn, $username, $password);
102 1
        return array($username, array());
103
    }
104
105
    /**
106
     *
107
     * Connects to the LDAP server and sets options.
108
     *
109
     * @return resource The LDAP connection.
110
     *
111
     * @throws Exception\ConnectionFailed when the connection fails.
112
     *
113
     */
114 3
    protected function connect()
115
    {
116 3
        $conn = $this->phpfunc->ldap_connect($this->server);
0 ignored issues
show
Documentation Bug introduced by
The method ldap_connect does not exist on object<Aura\Auth\Phpfunc>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
117 3
        if (! $conn) {
118 1
            throw new Exception\ConnectionFailed($this->server);
119
        }
120
121 2
        foreach ($this->options as $opt => $val) {
122 2
            $this->phpfunc->ldap_set_option($conn, $opt, $val);
0 ignored issues
show
Documentation Bug introduced by
The method ldap_set_option does not exist on object<Aura\Auth\Phpfunc>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
123 2
        }
124
125 2
        return $conn;
126
    }
127
128
    /**
129
     *
130
     * Binds to the LDAP server with username and password.
131
     *
132
     * @param resource $conn The LDAP connection.
133
     *
134
     * @param string $username The input username.
135
     *
136
     * @param string $password The input password.
137
     *
138
     * @throws Exception\BindFailed when the username/password fails.
139
     *
140
     */
141 2
    protected function bind($conn, $username, $password)
142
    {
143 2
        $username = $this->escape($username);
144 2
        $bind_rdn = sprintf($this->dnformat, $username);
145
146 2
        $bound = $this->phpfunc->ldap_bind($conn, $bind_rdn, $password);
0 ignored issues
show
Documentation Bug introduced by
The method ldap_bind does not exist on object<Aura\Auth\Phpfunc>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
147 2
        if (! $bound) {
148 1
            $error = $this->phpfunc->ldap_errno($conn)
0 ignored issues
show
Documentation Bug introduced by
The method ldap_errno does not exist on object<Aura\Auth\Phpfunc>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
149
                   . ': '
150 1
                   . $this->phpfunc->ldap_error($conn);
0 ignored issues
show
Documentation Bug introduced by
The method ldap_error does not exist on object<Aura\Auth\Phpfunc>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
151 1
            $this->phpfunc->ldap_unbind($conn);
0 ignored issues
show
Documentation Bug introduced by
The method ldap_unbind does not exist on object<Aura\Auth\Phpfunc>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
152 1
            throw new Exception\BindFailed($error);
153
        }
154
155 1
        $this->phpfunc->ldap_unbind($conn);
0 ignored issues
show
Documentation Bug introduced by
The method ldap_unbind does not exist on object<Aura\Auth\Phpfunc>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
156 1
    }
157
158
    /**
159
     *
160
     * Escapes input values for LDAP string.
161
     *
162
     * Per <http://projects.webappsec.org/w/page/13246947/LDAP%20Injection>
163
     * and <https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java>.
164
     *
165
     * @param string $str The string to be escaped.
166
     *
167
     * @return string The escaped string.
168
     *
169
     */
170 2
    protected function escape($str)
171
    {
172 2
        return strtr($str, array(
173 2
            '\\' => '\\\\',
174 2
            '&'  => '\\&',
175 2
            '!'  => '\\!',
176 2
            '|'  => '\\|',
177 2
            '='  => '\\=',
178 2
            '<'  => '\\<',
179 2
            '>'  => '\\>',
180 2
            ','  => '\\,',
181 2
            '+'  => '\\+',
182 2
            '-'  => '\\-',
183 2
            '"'  => '\\"',
184 2
            "'"  => "\\'",
185 2
            ';'  => '\\;',
186 2
        ));
187
    }
188
}
189