Completed
Push — devel ( b03b2f...7508db )
by Philippe
05:13
created

AuthorizeController   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 31
lcom 1
cbo 9
dl 0
loc 252
c 2
b 0
f 0
ccs 0
cts 185
cp 0
rs 9.8

6 Methods

Rating   Name   Duplication   Size   Complexity  
A behaviors() 0 16 1
C actionIndex() 0 49 8
B actionLogin() 0 41 6
C actionAuthorize() 0 85 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-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
    public function behaviors()
45
    {
46
        $behaviors = parent::behaviors();
47
        $behaviors['access'] = [
48
            'class' => AccessControl::className(),
49
            'only' => ['authorize'],
50
            'rules' => [
51
                [
52
                    'allow' => true,
53
                    'actions' => ['authorize'],
54
                    'roles' => ['@'],
55
                ],
56
            ],
57
        ];
58
        return $behaviors;
59
    }
60
61
    /**
62
     * Send back an oauth token
63
     * @return Response
64
     * @since XXX
65
     */
66
    public function actionIndex()
67
    {
68
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
69
        $oauthServer = Yii::createObject('OAuth2\Server');
70
        /* @var \Oauth2\Server $oauthServer */
71
        $status = false;
72
        $oauthRequest = OAuth2Request::createFromGlobals();
73
        $oauthResponse = new OAuth2Response();
74
        $grantType = Yii::$app->request->getQueryParam('response_type');
75
        switch ($grantType) {
76
            // Authorization Code
77
            case 'code':
78
                if (Module::getInstance()->allowAuthorizationCode === true) {
79
                    $oauthGrantType = Yii::createObject('OAuth2\GrantType\AuthorizationCode');
80
                    /* @var \OAuth2\GrantType\AuthorizationCode $oauthGrantType */
81
                    $oauthServer->addGrantType($oauthGrantType);
82
                    $status = $oauthServer->validateAuthorizeRequest($oauthRequest, $oauthResponse);
83
                    $error = $oauthResponse->getParameters();
84
                    if (empty($error) === false) {
85
                        Yii::$app->session->setFlash('error', $error, false);
86
                        return $this->redirect(['error']);
87
                    }
88
                } else {
89
                    $status = false;
90
                    Yii::$app->session->setFlash('error', ['error' => 'invalid_grant', 'error_description' => 'authorization code grant is not supported'], false);
91
                }
92
                break;
93
            // Implicit
94
            case 'token':
95
                $status = $oauthServer->validateAuthorizeRequest($oauthRequest, $oauthResponse);
96
                break;
97
        }
98
99
        if ($status === true) {
100
            Yii::$app->session->set('oauthServer', $oauthServer);
101
            if (isset($oauthRequest) === true) {
102
                Yii::$app->session->set('oauthRequest', $oauthRequest);
103
            }
104
            if (Yii::$app->user->isGuest === true) {
105
                $response = $this->redirect(['login']);
106
            } else {
107
                $response = $this->redirect(['authorize']);
108
            }
109
        } else {
110
            //TODO: check if we should redirect to specific url with an error
111
            $response = $this->redirect(['error']);
112
        }
113
        return $response;
114
    }
115
116
    /**
117
     * Display login page
118
     * @return Response|string
119
     * @since XXX
120
     */
121
    public function actionLogin()
122
    {
123
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
124
125
        $oauthServer = Yii::$app->session->get('oauthServer');
126
        /* @var \Oauth2\Server $oauthServer */
127
        if ($oauthServer === null) {
128
            Yii::$app->session->setFlash('error', [
129
                'error' => 'request_invalid',
130
                'error_description' => 'The request was not performed as expected.',
131
            ], false);
132
            return $this->redirect(['error']);
133
        }
134
135
        $userForm = Yii::createObject('sweelix\oauth2\server\forms\User');
136
        $response = null;
137
        /* @var \sweelix\oauth2\server\forms\User $userForm */
138
        if (Yii::$app->request->isPost === true) {
139
            //TODO: handle case when user decline the grants
140
            $userForm->load(Yii::$app->request->bodyParams);
141
            if ($userForm->validate() === true) {
142
                $userClass = $this->getUserClass();
143
                $realUser = $userClass::findByUsernameAndPassword($userForm->username, $userForm->password);
144
                /* @var \sweelix\oauth2\server\interfaces\UserModelInterface $realUser */
145
                if ($realUser !== null) {
146
                    Yii::$app->user->login($realUser, Module::getInstance()->loginDuration);
147
                    $response = $this->redirect(['authorize']);
148
                } else {
149
                    $userForm->addError('username');
150
                }
151
            }
152
        }
153
        if ($response === null) {
154
            // force empty password
155
            $userForm->password = '';
156
            $response = $this->render('login', [
157
                'user' => $userForm,
158
            ]);
159
        }
160
        return $response;
161
    }
