AuthorizeController   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 273
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 8

Importance

Changes 0
Metric Value
wmc 37
lcom 2
cbo 8
dl 0
loc 273
c 0
b 0
f 0
rs 9.44

7 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 14 3
A behaviors() 0 16 1
C actionIndex() 0 54 11
B actionLogin() 0 41 6
C actionAuthorize() 0 83 11
A actionError() 0 9 3
A getUserClass() 0 8 2
1
<?php
2
/**
3
 * DefaultController.php
4
 *
5
 * PHP version 5.6+
6
 *
7
 * @author pgaultier
8
 * @copyright 2010-2017 Philippe Gaultier
9
 * @license http://www.sweelix.net/license license
10
 * @version 1.2.0
11
 * @link http://www.sweelix.net
12
 * @package sweelix\oauth2\server\controllers
13
 */
14
15
namespace sweelix\oauth2\server\controllers;
16
17
use OAuth2\Request as OAuth2Request;
18
use OAuth2\Response as OAuth2Response;
19
use sweelix\oauth2\server\models\Client;
20
use sweelix\oauth2\server\models\Scope;
21
use sweelix\oauth2\server\Module;
22
use yii\filters\AccessControl;
23
use yii\web\Controller;
24
use yii\web\Response;
25
use Yii;
26
27
/**
28
 * Oauth2 main controller
29
 *
30
 * @author pgaultier
31
 * @copyright 2010-2017 Philippe Gaultier
32
 * @license http://www.sweelix.net/license license
33
 * @version 1.2.0
34
 * @link http://www.sweelix.net
35
 * @package sweelix\oauth2\server\controllers
36
 * @since 1.0.0
37
 */
