Completed
Push — master ( f5c98f...0b2e79 )
by Dmitry
12:04
created

HttpBasicAuth::getCredentialsFromRequest()   C

Complexity

Conditions 8
Paths 7

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 8.0189

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 14
cts 15
cp 0.9333
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 15
nc 7
nop 1
crap 8.0189
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\filters\auth;
9
10
use yii\web\Request;
11
12
/**
13
 * HttpBasicAuth is an action filter that supports the HTTP Basic authentication method.
14
 *
15
 * You may use HttpBasicAuth by attaching it as a behavior to a controller or module, like the following:
16
 *
17
 * ```php
18
 * public function behaviors()
19
 * {
20
 *     return [
21
 *         'basicAuth' => [
22
 *             'class' => \yii\filters\auth\HttpBasicAuth::className(),
23
 *         ],
24
 *     ];
25
 * }
26
 * ```
27
 *
28
 * The default implementation of HttpBasicAuth uses the [[\yii\web\User::loginByAccessToken()|loginByAccessToken()]]
29
 * method of the `user` application component and only passes the user name. This implementation is used
30
 * for authenticating API clients.
31
 *
32
 * If you want to authenticate users using username and password, you should provide the [[auth]] function for example like the following:
33
 *
34
 * ```php
35
 * public function behaviors()
36
 * {
37
 *     return [
38
 *         'basicAuth' => [
39
 *             'class' => \yii\filters\auth\HttpBasicAuth::className(),
40
 *             'auth' => function ($username, $password) {
41
 *                 $user = User::find()->where(['username' => $username])->one();
42
 *                 if ($user->verifyPassword($password)) {
43
 *                     return $user;
44
 *                 }
45
 *                 return null;
46
 *             },
47
 *         ],
48
 *     ];
49
 * }
50
 * ```
51
 *
52
 * @author Qiang Xue <[email protected]>
53
 * @since 2.0
54
 */
55
class HttpBasicAuth extends AuthMethod
56
{
57
    /**
58
     * @var string the HTTP authentication realm
59
     */
60
    public $realm = 'api';
61
    /**
62
     * @var callable a PHP callable that will authenticate the user with the HTTP basic auth information.
63
     * The callable receives a username and a password as its parameters. It should return an identity object
64
     * that matches the username and password. Null should be returned if there is no such identity.
65
     *
66
     * The following code is a typical implementation of this callable:
67
     *
68
     * ```php
69
     * function ($username, $password) {
70
     *     return \app\models\User::findOne([
71
     *         'username' => $username,
72
     *         'password' => $password,
73
     *     ]);
74
     * }
75
     * ```
76
     *
77
     * If this property is not set, the username information will be considered as an access token
78
     * while the password information will be ignored. The [[\yii\web\User::loginByAccessToken()]]
79
     * method will be called to authenticate and login the user.
80
     */
81
    public $auth;
82
83
84
    /**
85
     * @inheritdoc
86
     */
87 20
    public function authenticate($user, $request, $response)
88
    {
89 20
        list($username, $password) = $this->getCredentialsFromRequest($request);
90
91 20
        if ($this->auth) {
92 5
            if ($username !== null || $password !== null) {
93 5
                $identity = call_user_func($this->auth, $username, $password);
94 5
                if ($identity !== null) {
95 3
                    $user->switchIdentity($identity);
96
                } else {
97 2
                    $this->handleFailure($response);
98
                }
99
100 3
                return $identity;
101
            }
102 15
        } elseif ($username !== null) {
103 12
            $identity = $user->loginByAccessToken($username, get_class($this));
104 12
            if ($identity === null) {
105 3
                $this->handleFailure($response);
106
            }
107
108 9
            return $identity;
109
        }
110
111 3
        return null;
112
    }
113
114
    /**
115
     * Extract username and password from $request.
116
     *
117
     * @param Request $request
118
     * @since 2.0.13
119
     * @return array
120
     */
121 28
    protected function getCredentialsFromRequest($request)
122
    {
123 28
        $username = $request->getAuthUser();
124 28
        $password = $request->getAuthPassword();
125
126 28
        if ($username !== null || $password !== null) {
127 10
            return [$username, $password];
128
        }
129
130 18
        $headers = $request->getHeaders();
131 18
        $auth_token = $headers->get('HTTP_AUTHORIZATION') ?: $headers->get('REDIRECT_HTTP_AUTHORIZATION');
132 18
        if ($auth_token != null && strpos(strtolower($auth_token), 'basic') === 0) {
133 18
            $parts = array_map(function ($value) {
134 18
                return strlen($value) === 0 ? null : $value;
135 18
            }, explode(':', base64_decode(mb_substr($auth_token, 6)), 2));
136
137 18
            if (count($parts) < 2) {
138 2
                return [$parts[0], null];
139
            }
140
141 16
            return $parts;
142
        }
143
144
        return [null, null];
145
    }
146
147
    /**
148
     * @inheritdoc
149
     */
150 3
    public function challenge($response)
151
    {
152 3
        $response->getHeaders()->set('WWW-Authenticate', "Basic realm=\"{$this->realm}\"");
153 3
    }
154
}
155