Completed
Push — devel ( 7508db...540322 )
by Philippe
03:02
created

AuthorizeController::behaviors()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 16
ccs 11
cts 11
cp 1
rs 9.4285
cc 1
eloc 10
nc 1
nop 0
crap 1
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 behaviors()
45
    {
46 9
        $behaviors = parent::behaviors();
47 9
        $behaviors['access'] = [
48 9
            'class' => AccessControl::className(),
49 9
            'only' => ['authorize'],
50
            'rules' => [
51
                [
52 9
                    'allow' => true,
53 9
                    'actions' => ['authorize'],
54 9
                    'roles' => ['@'],
55 9
                ],
56 9
            ],
57
        ];
58 9
        return $behaviors;
59
    }
60
61
    /**
62
     * Send back an oauth token
63
     * @return Response
64
     * @since XXX
65
     */
66 8
    public function actionIndex()
67
    {
68 8
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
69 8
        $oauthServer = Yii::createObject('OAuth2\Server');
70
        /* @var \Oauth2\Server $oauthServer */
71 8
        $status = false;
72 8
        $oauthRequest = OAuth2Request::createFromGlobals();
73 8
        $oauthResponse = new OAuth2Response();
74 8
        $grantType = Yii::$app->request->getQueryParam('response_type');
75
        switch ($grantType) {
76
            // Authorization Code
77 8
            case 'code':
78 4
                if (Module::getInstance()->allowAuthorizationCode === true) {
79 3
                    $oauthGrantType = Yii::createObject('OAuth2\GrantType\AuthorizationCode');
80
                    /* @var \OAuth2\GrantType\AuthorizationCode $oauthGrantType */
81 3
                    $oauthServer->addGrantType($oauthGrantType);
82 3
                    $status = $oauthServer->validateAuthorizeRequest($oauthRequest, $oauthResponse);
83 3
                    $error = $oauthResponse->getParameters();
84 3
                    if (($status === false) && (empty($error) === false)) {
85 1
                        Yii::$app->session->setFlash('error', $error, false);
86
                        // 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...
87 1
                    }
88 3
                } else {
89 1
                    $status = false;
90 1
                    Yii::$app->session->setFlash('error', ['error' => 'invalid_grant', 'error_description' => 'authorization code grant is not supported'], false);
91
                }
92 4
                break;
93
            // Implicit
94 4
            case 'token':
95 4
                $status = $oauthServer->validateAuthorizeRequest($oauthRequest, $oauthResponse);
96 4
                $error = $oauthResponse->getParameters();
97 4
                if (($status === false) && (empty($error) === false)) {
98 2
                    Yii::$app->session->setFlash('error', $error, false);
99
                    // 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...
100 2
                }
101 4
                break;
102
        }
103
104 8
        if ($status === true) {
105 4
            Yii::$app->session->set('oauthServer', $oauthServer);
106 4
            if (isset($oauthRequest) === true) {
107 4
                Yii::$app->session->set('oauthRequest', $oauthRequest);
108 4
            }
109 4
            if (Yii::$app->user->isGuest === true) {
110 4
                $response = $this->redirect(['login']);
111 4
            } else {
112 1
                $response = $this->redirect(['authorize']);
113
            }
114 4
        } else {
115
            //TODO: check if we should redirect to specific url with an error
116 4
            $response = $this->redirect(['error']);
117
        }
118 8
        return $response;
119
    }
120
121
    /**
122
     * Display login page
123
     * @return Response|string
124
     * @since XXX
125
     */
126 5
    public function actionLogin()
127
    {
128 5
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
129
130 5
        $oauthServer = Yii::$app->session->get('oauthServer');
131
        /* @var \Oauth2\Server $oauthServer */
132 5
        if ($oauthServer === null) {
133 1
            Yii::$app->session->setFlash('error', [
134 1
                'error' => 'request_invalid',
135 1
                'error_description' => 'The request was not performed as expected.',
136 1
            ], false);
137 1
            return $this->redirect(['error']);
138
        }
139
140 4
        $userForm = Yii::createObject('sweelix\oauth2\server\forms\User');
141 4
        $response = null;
142
        /* @var \sweelix\oauth2\server\forms\User $userForm */
143 4
        if (Yii::$app->request->isPost === true) {
144
            //TODO: handle case when user decline the grants
145 4
            $userForm->load(Yii::$app->request->bodyParams);
146 5
            if ($userForm->validate() === true) {
147 4
                $userClass = $this->getUserClass();
148 4
                $realUser = $userClass::findByUsernameAndPassword($userForm->username, $userForm->password);
149
                /* @var \sweelix\oauth2\server\interfaces\UserModelInterface $realUser */
150 4
                if ($realUser !== null) {
151 4
                    Yii::$app->user->login($realUser, Module::getInstance()->loginDuration);
152 4
                    $response = $this->redirect(['authorize']);
153 4
                } else {
154 2
                    $userForm->addError('username');
155
                }
156 4
            }
157 4
        }
158 4
        if ($response === null) {
159
            // force empty password
160 4
            $userForm->password = '';
161 4
            $response = $this->render('login', [
162 4
                'user' => $userForm,
163 4
            ]);
164 4
        }
165 4
        return $response;
166
    }
