Completed
Push — devel ( 8e7291...5a91d2 )
by Philippe
06:50 queued 03:54
created

AuthorizeController   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 273
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 9

Test Coverage

Coverage 84.15%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 37
c 5
b 0
f 0
lcom 2
cbo 9
dl 0
loc 273
ccs 138
cts 164
cp 0.8415
rs 8.6

7 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 14 3
A behaviors() 0 16 1
A actionError() 0 9 3
C actionIndex() 0 54 11
B actionLogin() 0 41 6
A getUserClass() 0 8 2
C actionAuthorize() 0 83 11
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.1.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.1.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
    /**
42
     * @inheritdoc
43
     */
44 10
    public function init()
45
    {
46 10
        $module = Module::getInstance();
47
48 10
        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...
49
            $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...
50
        }
51
52 10
        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...
53
            $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...
54
        }
55
56 10
        parent::init();
57 10
    }
58
59
    /**
60
     * @inheritdoc
61
     */
62 10
    public function behaviors()
63
    {
64 10
        $behaviors = parent::behaviors();
65 10
        $behaviors['access'] = [
66 10
            'class' => AccessControl::className(),
67 10
            'only' => ['authorize'],
68
            'rules' => [
69
                [
70 10
                    'allow' => true,
71 10
                    'actions' => ['authorize'],
72 10
                    'roles' => ['@'],
73 10
                ],
74 10
            ],
75
        ];
76 10
        return $behaviors;
77
    }
78
79
    /**
80
     * Send back an oauth token
81
     * @return Response
82
     * @since 1.0.0
83
     */
84 9
    public function actionIndex()
85
    {
86 9
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
87 9
        $oauthServer = Yii::createObject('OAuth2\Server');
88
        /* @var \Oauth2\Server $oauthServer */
89 9
        $status = false;
90 9
        $oauthRequest = OAuth2Request::createFromGlobals();
91 9
        $oauthResponse = new OAuth2Response();
92 9
        $grantType = Yii::$app->request->getQueryParam('response_type');
93
        switch ($grantType) {
94
            // Authorization Code
95 9
            case 'code':
96 5
                if (Module::getInstance()->allowAuthorizationCode === true) {
97 4
                    $oauthGrantType = Yii::createObject('OAuth2\GrantType\AuthorizationCode');
98
                    /* @var \OAuth2\GrantType\AuthorizationCode $oauthGrantType */
99 4
                    $oauthServer->addGrantType($oauthGrantType);
100 4
                    $status = $oauthServer->validateAuthorizeRequest($oauthRequest, $oauthResponse);
101 4
                    $error = $oauthResponse->getParameters();
102 4
                    if (($status === false) && (empty($error) === false)) {
103 2
                        Yii::$app->session->setFlash('error', $error, false);
104
                        // return $this->redirect(['error']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
105 2
                    }
106 4
                } else {
107 1
                    $status = false;
108 1
                    Yii::$app->session->setFlash('error', ['error' => 'invalid_grant', 'error_description' => 'authorization code grant is not supported'], false);
109
                }
110 5
                break;
111
            // Implicit
112 4
            case 'token':
113 4
                $status = $oauthServer->validateAuthorizeRequest($oauthRequest, $oauthResponse);
114 4
                $error = $oauthResponse->getParameters();
115 4
                if (($status === false) && (empty($error) === false)) {
116 2
                    Yii::$app->session->setFlash('error', $error, false);
117
                    // return $this->redirect(['error']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
118 2
                }
119 4
                break;
120
        }
121
122 9
        if ($status === true) {
123 4
            Yii::$app->session->set('oauthServer', $oauthServer);
124 4
            if (isset($oauthRequest) === true) {
125 4
                Yii::$app->session->set('oauthRequest', $oauthRequest);
126 4
            }
127 4
            if (Yii::$app->user->isGuest === true) {
128 4
                $response = $this->redirect(['login']);
129 4
            } else {
130 1
                $response = $this->redirect(['authorize']);
131
            }
132 4
        } else {
133
            //TODO: check if we should redirect to specific url with an error
134 5
            $response = $this->redirect(['error']);
135
        }
136 9
        return $response;
137
    }
138
139
    /**
140
     * Display login page
141
     * @return Response|string
142
     * @since 1.0.0
143
     */
144 5
    public function actionLogin()
145
    {
146 5
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
147
148 5
        $oauthServer = Yii::$app->session->get('oauthServer');
149
        /* @var \Oauth2\Server $oauthServer */
150 5
        if ($oauthServer === null) {
151 1
            Yii::$app->session->setFlash('error', [
152 1
                'error' => 'request_invalid',
153 1
                'error_description' => 'The request was not performed as expected.',
154 1
            ], false);
155 1
            return $this->redirect(['error']);
156
        }
157
158 4
        $userForm = Yii::createObject('sweelix\oauth2\server\forms\User');
159 4
        $response = null;
160
        /* @var \sweelix\oauth2\server\forms\User $userForm */
161 4
        if (Yii::$app->request->isPost === true) {
162
            //TODO: handle case when user decline the grants
163 4
            $userForm->load(Yii::$app->request->bodyParams);
164 4
            if ($userForm->validate() === true) {
165 4
                $userClass = $this->getUserClass();
166 4
                $realUser = $userClass::findByUsernameAndPassword($userForm->username, $userForm->password);
167
                /* @var \sweelix\oauth2\server\interfaces\UserModelInterface $realUser */
168 4
                if ($realUser !== null) {
169 4
                    Yii::$app->user->login($realUser, Module::getInstance()->loginDuration);
170 4
                    $response = $this->redirect(['authorize']);
171 4
                } else {
172 2
                    $userForm->addError('username');
173
                }
174 4
            }
175 4
        }
176 4
        if ($response === null) {
177
            // force empty password
178 4
            $userForm->password = '';
179 4
            $response = $this->render('login', [
180 4
                'user' => $userForm,
181 4
            ]);
182 4
        }
183 4
        return $response;
184
    }