162
163
    /**
164
     * Display authorize page
165
     * @return string|Response
166
     * @since XXX
167
     */
168
    public function actionAuthorize()
169
    {
170
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
171
        $oauthServer = Yii::$app->session->get('oauthServer');
172
        /* @var \Oauth2\Server $oauthServer */
173
        if ($oauthServer === null) {
174
            Yii::$app->session->setFlash('error', [
175
                'error' => 'request_invalid',
176
                'error_description' => 'The request was not performed as expected.',
177
            ], false);
178
            return $this->redirect(['error']);
179
        }
180
        $oauthController = $oauthServer->getAuthorizeController();
181
        $client = Client::findOne($oauthController->getClientId());
182
183
        if ($client->hasUser(Yii::$app->user->id) === true) {
184
            // already logged
185
            $oauthRequest = Yii::$app->session->get('oauthRequest');
186
            $oauthResponse = new OAuth2Response();
187
            $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, true, Yii::$app->user->id);
188
            /* @var OAuth2Response $oauthResponse */
189
            Yii::$app->session->remove('oauthServer');
190
            Yii::$app->session->remove('oauthRequest');
191
            $error = $oauthResponse->getParameters();
192
            if (empty($error) === false) {
193
                Yii::$app->session->setFlash('error', $error, false);
194
                return $this->redirect(['error']);
195
            } else {
196
                return $this->redirect($oauthResponse->getHttpHeader('Location'));
197
            }
198
        } else {
199
            // perform regular authorization
200
            $additionalScopes = $oauthController->getScope();
201
            $requestedScopes = [];
202
            if (empty($additionalScopes) === false) {
203
                $additionalScopes = explode(' ', $additionalScopes);
204
                foreach($additionalScopes as $scope) {
205
                    $dbScope = Scope::findOne($scope);
206
                    if ($dbScope !== null) {
207
                        $requestedScopes[] = [
208
                            'id' => $dbScope->id,
0 ignored issues
show
Bug introduced by
Accessing id on the interface sweelix\oauth2\server\in...ces\ScopeModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
209
                            'description' => $dbScope->definition,
0 ignored issues
show
Bug introduced by
Accessing definition on the interface sweelix\oauth2\server\in...ces\ScopeModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
210
                        ];
211
                    } else {
212
                        $requestedScopes[] = [
213
                            'id' => $scope,
214
                            'description' => null,
215
                        ];
216
                    }
217
                }
218
            }
219
            if (Yii::$app->request->isPost === true) {
220
                $accept = Yii::$app->request->getBodyParam('accept', null);
221
                $oauthRequest = Yii::$app->session->get('oauthRequest');
222
                $oauthResponse = new OAuth2Response();
223
                /* @var OAuth2Response $oauthResponse */
224
225
                if ($accept !== null) {
226
                    $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, true, Yii::$app->user->id);
227
                    $client->addUser(Yii::$app->user->id);
228
                    // authorize
229
                } else {
230
                    $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, false, Yii::$app->user->id);
231
                    $client->removeUser(Yii::$app->user->id);
232
                    // decline
233
                }
234
235
                Yii::$app->session->remove('oauthServer');
236
                Yii::$app->session->remove('oauthRequest');
237
                $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...
238
                $redirect = $oauthResponse->getHttpHeader('Location');
239
                if ((empty($error) === false) && ($redirect === null)) {
240
                    Yii::$app->session->setFlash('error', $error, false);
241
                    return $this->redirect(['error']);
242
                } else {
243
                    return $this->redirect($redirect);
244
                }
245
            }
246
        }
247
248
        return $this->render('authorize', [
249
            'client' => $client,
250
            'requestedScopes' => $requestedScopes,
251
        ]);
252
    }
253
254
    /**
255
     * Display an error page
256
     * @return Response|string
257
     * @since XXX
258
     */
259
    public function actionError()
260
    {
261
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
262
        $errorData = Yii::$app->session->getFlash('error');
263
        return $this->render('error', [
264
            'type' => (isset($errorData['error']) ? $errorData['error'] : null),
265
            'description' => (isset($errorData['error_description']) ? $errorData['error_description'] : null),
266
        ]);
267
    }
268
269
    /**
270
     * @var string
271
     */
272
    private $userClass;
273
274
    /**
275
     * @return string classname for selected interface
276
     * @since XXX
277
     */
278
    public function getUserClass()
279
    {
280
        if ($this->userClass === null) {
281
            $scope = Yii::createObject('sweelix\oauth2\server\interfaces\UserModelInterface');
282
            $this->userClass = get_class($scope);
283
        }
284
        return $this->userClass;
285
    }
286
287
288
289
}
290