167
168
    /**
169
     * Display authorize page
170
     * @return string|Response
171
     * @since XXX
172
     */
173 4
    public function actionAuthorize()
174
    {
175 4
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
176 4
        $oauthServer = Yii::$app->session->get('oauthServer');
177
        /* @var \Oauth2\Server $oauthServer */
178 4
        if ($oauthServer === null) {
179
            Yii::$app->session->setFlash('error', [
180
                'error' => 'request_invalid',
181
                'error_description' => 'The request was not performed as expected.',
182
            ], false);
183
            return $this->redirect(['error']);
184
        }
185 4
        $oauthController = $oauthServer->getAuthorizeController();
186 4
        $client = Client::findOne($oauthController->getClientId());
187
188 4
        if ($client->hasUser(Yii::$app->user->id) === true) {
189
            // already logged
190 1
            $oauthRequest = Yii::$app->session->get('oauthRequest');
191 1
            $oauthResponse = new OAuth2Response();
192 1
            $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, true, Yii::$app->user->id);
193
            /* @var OAuth2Response $oauthResponse */
194 1
            Yii::$app->session->remove('oauthServer');
195 1
            Yii::$app->session->remove('oauthRequest');
196 1
            $error = $oauthResponse->getParameters();
197 1
            if (empty($error) === false) {
198
                Yii::$app->session->setFlash('error', $error, false);
199
                return $this->redirect(['error']);
200
            } else {
201 1
                return $this->redirect($oauthResponse->getHttpHeader('Location'));
202
            }
203
        } else {
204
            // perform regular authorization
205 4
            $additionalScopes = $oauthController->getScope();
206 4
            $requestedScopes = [];
207 4
            if (empty($additionalScopes) === false) {
208
                $additionalScopes = explode(' ', $additionalScopes);
209
                foreach($additionalScopes as $scope) {
210
                    $dbScope = Scope::findOne($scope);
211
                    if ($dbScope !== null) {
212
                        $requestedScopes[] = [
213
                            '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...
214
                            '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...
215
                        ];
216
                    } else {
217
                        $requestedScopes[] = [
218
                            'id' => $scope,
219
                            'description' => null,
220
                        ];
221
                    }
222
                }
223
            }
224 4
            if (Yii::$app->request->isPost === true) {
225 4
                $accept = Yii::$app->request->getBodyParam('accept', null);
226 4
                $oauthRequest = Yii::$app->session->get('oauthRequest');
227 4
                $oauthResponse = new OAuth2Response();
228
                /* @var OAuth2Response $oauthResponse */
229
230 4
                if ($accept !== null) {
231 2
                    $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, true, Yii::$app->user->id);
232 2
                    $client->addUser(Yii::$app->user->id);
233
                    // authorize
234 2
                } else {
235 2
                    $oauthResponse = $oauthServer->handleAuthorizeRequest($oauthRequest, $oauthResponse, false, Yii::$app->user->id);
236 2
                    $client->removeUser(Yii::$app->user->id);
237
                    // decline
238
                }
239
240 4
                Yii::$app->session->remove('oauthServer');
241 4
                Yii::$app->session->remove('oauthRequest');
242 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...
243 4
                $redirect = $oauthResponse->getHttpHeader('Location');
244 4
                if ((empty($error) === false) && ($redirect === null)) {
245
                    Yii::$app->session->setFlash('error', $error, false);
246
                    return $this->redirect(['error']);
247
                } else {
248 4
                    return $this->redirect($redirect);
249
                }
250
            }
251
        }
252
253 4
        return $this->render('authorize', [
254 4
            'client' => $client,
255 4
            'requestedScopes' => $requestedScopes,
256 4
        ]);
257
    }
258
259
    /**
260
     * Display an error page
261
     * @return Response|string
262
     * @since XXX
263
     */
264 5
    public function actionError()
265
    {
266 5
        Yii::$app->response->headers->add('Content-Security-Policy', 'frame-ancestors \'none\';');
267 5
        $errorData = Yii::$app->session->getFlash('error');
268 5
        return $this->render('error', [
269 5
            'type' => (isset($errorData['error']) ? $errorData['error'] : null),
270 5
            'description' => (isset($errorData['error_description']) ? $errorData['error_description'] : null),
271 5
        ]);
272
    }
273
274
    /**
275
     * @var string
276
     */
277
    private $userClass;
278
279
    /**
280
     * @return string classname for selected interface
281
     * @since XXX
282
     */
283 4
    public function getUserClass()
284
    {
285 4
        if ($this->userClass === null) {
286 4
            $scope = Yii::createObject('sweelix\oauth2\server\interfaces\UserModelInterface');
287 4
            $this->userClass = get_class($scope);
288 4
        }
289 4
        return $this->userClass;
290
    }
291
292
293
294
}
295