185
186
    /**
187
     * Display authorize page
188
     * @return string|Response
189
     * @since 1.0.0
190
     */
191 4
    public function actionAuthorize()
192
    {
193 4
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
194 4
        $oauthServer = Yii::$app->session->get('oauthServer');
195
        /* @var \Oauth2\Server $oauthServer */
196 4
        if ($oauthServer === null) {
197
            Yii::$app->session->setFlash('error', [
198
                'error' => 'request_invalid',
199
                'error_description' => 'The request was not performed as expected.',
200
            ], false);
201
            return $this->redirect(['error']);
202 1
        }
203 4
        $oauthController = $oauthServer->getAuthorizeController();
204 4
        $client = Client::findOne($oauthController->getClientId());
205
206 4
        if ($client->hasUser(Yii::$app->user->id) === true) {
207
            // already logged
208 1
            $oauthRequest = Yii::$app->session->get('oauthRequest');
209 1
            $oauthResponse = new OAuth2Response();
210 1
            $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, true, Yii::$app->user->id);
211
            /* @var OAuth2Response $oauthResponse */
212 1
            Yii::$app->session->remove('oauthServer');
213 1
            Yii::$app->session->remove('oauthRequest');
214 1
            $error = $oauthResponse->getParameters();
215 1
            if (empty($error) === false) {
216
                Yii::$app->session->setFlash('error', $error, false);
217
                return $this->redirect(['error']);
218
            } else {
219 1
                return $this->redirect($oauthResponse->getHttpHeader('Location'));
220
            }
221
        } else {
222
            // perform regular authorization
223 4
            $additionalScopes = $oauthController->getScope();
224 4
            $requestedScopes = [];
225 4
            if (empty($additionalScopes) === false) {
226
                $additionalScopes = explode(' ', $additionalScopes);
227
                foreach($additionalScopes as $scope) {
228
                    $dbScope = Scope::findOne($scope);
229
                    if ($dbScope !== null) {
230
                        $requestedScopes[] = $dbScope;
231
                    } else {
232
                        Yii::$app->session->setFlash('error', [
233
                            'error' => 'invalid_scope',
234
                            'error_description' => 'Scope '.$scope.' does not exist.',
235
                        ], false);
236
                        return $this->redirect(['error']);
237
                    }
238
                }
239
            }
240 4
            if (Yii::$app->request->isPost === true) {
241 4
                $accept = Yii::$app->request->getBodyParam('accept', null);
242 4
                $oauthRequest = Yii::$app->session->get('oauthRequest');
243 4
                $oauthResponse = new OAuth2Response();
244
                /* @var OAuth2Response $oauthResponse */
245
246 4
                if ($accept !== null) {
247 2
                    $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, true, Yii::$app->user->id);
248 2
                    $client->addUser(Yii::$app->user->id);
249
                    // authorize
250 2
                } else {
251 2
                    $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, false, Yii::$app->user->id);
252 2
                    $client->removeUser(Yii::$app->user->id);
253
                    // decline
254
                }
255
256 4
                Yii::$app->session->remove('oauthServer');
257 4
                Yii::$app->session->remove('oauthRequest');
258 4
                $error = $oauthResponse->getParameters();
259 4
                $redirect = $oauthResponse->getHttpHeader('Location');
260 4
                if ((empty($error) === false) && ($redirect === null)) {
261
                    Yii::$app->session->setFlash('error', $error, false);
262
                    return $this->redirect(['error']);
263
                } else {
264 4
                    return $this->redirect($redirect);
265
                }
266
            }
267
        }
268
269 4
        return $this->render('authorize', [
270 4
            'client' => $client,
271 4
            'requestedScopes' => $requestedScopes,
272 4
        ]);
273
    }
274
275
    /**
276
     * Display an error page
277
     * @return Response|string
278
     * @since 1.0.0
279
     */
280 6
    public function actionError()
281
    {
282 6
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
283 6
        $errorData = Yii::$app->session->getFlash('error');
284 6
        return $this->render('error', [
285 6
            'type' => (isset($errorData['error']) ? $errorData['error'] : null),
286 6
            'description' => (isset($errorData['error_description']) ? $errorData['error_description'] : null),
287 6
        ]);
288
    }
289
290
    /**
291
     * @var string
292
     */
293
    private $userClass;
294
295
    /**
296
     * @return string classname for selected interface
297
     * @since 1.0.0
298
     */
299 4
    public function getUserClass()
300
    {
301 4
        if ($this->userClass === null) {
302 4
            $scope = Yii::createObject('sweelix\oauth2\server\interfaces\UserModelInterface');
303 4
            $this->userClass = get_class($scope);
304 4
        }
305 4
        return $this->userClass;
306
    }
307
308
309
310
}
311