38
class AuthorizeController extends Controller
39
{
40
    /**
41
     * @inheritdoc
42
     */
43
    public function init()
44
    {
45
        $module = Module::getInstance();
46
47
        if ($module->overrideLayout !== null) {
0 ignored issues
show
Bug introduced by
The property overrideLayout does not seem to exist. Did you mean layout?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
48
            $this->layout = $module->overrideLayout;
0 ignored issues
show
Bug introduced by
The property overrideLayout does not seem to exist. Did you mean layout?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
49
        }
50
51
        if ($module->overrideViewPath !== null) {
0 ignored issues
show
Bug introduced by
The property overrideViewPath does not seem to exist. Did you mean viewPath?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
52
            $this->setViewPath($module->overrideViewPath);
0 ignored issues
show
Bug introduced by
The property overrideViewPath does not seem to exist. Did you mean viewPath?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
53
        }
54
55
        parent::init();
56
    }
57
58
    /**
59
     * @inheritdoc
60
     */
61
    public function behaviors()
62
    {
63
        $behaviors = parent::behaviors();
64
        $behaviors['access'] = [
65
            'class' => AccessControl::class,
66
            'only' => ['authorize'],
67
            'rules' => [
68
                [
69
                    'allow' => true,
70
                    'actions' => ['authorize'],
71
                    'roles' => ['@'],
72
                ],
73
            ],
74
        ];
75
        return $behaviors;
76
    }
77
78
    /**
79
     * Send back an oauth token
80
     * @return Response
81
     * @throws \yii\base\InvalidConfigException
82
     * @since 1.0.0
83
     */
84
    public function actionIndex()
85
    {
86
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
87
        $oauthServer = Yii::createObject('OAuth2\Server');
88
        /* @var \Oauth2\Server $oauthServer */
89
        $status = false;
90
        $oauthRequest = OAuth2Request::createFromGlobals();
91
        $oauthResponse = new OAuth2Response();
92
        $grantType = Yii::$app->request->getQueryParam('response_type');
93
        switch ($grantType) {
94
            // Authorization Code
95
            case 'code':
96
                if (Module::getInstance()->allowAuthorizationCode === true) {
97
                    $oauthGrantType = Yii::createObject('OAuth2\GrantType\AuthorizationCode');
98
                    /* @var \OAuth2\GrantType\AuthorizationCode $oauthGrantType */
99
                    $oauthServer->addGrantType($oauthGrantType);
100
                    $status = $oauthServer->validateAuthorizeRequest($oauthRequest, $oauthResponse);
101
                    $error = $oauthResponse->getParameters();
102
                    if (($status === false) && (empty($error) === false)) {
103
                        Yii::$app->session->setFlash('error', $error, false);
104
                        // return $this->redirect(['error']);
105
                    }
106
                } else {
107
                    $status = false;
108
                    Yii::$app->session->setFlash('error', ['error' => 'invalid_grant', 'error_description' => 'authorization code grant is not supported'], false);
109
                }
110
                break;
111
            // Implicit
112
            case 'token':
113
                $status = $oauthServer->validateAuthorizeRequest($oauthRequest, $oauthResponse);
114
                $error = $oauthResponse->getParameters();
115
                if (($status === false) && (empty($error) === false)) {
116
                    Yii::$app->session->setFlash('error', $error, false);
117
                    // return $this->redirect(['error']);
118
                }
119
                break;
120
        }
121
122
        if ($status === true) {
123
            Yii::$app->session->set('oauthServer', $oauthServer);
124
            if (isset($oauthRequest) === true) {
125
                Yii::$app->session->set('oauthRequest', $oauthRequest);
126
            }
127
            if (Yii::$app->user->isGuest === true) {
128
                $response = $this->redirect(['login']);
129
            } else {
130
                $response = $this->redirect(['authorize']);
131
            }
132
        } else {
133
            //TODO: check if we should redirect to specific url with an error
134
            $response = $this->redirect(['error']);
135
        }
136
        return $response;
137
    }
138
139
    /**
140
     * Display login page
141
     * @return Response|string
142
     * @throws \yii\base\InvalidConfigException
143
     * @since 1.0.0
144
     */
145
    public function actionLogin()
146
    {
147
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
148
149
        $oauthServer = Yii::$app->session->get('oauthServer');
150
        /* @var \Oauth2\Server $oauthServer */
151
        if ($oauthServer === null) {
152
            Yii::$app->session->setFlash('error', [
153
                'error' => 'request_invalid',
154
                'error_description' => 'The request was not performed as expected.',
155
            ], false);
156
            return $this->redirect(['error']);
157
        }
158
159
        $userForm = Yii::createObject('sweelix\oauth2\server\forms\User');
160
        $response = null;
161
        /* @var \sweelix\oauth2\server\forms\User $userForm */
162
        if (Yii::$app->request->isPost === true) {
163
            //TODO: handle case when user decline the grants
164
            $userForm->load(Yii::$app->request->bodyParams);
165
            if ($userForm->validate() === true) {
166
                $userClass = $this->getUserClass();
167
                $realUser = $userClass::findByUsernameAndPassword($userForm->username, $userForm->password);
168
                /* @var \sweelix\oauth2\server\interfaces\UserModelInterface $realUser */
169
                if ($realUser !== null) {
170
                    Yii::$app->user->login($realUser, Module::getInstance()->loginDuration);
171
                    $response = $this->redirect(['authorize']);
172
                } else {
173
                    $userForm->addError('username');
174
                }
175
            }
176
        }
177
        if ($response === null) {
178
            // force empty password
179
            $userForm->password = '';
180
            $response = $this->render('login', [
181
                'user' => $userForm,
182
            ]);
183
        }
184
        return $response;
185
    }
186
187
    /**
188
     * Display authorize page
189
     * @return string|Response
190
     * @throws \yii\base\UnknownClassException
191
     * @since 1.0.0
192
     */
193
    public function actionAuthorize()
194
    {
195
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
196
        $oauthServer = Yii::$app->session->get('oauthServer');
197
        /* @var \Oauth2\Server $oauthServer */
198
        if ($oauthServer === null) {
199
            Yii::$app->session->setFlash('error', [
200
                'error' => 'request_invalid',
201
                'error_description' => 'The request was not performed as expected.',
202
            ], false);
203
            return $this->redirect(['error']);
204
        }
205
        $oauthController = $oauthServer->getAuthorizeController();
206
        $client = Client::findOne($oauthController->getClientId());
207
208
        if ($client->hasUser(Yii::$app->user->id) === true) {
209
            // already logged
210
            $oauthRequest = Yii::$app->session->get('oauthRequest');
211
            $oauthResponse = new OAuth2Response();
212
            $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, true, Yii::$app->user->id);
213
            /* @var OAuth2Response $oauthResponse */
214
            Yii::$app->session->remove('oauthServer');
215
            Yii::$app->session->remove('oauthRequest');
216
            $error = $oauthResponse->getParameters();
217
            if (empty($error) === false) {
218
                Yii::$app->session->setFlash('error', $error, false);
219
                return $this->redirect(['error']);
220
            } else {
221
                return $this->redirect($oauthResponse->getHttpHeader('Location'));
222
            }
223
        } else {
224
            // perform regular authorization
225
            $additionalScopes = $oauthController->getScope();
226
            $requestedScopes = [];
227
            if (empty($additionalScopes) === false) {
228
                $additionalScopes = explode(' ', $additionalScopes);
229
                foreach ($additionalScopes as $scope) {
230
                    $dbScope = Scope::findOne($scope);
231
                    if ($dbScope !== null) {
232
                        $requestedScopes[] = $dbScope;
233
                    } else {
234
                        Yii::$app->session->setFlash('error', [
235
                            'error' => 'invalid_scope',
236
                            'error_description' => 'Scope ' . $scope . ' does not exist.',
237
                        ], false);
238
                        return $this->redirect(['error']);
239
                    }
240
                }
241
            }
242
            if (Yii::$app->request->isPost === true) {
243
                $accept = Yii::$app->request->getBodyParam('accept', null);
244
                $oauthRequest = Yii::$app->session->get('oauthRequest');
245
                $oauthResponse = new OAuth2Response();
246
                /* @var OAuth2Response $oauthResponse */
247
248
                if ($accept !== null) {
249
                    $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, true, Yii::$app->user->id);
250
                    $client->addUser(Yii::$app->user->id);
251
                    // authorize
252
                } else {
253
                    $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, false, Yii::$app->user->id);
254
                    $client->removeUser(Yii::$app->user->id);
255
                    // decline
256
                }
257
258
                Yii::$app->session->remove('oauthServer');
259
                Yii::$app->session->remove('oauthRequest');
260
                $error = $oauthResponse->getParameters();
0 ignored issues
show
Bug introduced by
The method getParameters() does not exist on OAuth2\ResponseInterface. Did you maybe mean getParameter()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
261
                $redirect = $oauthResponse->getHttpHeader('Location');
262
                if ((empty($error) === false) && ($redirect === null)) {
263
                    Yii::$app->session->setFlash('error', $error, false);
264
                    return $this->redirect(['error']);
265
                } else {
266
                    return $this->redirect($redirect);
267
                }
268
            }
269
        }
270
271
        return $this->render('authorize', [
272
            'client' => $client,
273
            'requestedScopes' => $requestedScopes,
274
        ]);
275
    }
276
277
    /**
278
     * Display an error page
279
     * @return Response|string
280
     * @since 1.0.0
281
     */
282
    public function actionError()
283
    {
284
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
285
        $errorData = Yii::$app->session->getFlash('error');
286
        return $this->render('error', [
287
            'type' => (isset($errorData['error']) ? $errorData['error'] : null),
288
            'description' => (isset($errorData['error_description']) ? $errorData['error_description'] : null),
289
        ]);
290
    }
291
292
    /**
293
     * @var string
294
     */
295
    private $userClass;
296
297
    /**
298
     * @return string classname for selected interface
299
     * @throws \yii\base\InvalidConfigException
300
     * @since 1.0.0
301
     */
302
    public function getUserClass()
303
    {
304
        if ($this->userClass === null) {
305
            $scope = Yii::createObject('sweelix\oauth2\server\interfaces\UserModelInterface');
306
            $this->userClass = get_class($scope);
307
        }
308
        return $this->userClass;
309
    }
310
}
311