Completed
Push — devel ( d561a1...ec15d0 )
by Philippe
02:30
created

AuthorizeController::getUserClass()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
ccs 6
cts 6
cp 1
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
crap 2
1
<?php
2
/**
3
 * DefaultController.php
4
 *
5
 * PHP version 5.6+
6
 *
7
 * @author pgaultier
8
 * @copyright 2010-2016 Ibitux
9
 * @license http://www.ibitux.com/license license
10
 * @version XXX
11
 * @link http://www.ibitux.com
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-2016 Ibitux
32
 * @license http://www.ibitux.com/license license
33
 * @version XXX
34
 * @link http://www.ibitux.com
35
 * @package sweelix\oauth2\server\controllers
36
 * @since XXX
37
 */
38
class AuthorizeController extends Controller
39
{
40
41
    /**
42
     * @inheritdoc
43
     */
44 9
    public function init()
45
    {
46 9
        $module = Module::getInstance();
47
48 9
        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 9
        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 9
        parent::init();
57 9
    }
58
59
    /**
60
     * @inheritdoc
61
     */
62 9
    public function behaviors()
63
    {
64 9
        $behaviors = parent::behaviors();
65 9
        $behaviors['access'] = [
66 9
            'class' => AccessControl::className(),
67 9
            'only' => ['authorize'],
68
            'rules' => [
69
                [
70 9
                    'allow' => true,
71 9
                    'actions' => ['authorize'],
72 9
                    'roles' => ['@'],
73 9
                ],
74 9
            ],
75
        ];
76 9
        return $behaviors;
77
    }
78
79
    /**
80
     * Send back an oauth token
81
     * @return Response
82
     * @since XXX
83
     */
84 8
    public function actionIndex()
85
    {
86 8
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
87 8
        $oauthServer = Yii::createObject('OAuth2\Server');
88
        /* @var \Oauth2\Server $oauthServer */
89 8
        $status = false;
90 8
        $oauthRequest = OAuth2Request::createFromGlobals();
91 8
        $oauthResponse = new OAuth2Response();
92 8
        $grantType = Yii::$app->request->getQueryParam('response_type');
93
        switch ($grantType) {
94
            // Authorization Code
95 8
            case 'code':
96 4
                if (Module::getInstance()->allowAuthorizationCode === true) {
97 3
                    $oauthGrantType = Yii::createObject('OAuth2\GrantType\AuthorizationCode');
98
                    /* @var \OAuth2\GrantType\AuthorizationCode $oauthGrantType */
99 3
                    $oauthServer->addGrantType($oauthGrantType);
100 3
                    $status = $oauthServer->validateAuthorizeRequest($oauthRequest, $oauthResponse);
101 3
                    $error = $oauthResponse->getParameters();
102 3
                    if (($status === false) && (empty($error) === false)) {
103 1
                        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 1
                    }
106 3
                } 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 4
                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 8
        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 4
            $response = $this->redirect(['error']);
135
        }
136 8
        return $response;
137
    }
138
139
    /**
140
     * Display login page
141
     * @return Response|string
142
     * @since XXX
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 XXX
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
        }
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();
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...
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 XXX
279
     */
280 5
    public function actionError()
281
    {
282 5
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
283 5
        $errorData = Yii::$app->session->getFlash('error');
284 5
        return $this->render('error', [
285 5
            'type' => (isset($errorData['error']) ? $errorData['error'] : null),
286 5
            'description' => (isset($errorData['error_description']) ? $errorData['error_description'] : null),
287 5
        ]);
288
    }
289
290
    /**
291
     * @var string
292
     */
293
    private $userClass;
294
295
    /**
296
     * @return string classname for selected interface
297
     * @since XXX
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