Commit f91c1ae8773352ce6a24131a9a83ba59bdc73b40
1 parent
bb1ff629
new commit components
Компонент авторизации через соц сети вынес в папку common
Showing
76 changed files
with
7942 additions
and
18 deletions
Show diff stats
1 | +Yii2 EAuth Change Log | |
2 | +===================== | |
3 | + | |
4 | +### 2.3.0 (17.10.2015) | |
5 | +* Added InstagramOAuth2Service (#61) | |
6 | +* Fixed default token lifetime (#53) | |
7 | +* Replace array() with [] (#54) | |
8 | +* Remove deprecated Google OpenID service (#56) | |
9 | +* Remove deprecated Yandex OpenID service | |
10 | + | |
11 | +### 2.2.4 (27.07.2015) | |
12 | +* Fixed typo in `oauth2/Service.php` (#34) | |
13 | +* Added German translation | |
14 | +* Added `email` attribute to `LinkedinOAuth2Service.php` | |
15 | + | |
16 | +### 2.2.3 (15.07.2014) | |
17 | +* Added ability to call public api methods (without access token) (#28) | |
18 | + | |
19 | +### 2.2.2 (15.07.2014) | |
20 | +* Fixed wrong redirect_uri when popup is used | |
21 | + | |
22 | +### 2.2.1 (25.04.2014) | |
23 | +* Fix missing query params in callback urls (#26) | |
24 | +* Follow Yii2 code style | |
25 | + | |
26 | +### 2.2.0 (19.04.2014) | |
27 | +* Support for PHPoAuthLib v0.3 (#22) | |
28 | +* Support for Yii2 beta | |
29 | +* Internal state implementation replaced to PHPoAuthLib storage | |
30 | + | |
31 | +### 2.1.5 (24.03.2014) | |
32 | +* Fixed Yii2 refactor (#17) | |
33 | +* PSR-4 | |
34 | + | |
35 | +### 2.1.4 (11.03.2014) | |
36 | +* Fixed wrong callbackUrl in oauth\ServiceBase when UrlManager uses prettyUrl=false and showScript=false (#12) | |
37 | +* Fixed Yii::t() calls according to Yii2 i18n Named Placeholders (#14) | |
38 | +* Fixed Yii2 refactor #2630 (#15) | |
39 | + | |
40 | +### 2.1.3 (30.01.2014) | |
41 | +* Yii2 update (Request methods has been refactored). | |
42 | + | |
43 | +### 2.1.2 (17.01.2014) | |
44 | +* Fixed typo in oauth2\ServiceProxy | |
45 | + | |
46 | +### 2.1.1 (07.01.2014) | |
47 | +* Fixed scope validation for OAuth services. | |
48 | + | |
49 | +### 2.1.0 (22.12.2013) | |
50 | +* Reorganize project with new namespace. | |
51 | +* Assets bundle has been moved. | |
52 | +* Fixed typo in HttpClient (#8). | |
53 | +* Added default User-Agent header to HttpClient. | |
54 | +* Disabled CSRF validation for OpenID callbacks. | |
55 | +* Optimized icons file. | |
56 | +* Added SteamOpenIDService. | |
57 | +* Improved redirect widget. | |
58 | + | |
59 | +### 2.0.3 (26.10.2013) | |
60 | +* Fixed redirect_uri when not using url rule (#2). | |
61 | +* Fixed hasValidAccessToken() method for OAuth1 services (#3). | |
62 | +* Fixed auto login cookie (#4). | |
63 | + | |
64 | +### 2.0.2 (12.10.2013) | |
65 | +* Fixed ServiceProxy constructor to match its interface (#1). | |
66 | +* Added HttpClient with logging support and curl/streams fallback. | |
67 | +* TokenStorage and HttpClient are configurable now. | |
68 | + | |
69 | +### 2.0.1 (08.09.2013) | |
70 | +* Fixed package versions in the composer.json. | |
71 | +* Fixed directories names. | |
72 | +* Added support for custom scope separator in OAuth2 services. | |
73 | +* Added support for additional headers for OAuth2 requests. | |
74 | +* Added method to get error from access token response. | |
75 | +* Added GitHubOAuth2Service. | |
76 | +* Added LinkedinOAuth2Service. | |
77 | +* Added MailruOAuth2Service. | |
78 | +* Added OdnoklassnikiOAuth2Service. | |
79 | +* Added LiveOAuth2Service. | |
80 | +* Added YahooOpenIDService. | |
81 | + | |
82 | +### Version 2.0.0 (03.09.2013) | |
83 | +* Use curl for http requests by default. | |
84 | +* getIsAuthenticated() function now looks up for existing access token for all OAuth services. | |
85 | +* Added support for oauth_expires_in to OAuth1 services. | |
86 | +* Added error handlers to OAuth1 services. | |
87 | +* Added support for refresh tokens to OAuth2 ServiceProxy. | |
88 | +* Added an option to disable OAuth2 state validation. | |
89 | + | |
90 | +### 31.08.2013 | |
91 | +* Reorganize directories. Separate root directory by service type. | |
92 | +* Fixed OAuthService::getCallbackUrl(). Now returns url without GET arguments. | |
93 | +* Fixed typos in OAuth services. | |
94 | +* Fixed OpenID loadAttributes functions. | |
95 | +* OAuth2 display mode handling moved to the base class. | |
96 | +* Added OAuthService::getAccessTokenData() method to access to valid access_token and related data. | |
97 | +* Added token default lifetime setting. | |
98 | +* Added "state" argument handling for OAuth2 services to improve security. | |
99 | +* Updated OpenID library. Fixed error with stream requests. | |
100 | +* Added VKontakteOAuth2Service. | |
101 | +* Added GoogleOAuth2Service. | |
102 | +* Added GoogleOAuth2Service. | |
103 | +* Added YandexOAuth2Service. | |
104 | +* Added session token storage using Yii session. | |
105 | + | |
106 | +### 30.08.2013 | |
107 | +* Initial release for Yii2. | ... | ... |
1 | +Copyright (c) 2011, Maxim Zemskov | |
2 | +All rights reserved. | |
3 | + | |
4 | +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | |
5 | + | |
6 | +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | |
7 | +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | |
8 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
0 | 9 | \ No newline at end of file | ... | ... |
1 | +Yii2 EAuth extension | |
2 | +==================== | |
3 | + | |
4 | +EAuth extension allows to authenticate users with accounts on other websites. | |
5 | +Supported protocols: OpenID, OAuth 1.0 and OAuth 2.0. | |
6 | + | |
7 | +EAuth is an extension to provide a unified (does not depend on the selected service) method to authenticate the user. The extension itself does not perform login, does not register the user and does not bind the user accounts from different providers. | |
8 | + | |
9 | +* [Demo](http://nodge.ru/yii-eauth/demo2/) | |
10 | +* [Demo project](https://github.com/Nodge/yii2-eauth-demo/) | |
11 | +* [Installation](#installation) | |
12 | +* [Version for yii 1.1](https://github.com/Nodge/yii-eauth/) | |
13 | + | |
14 | +### Why own extension and not a third-party service? | |
15 | +The implementation of the authorization on your own server has several advantages: | |
16 | + | |
17 | +* Full control over the process: What will be written in the authorization window, what data we get, etc. | |
18 | +* Ability to change the appearance of the widget. | |
19 | +* When logging in via OAuth, it is possible to invoke methods on the API. | |
20 | +* Fewer dependencies on third-party services - more reliable application. | |
21 | + | |
22 | + | |
23 | +### The extension allows you to: | |
24 | + | |
25 | +* Ignore the nuances of authorization through the different types of services and use the class based adapters for each service. | |
26 | +* Get a unique user ID that can be used to register the user in your application. | |
27 | +* Extend the standard authorization classes to obtain additional data about the user. | |
28 | +* Work with the API of social networks by extending the authorization classes. | |
29 | +* Set up a list of supported services, customize the appearance of the widget, use the popup window without closing your application. | |
30 | + | |
31 | + | |
32 | +### Extension includes: | |
33 | + | |
34 | +* The component that contains utility functions. | |
35 | +* A widget that displays a list of services in the form of icons and allowing authorization in the popup window. | |
36 | +* Base classes to create your own services. | |
37 | +* Ready to authenticate via Google, Twitter, Facebook and other providers. | |
38 | + | |
39 | + | |
40 | +### Included services: | |
41 | + | |
42 | +* OpenID: | |
43 | + * Yahoo | |
44 | + * Steam | |
45 | +* OAuth1: | |
46 | ||
47 | ||
48 | +* OAuth2: | |
49 | ||
50 | ||
51 | + * Live | |
52 | + * GitHub | |
53 | ||
54 | ||
55 | + * Yandex (ru) | |
56 | + * VKontake (ru) | |
57 | + * Mail.ru (ru) | |
58 | + * Odnoklassniki (ru) | |
59 | + | |
60 | + | |
61 | +### Resources | |
62 | + | |
63 | +* [Yii EAuth](https://github.com/Nodge/yii2-eauth) | |
64 | +* [Demo](http://nodge.ru/yii-eauth/demo2/) | |
65 | +* [Demo project](https://github.com/Nodge/yii2-eauth-demo/) | |
66 | +* [Yii Framework](http://yiiframework.com/) | |
67 | +* [OpenID](http://openid.net/) | |
68 | +* [OAuth](http://oauth.net/) | |
69 | +* [OAuth 2.0](http://oauth.net/2/) | |
70 | +* [LightOpenID](https://github.com/iignatov/LightOpenID) | |
71 | +* [PHPoAuthLib](https://github.com/Lusitanian/PHPoAuthLib) | |
72 | + | |
73 | + | |
74 | +### Requirements | |
75 | + | |
76 | +* Yii 2.0 or above | |
77 | +* curl php extension | |
78 | +* LightOpenId | |
79 | +* PHPoAuthLib | |
80 | + | |
81 | + | |
82 | +# Installation | |
83 | + | |
84 | +This library can be found on [Packagist](https://packagist.org/packages/nodge/yii2-eauth). | |
85 | +The recommended way to install this is through [composer](http://getcomposer.org). | |
86 | + | |
87 | +Edit your `composer.json` and add: | |
88 | + | |
89 | +```json | |
90 | +{ | |
91 | + "require": { | |
92 | + "nodge/yii2-eauth": "~2.0" | |
93 | + } | |
94 | +} | |
95 | +``` | |
96 | + | |
97 | +And install dependencies: | |
98 | + | |
99 | +```bash | |
100 | +$ curl -sS https://getcomposer.org/installer | php | |
101 | +$ php composer.phar install | |
102 | +``` | |
103 | + | |
104 | + | |
105 | +# Usage | |
106 | + | |
107 | +## Demo project | |
108 | + | |
109 | +The source code of the [demo](http://nodge.ru/yii-eauth/demo2/) is available [here](https://github.com/Nodge/yii2-eauth-demo/). | |
110 | + | |
111 | + | |
112 | +## Basic setup | |
113 | + | |
114 | +### Configuration | |
115 | + | |
116 | +Add the following in your config: | |
117 | + | |
118 | +```php | |
119 | +<?php | |
120 | +... | |
121 | + 'components' => [ | |
122 | + 'eauth' => [ | |
123 | + 'class' => 'nodge\eauth\EAuth', | |
124 | + 'popup' => true, // Use the popup window instead of redirecting. | |
125 | + 'cache' => false, // Cache component name or false to disable cache. Defaults to 'cache' on production environments. | |
126 | + 'cacheExpire' => 0, // Cache lifetime. Defaults to 0 - means unlimited. | |
127 | + 'httpClient' => [ | |
128 | + // uncomment this to use streams in safe_mode | |
129 | + //'useStreamsFallback' => true, | |
130 | + ], | |
131 | + 'services' => [ // You can change the providers and their classes. | |
132 | + 'google' => [ | |
133 | + // register your app here: https://code.google.com/apis/console/ | |
134 | + 'class' => 'nodge\eauth\services\GoogleOAuth2Service', | |
135 | + 'clientId' => '...', | |
136 | + 'clientSecret' => '...', | |
137 | + 'title' => 'Google', | |
138 | + ], | |
139 | + 'twitter' => [ | |
140 | + // register your app here: https://dev.twitter.com/apps/new | |
141 | + 'class' => 'nodge\eauth\services\TwitterOAuth1Service', | |
142 | + 'key' => '...', | |
143 | + 'secret' => '...', | |
144 | + ], | |
145 | + 'yandex' => [ | |
146 | + // register your app here: https://oauth.yandex.ru/client/my | |
147 | + 'class' => 'nodge\eauth\services\YandexOAuth2Service', | |
148 | + 'clientId' => '...', | |
149 | + 'clientSecret' => '...', | |
150 | + 'title' => 'Yandex', | |
151 | + ], | |
152 | + 'facebook' => [ | |
153 | + // register your app here: https://developers.facebook.com/apps/ | |
154 | + 'class' => 'nodge\eauth\services\FacebookOAuth2Service', | |
155 | + 'clientId' => '...', | |
156 | + 'clientSecret' => '...', | |
157 | + ], | |
158 | + 'yahoo' => [ | |
159 | + 'class' => 'nodge\eauth\services\YahooOpenIDService', | |
160 | + //'realm' => '*.example.org', // your domain, can be with wildcard to authenticate on subdomains. | |
161 | + ], | |
162 | + 'linkedin' => [ | |
163 | + // register your app here: https://www.linkedin.com/secure/developer | |
164 | + 'class' => 'nodge\eauth\services\LinkedinOAuth1Service', | |
165 | + 'key' => '...', | |
166 | + 'secret' => '...', | |
167 | + 'title' => 'LinkedIn (OAuth1)', | |
168 | + ], | |
169 | + 'linkedin_oauth2' => [ | |
170 | + // register your app here: https://www.linkedin.com/secure/developer | |
171 | + 'class' => 'nodge\eauth\services\LinkedinOAuth2Service', | |
172 | + 'clientId' => '...', | |
173 | + 'clientSecret' => '...', | |
174 | + 'title' => 'LinkedIn (OAuth2)', | |
175 | + ], | |
176 | + 'github' => [ | |
177 | + // register your app here: https://github.com/settings/applications | |
178 | + 'class' => 'nodge\eauth\services\GitHubOAuth2Service', | |
179 | + 'clientId' => '...', | |
180 | + 'clientSecret' => '...', | |
181 | + ], | |
182 | + 'live' => [ | |
183 | + // register your app here: https://account.live.com/developers/applications/index | |
184 | + 'class' => 'nodge\eauth\services\LiveOAuth2Service', | |
185 | + 'clientId' => '...', | |
186 | + 'clientSecret' => '...', | |
187 | + ], | |
188 | + 'steam' => [ | |
189 | + 'class' => 'nodge\eauth\services\SteamOpenIDService', | |
190 | + //'realm' => '*.example.org', // your domain, can be with wildcard to authenticate on subdomains. | |
191 | + ], | |
192 | + 'instagram' => [ | |
193 | + // register your app here: https://instagram.com/developer/register/ | |
194 | + 'class' => 'nodge\eauth\services\InstagramOAuth2Service', | |
195 | + 'clientId' => '...', | |
196 | + 'clientSecret' => '...', | |
197 | + ], | |
198 | + 'vkontakte' => [ | |
199 | + // register your app here: https://vk.com/editapp?act=create&site=1 | |
200 | + 'class' => 'nodge\eauth\services\VKontakteOAuth2Service', | |
201 | + 'clientId' => '...', | |
202 | + 'clientSecret' => '...', | |
203 | + ], | |
204 | + 'mailru' => [ | |
205 | + // register your app here: http://api.mail.ru/sites/my/add | |
206 | + 'class' => 'nodge\eauth\services\MailruOAuth2Service', | |
207 | + 'clientId' => '...', | |
208 | + 'clientSecret' => '...', | |
209 | + ], | |
210 | + 'odnoklassniki' => [ | |
211 | + // register your app here: http://dev.odnoklassniki.ru/wiki/pages/viewpage.action?pageId=13992188 | |
212 | + // ... or here: http://www.odnoklassniki.ru/dk?st.cmd=appsInfoMyDevList&st._aid=Apps_Info_MyDev | |
213 | + 'class' => 'nodge\eauth\services\OdnoklassnikiOAuth2Service', | |
214 | + 'clientId' => '...', | |
215 | + 'clientSecret' => '...', | |
216 | + 'clientPublic' => '...', | |
217 | + 'title' => 'Odnoklas.', | |
218 | + ], | |
219 | + ], | |
220 | + ], | |
221 | + | |
222 | + 'i18n' => [ | |
223 | + 'translations' => [ | |
224 | + 'eauth' => [ | |
225 | + 'class' => 'yii\i18n\PhpMessageSource', | |
226 | + 'basePath' => '@eauth/messages', | |
227 | + ], | |
228 | + ], | |
229 | + ], | |
230 | + | |
231 | + // (optionally) you can configure pretty urls | |
232 | + 'urlManager' => [ | |
233 | + 'enablePrettyUrl' => true, | |
234 | + 'showScriptName' => false, | |
235 | + 'rules' => [ | |
236 | + 'login/<service:google|facebook|etc>' => 'site/login', | |
237 | + ], | |
238 | + ], | |
239 | + | |
240 | + // (optionally) you can configure logging | |
241 | + 'log' => [ | |
242 | + 'targets' => [ | |
243 | + [ | |
244 | + 'class' => 'yii\log\FileTarget', | |
245 | + 'logFile' => '@app/runtime/logs/eauth.log', | |
246 | + 'categories' => ['nodge\eauth\*'], | |
247 | + 'logVars' => [], | |
248 | + ], | |
249 | + ], | |
250 | + ], | |
251 | + ... | |
252 | + ], | |
253 | +... | |
254 | +``` | |
255 | + | |
256 | +### User model | |
257 | + | |
258 | +You need to modify your User model to login with EAuth services. | |
259 | +Example from demo project: | |
260 | + | |
261 | +```php | |
262 | +<?php | |
263 | +... | |
264 | + /** | |
265 | + * @var array EAuth attributes | |
266 | + */ | |
267 | + public $profile; | |
268 | + | |
269 | + public static function findIdentity($id) { | |
270 | + if (Yii::$app->getSession()->has('user-'.$id)) { | |
271 | + return new self(Yii::$app->getSession()->get('user-'.$id)); | |
272 | + } | |
273 | + else { | |
274 | + return isset(self::$users[$id]) ? new self(self::$users[$id]) : null; | |
275 | + } | |
276 | + } | |
277 | + | |
278 | + /** | |
279 | + * @param \nodge\eauth\ServiceBase $service | |
280 | + * @return User | |
281 | + * @throws ErrorException | |
282 | + */ | |
283 | + public static function findByEAuth($service) { | |
284 | + if (!$service->getIsAuthenticated()) { | |
285 | + throw new ErrorException('EAuth user should be authenticated before creating identity.'); | |
286 | + } | |
287 | + | |
288 | + $id = $service->getServiceName().'-'.$service->getId(); | |
289 | + $attributes = [ | |
290 | + 'id' => $id, | |
291 | + 'username' => $service->getAttribute('name'), | |
292 | + 'authKey' => md5($id), | |
293 | + 'profile' => $service->getAttributes(), | |
294 | + ]; | |
295 | + $attributes['profile']['service'] = $service->getServiceName(); | |
296 | + Yii::$app->getSession()->set('user-'.$id, $attributes); | |
297 | + return new self($attributes); | |
298 | + } | |
299 | +... | |
300 | +``` | |
301 | + | |
302 | +Then you can access to EAuth attributes through: | |
303 | + | |
304 | +```php | |
305 | +<?php | |
306 | + $identity = Yii::$app->getUser()->getIdentity(); | |
307 | + if (isset($identity->profile)) { | |
308 | + VarDumper::dump($identity->profile, 10, true); | |
309 | + } | |
310 | +``` | |
311 | + | |
312 | +### Controller | |
313 | + | |
314 | +Attach OpenID Controller behavior to disable CSRF validation for OpenID callbacks. | |
315 | +Or you can disable CSRF validation by yourself. | |
316 | + | |
317 | +```php | |
318 | +<?php | |
319 | +... | |
320 | + public function behaviors() { | |
321 | + return [ | |
322 | + 'eauth' => [ | |
323 | + // required to disable csrf validation on OpenID requests | |
324 | + 'class' => \nodge\eauth\openid\ControllerBehavior::className(), | |
325 | + 'only' => ['login'], | |
326 | + ], | |
327 | + ]; | |
328 | + } | |
329 | +... | |
330 | +``` | |
331 | + | |
332 | +Add the following to your Login action: | |
333 | + | |
334 | +```php | |
335 | +<?php | |
336 | +... | |
337 | + public function actionLogin() { | |
338 | + $serviceName = Yii::$app->getRequest()->getQueryParam('service'); | |
339 | + if (isset($serviceName)) { | |
340 | + /** @var $eauth \nodge\eauth\ServiceBase */ | |
341 | + $eauth = Yii::$app->get('eauth')->getIdentity($serviceName); | |
342 | + $eauth->setRedirectUrl(Yii::$app->getUser()->getReturnUrl()); | |
343 | + $eauth->setCancelUrl(Yii::$app->getUrlManager()->createAbsoluteUrl('site/login')); | |
344 | + | |
345 | + try { | |
346 | + if ($eauth->authenticate()) { | |
347 | +// var_dump($eauth->getIsAuthenticated(), $eauth->getAttributes()); exit; | |
348 | + | |
349 | + $identity = User::findByEAuth($eauth); | |
350 | + Yii::$app->getUser()->login($identity); | |
351 | + | |
352 | + // special redirect with closing popup window | |
353 | + $eauth->redirect(); | |
354 | + } | |
355 | + else { | |
356 | + // close popup window and redirect to cancelUrl | |
357 | + $eauth->cancel(); | |
358 | + } | |
359 | + } | |
360 | + catch (\nodge\eauth\ErrorException $e) { | |
361 | + // save error to show it later | |
362 | + Yii::$app->getSession()->setFlash('error', 'EAuthException: '.$e->getMessage()); | |
363 | + | |
364 | + // close popup window and redirect to cancelUrl | |
365 | +// $eauth->cancel(); | |
366 | + $eauth->redirect($eauth->getCancelUrl()); | |
367 | + } | |
368 | + } | |
369 | + | |
370 | + // default authorization code through login/password .. | |
371 | + } | |
372 | +... | |
373 | +``` | |
374 | + | |
375 | +### View | |
376 | + | |
377 | +```php | |
378 | +... | |
379 | +<?php | |
380 | + if (Yii::$app->getSession()->hasFlash('error')) { | |
381 | + echo '<div class="alert alert-danger">'.Yii::$app->getSession()->getFlash('error').'</div>'; | |
382 | + } | |
383 | +?> | |
384 | +... | |
385 | +<p class="lead">Do you already have an account on one of these sites? Click the logo to log in with it here:</p> | |
386 | +<?php echo \nodge\eauth\Widget::widget(['action' => 'site/login']); ?> | |
387 | +... | |
388 | +``` | |
389 | + | |
390 | + | |
391 | +## Extending | |
392 | + | |
393 | +To receive all the necessary data to your application, you can override the base class of any provider. | |
394 | +Base classes are stored in `@eauth/src/services`. | |
395 | +Examples of extended classes can be found in `@eauth/src/services/extended/`. | |
396 | + | |
397 | +After overriding the base class, you need to update your configuration file with a new class name. | |
398 | + | |
399 | + | |
400 | +## Working with OAuth API | |
401 | + | |
402 | +You can extend base classes with necessary methods and then write something like this: | |
403 | + | |
404 | +```php | |
405 | +<?php | |
406 | + /** @var $eauth EAuthServiceBase */ | |
407 | + $eauth = Yii::$app->eauth->getIdentity('facebook'); | |
408 | + | |
409 | + // to get protected resources user should be authenticated: | |
410 | + if ($eauth->getIsAuthenticated()) { | |
411 | + $eauth->callProtectedApiMethod(); | |
412 | + $eauth->callAnotherProtectedApiMethod(); | |
413 | + } | |
414 | + | |
415 | + // or you can get public resources at any time: | |
416 | + $eauth->callPublicApiMethod(); | |
417 | + $eauth->callAnotherPublicApiMethod(); | |
418 | +``` | |
419 | + | |
420 | +Example of an API call method: | |
421 | + | |
422 | +```php | |
423 | +<?php | |
424 | + class FacebookOAuth2Service extends \nodge\eauth\services\FacebookOAuth2Service | |
425 | + { | |
426 | + public function fooApiMethod($bar) { | |
427 | + $api_method = 'me'; // ex. for Facebook this results to https://graph.facebook.com/me | |
428 | + | |
429 | + // get protected resource | |
430 | + $response = $this->makeSignedRequest($api_method, [ | |
431 | + 'query' => [ 'foo' => 'bar' ], // GET arguments | |
432 | + 'data' => [ 'foo' => 'bar' ], // POST arguments | |
433 | + 'headers' => [ 'X-Foo' => 'bar' ], // Extra HTTP headers | |
434 | + ]); | |
435 | + | |
436 | + // you can get public resources with the same API: | |
437 | + //$response = $this->makeRequest($api_method, $options); | |
438 | + | |
439 | + // process $response | |
440 | + $data = process($response); | |
441 | + | |
442 | + // return results | |
443 | + return $data; | |
444 | + } | |
445 | + } | |
446 | +``` | |
447 | + | |
448 | +API calls are performed if the current user has a valid access token (saved during the authentication). | |
449 | +You can save access_token to your database by using custom token storage in your config: | |
450 | + | |
451 | +```php | |
452 | +<?php | |
453 | +... | |
454 | + 'components' => [ | |
455 | + 'eauth' => [ | |
456 | + 'class' => 'nodge\eauth\EAuth', | |
457 | + 'tokenStorage' => [ | |
458 | + 'class' => '@app\eauth\DatabaseTokenStorage', | |
459 | + ], | |
460 | + ], | |
461 | + ... | |
462 | + ], | |
463 | +... | |
464 | +``` | |
465 | + | |
466 | + | |
467 | +## Translation | |
468 | + | |
469 | +To use translations, add the following in your config: | |
470 | + | |
471 | +```php | |
472 | +<?php | |
473 | +... | |
474 | + 'components' => [ | |
475 | + 'i18n' => [ | |
476 | + 'translations' => [ | |
477 | + 'eauth' => [ | |
478 | + 'class' => 'yii\i18n\PhpMessageSource', | |
479 | + 'basePath' => '@eauth/messages', | |
480 | + ], | |
481 | + ], | |
482 | + ], | |
483 | + ... | |
484 | + ], | |
485 | +... | |
486 | +``` | |
487 | + | |
488 | +Available translations can be found in `@eauth/src/messages`. | |
489 | + | |
490 | + | |
491 | +# License | |
492 | + | |
493 | +The extension was released under the [New BSD License](http://www.opensource.org/licenses/bsd-license.php), so you'll find the latest version on [GitHub](https://github.com/Nodge/yii2-eauth). | ... | ... |
1 | +{ | |
2 | + "name": "nodge/yii2-eauth", | |
3 | + "description": "Yii2 EAuth Extension. EAuth allows to authenticate users with accounts on other websites (Google, Facebook, Twitter, etc).", | |
4 | + "keywords": ["yii2", "extension", "eauth", "openid", "oauth", "authentication"], | |
5 | + "homepage": "https://github.com/Nodge/yii2-eauth", | |
6 | + "type": "yii2-extension", | |
7 | + "license": "New BSD License", | |
8 | + "authors": [ | |
9 | + { | |
10 | + "name": "Maxim Zemskov", | |
11 | + "email": "nodge@yandex.ru", | |
12 | + "homepage": "http://nodge.ru/" | |
13 | + } | |
14 | + ], | |
15 | + "support": { | |
16 | + "source": "https://github.com/nodge/yii2-eauth" | |
17 | + }, | |
18 | + "autoload": { | |
19 | + "psr-4": { | |
20 | + "common\modules\nodge\\eauth\\": "src/" | |
21 | + } | |
22 | + }, | |
23 | + "require": { | |
24 | + "php": ">=5.4.0", | |
25 | + "lib-curl": "*", | |
26 | + "yiisoft/yii2": "*", | |
27 | + "lusitanian/oauth": "~0.3.0", | |
28 | + "nodge/lightopenid": "~1.1.0" | |
29 | + }, | |
30 | + "extra": { | |
31 | + "bootstrap": "common\modules\nodge\\eauth\\Bootstrap" | |
32 | + } | |
33 | +} | |
0 | 34 | \ No newline at end of file | ... | ... |
1 | +<?php | |
2 | +/** | |
3 | + * Extension class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace common\modules\nodge\eauth\src\eauth; | |
11 | + | |
12 | +use Yii; | |
13 | +use yii\base\Application; | |
14 | +use yii\base\BootstrapInterface; | |
15 | + | |
16 | +/** | |
17 | + * This is the bootstrap class for the yii2-eauth extension. | |
18 | + */ | |
19 | +class Bootstrap implements BootstrapInterface | |
20 | +{ | |
21 | + /** | |
22 | + * @inheritdoc | |
23 | + */ | |
24 | + public function bootstrap($app) | |
25 | + { | |
26 | + Yii::setAlias('@eauth', __DIR__); | |
27 | + } | |
28 | +} | |
0 | 29 | \ No newline at end of file | ... | ... |
1 | +<?php | |
2 | +/** | |
3 | + * EAuth class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace common\components\nodge\eauth\src; | |
11 | + | |
12 | +use Yii; | |
13 | +use yii\base\Object; | |
14 | +use yii\helpers\ArrayHelper; | |
15 | +use yii\helpers\Url; | |
16 | + | |
17 | +/** | |
18 | + * The EAuth class provides simple authentication via OpenID and OAuth providers. | |
19 | + * | |
20 | + * @package application.extensions.eauth | |
21 | + */ | |
22 | +class EAuth extends Object | |
23 | +{ | |
24 | + | |
25 | + /** | |
26 | + * @var array Authorization services and their settings. | |
27 | + */ | |
28 | + protected $services = []; | |
29 | + | |
30 | + /** | |
31 | + * @var boolean Whether to use popup window for the authorization dialog. | |
32 | + */ | |
33 | + protected $popup = true; | |
34 | + | |
35 | + /** | |
36 | + * @var string|bool Cache component name to use. False to disable cache. | |
37 | + */ | |
38 | + public $cache = null; | |
39 | + | |
40 | + /** | |
41 | + * @var integer the number of seconds in which the cached value will expire. 0 means never expire. | |
42 | + */ | |
43 | + public $cacheExpire = 0; | |
44 | + | |
45 | + /** | |
46 | + * @var string popup redirect view with custom js code | |
47 | + */ | |
48 | + protected $redirectWidget = '\\nodge\\eauth\\RedirectWidget'; | |
49 | + | |
50 | + /** | |
51 | + * @var array TokenStorage class. | |
52 | + */ | |
53 | + protected $tokenStorage = [ | |
54 | + 'class' => 'nodge\eauth\oauth\SessionTokenStorage', | |
55 | + ]; | |
56 | + | |
57 | + /** | |
58 | + * @var array HttpClient class. | |
59 | + */ | |
60 | + protected $httpClient = [ | |
61 | + 'class' => 'nodge\eauth\oauth\HttpClient', | |
62 | +// 'useStreamsFallback' => false, | |
63 | + ]; | |
64 | + | |
65 | + /** | |
66 | + * Initialize the component. | |
67 | + */ | |
68 | + public function init() | |
69 | + { | |
70 | + parent::init(); | |
71 | + | |
72 | + // set default cache on production environments | |
73 | + if (!isset($this->cache) && YII_ENV_PROD) { | |
74 | + $this->cache = 'cache'; | |
75 | + } | |
76 | + } | |
77 | + | |
78 | + /** | |
79 | + * @param array $services | |
80 | + */ | |
81 | + public function setServices($services) | |
82 | + { | |
83 | + $this->services = $services; | |
84 | + } | |
85 | + | |
86 | + /** | |
87 | + * Returns services settings declared in the authorization classes. | |
88 | + * For perfomance reasons it uses cache to store settings array. | |
89 | + * | |
90 | + * @return \stdClass[] services settings. | |
91 | + */ | |
92 | + public function getServices() | |
93 | + { | |
94 | + $services = false; | |
95 | + if (!empty($this->cache) && Yii::$app->has($this->cache)) { | |
96 | + /** @var $cache \yii\caching\Cache */ | |
97 | + $cache = Yii::$app->get($this->cache); | |
98 | + $services = $cache->get('EAuth.services'); | |
99 | + } | |
100 | + | |
101 | + if (false === $services || !is_array($services)) { | |
102 | + $services = []; | |
103 | + foreach ($this->services as $service => $options) { | |
104 | + /** @var $class ServiceBase */ | |
105 | + $class = $this->getIdentity($service); | |
106 | + $services[$service] = (object)[ | |
107 | + 'id' => $class->getServiceName(), | |
108 | + 'title' => $class->getServiceTitle(), | |
109 | + 'type' => $class->getServiceType(), | |
110 | + 'jsArguments' => $class->getJsArguments(), | |
111 | + ]; | |
112 | + } | |
113 | + if (isset($cache)) { | |
114 | + $cache->set('EAuth.services', $services, $this->cacheExpire); | |
115 | + } | |
116 | + } | |
117 | + return $services; | |
118 | + } | |
119 | + | |
120 | + /** | |
121 | + * @param bool $usePopup | |
122 | + */ | |
123 | + public function setPopup($usePopup) | |
124 | + { | |
125 | + $this->popup = $usePopup; | |
126 | + } | |
127 | + | |
128 | + /** | |
129 | + * @return bool | |
130 | + */ | |
131 | + public function getPopup() | |
132 | + { | |
133 | + return $this->popup; | |
134 | + } | |
135 | + | |
136 | + /** | |
137 | + * @param string|bool $cache | |
138 | + */ | |
139 | + public function setCache($cache) | |
140 | + { | |
141 | + $this->cache = $cache; | |
142 | + } | |
143 | + | |
144 | + /** | |
145 | + * @return string|bool | |
146 | + */ | |
147 | + public function getCache() | |
148 | + { | |
149 | + return $this->cache; | |
150 | + } | |
151 | + | |
152 | + /** | |
153 | + * @param int $cacheExpire | |
154 | + */ | |
155 | + public function setCacheExpire($cacheExpire) | |
156 | + { | |
157 | + $this->cacheExpire = $cacheExpire; | |
158 | + } | |
159 | + | |
160 | + /** | |
161 | + * @return int | |
162 | + */ | |
163 | + public function getCacheExpire() | |
164 | + { | |
165 | + return $this->cacheExpire; | |
166 | + } | |
167 | + | |
168 | + /** | |
169 | + * @param string $redirectWidget | |
170 | + */ | |
171 | + public function setRedirectWidget($redirectWidget) | |
172 | + { | |
173 | + $this->redirectWidget = $redirectWidget; | |
174 | + } | |
175 | + | |
176 | + /** | |
177 | + * @return string | |
178 | + */ | |
179 | + public function getRedirectWidget() | |
180 | + { | |
181 | + return $this->redirectWidget; | |
182 | + } | |
183 | + | |
184 | + /** | |
185 | + * @param array $config | |
186 | + */ | |
187 | + public function setTokenStorage(array $config) | |
188 | + { | |
189 | + $this->tokenStorage = ArrayHelper::merge($this->tokenStorage, $config); | |
190 | + } | |
191 | + | |
192 | + /** | |
193 | + * @return array | |
194 | + */ | |
195 | + public function getTokenStorage() | |
196 | + { | |
197 | + return $this->tokenStorage; | |
198 | + } | |
199 | + | |
200 | + /** | |
201 | + * @param array $config | |
202 | + */ | |
203 | + public function setHttpClient(array $config) | |
204 | + { | |
205 | + $this->httpClient = ArrayHelper::merge($this->httpClient, $config); | |
206 | + } | |
207 | + | |
208 | + /** | |
209 | + * @return array | |
210 | + */ | |
211 | + public function getHttpClient() | |
212 | + { | |
213 | + return $this->httpClient; | |
214 | + } | |
215 | + | |
216 | + /** | |
217 | + * Returns the settings of the service. | |
218 | + * | |
219 | + * @param string $service the service name. | |
220 | + * @return \stdClass the service settings. | |
221 | + * @throws ErrorException | |
222 | + */ | |
223 | + protected function getService($service) | |
224 | + { | |
225 | + $service = strtolower($service); | |
226 | + $services = $this->getServices(); | |
227 | + if (!isset($services[$service])) { | |
228 | + throw new ErrorException(Yii::t('eauth', 'Undefined service name: {service}.', ['service' => $service]), 500); | |
229 | + } | |
230 | + return $services[$service]; | |
231 | + } | |
232 | + | |
233 | + /** | |
234 | + * Returns the type of the service. | |
235 | + * | |
236 | + * @param string $service the service name. | |
237 | + * @return string the service type. | |
238 | + */ | |
239 | + public function getServiceType($service) | |
240 | + { | |
241 | + $service = $this->getService($service); | |
242 | + return $service->type; | |
243 | + } | |
244 | + | |
245 | + /** | |
246 | + * Returns the service identity class. | |
247 | + * | |
248 | + * @param string $service the service name. | |
249 | + * @return IAuthService the identity class. | |
250 | + * @throws ErrorException | |
251 | + */ | |
252 | + public function getIdentity($service) | |
253 | + { | |
254 | + $service = strtolower($service); | |
255 | + if (!isset($this->services[$service])) { | |
256 | + throw new ErrorException(Yii::t('eauth', 'Undefined service name: {service}.', ['service' => $service]), 500); | |
257 | + } | |
258 | + $service = $this->services[$service]; | |
259 | + | |
260 | + $service['component'] = $this; | |
261 | + | |
262 | + /** @var $identity IAuthService */ | |
263 | + $identity = Yii::createObject($service); | |
264 | + return $identity; | |
265 | + } | |
266 | + | |
267 | + /** | |
268 | + * Redirects to url. If the authorization dialog opened in the popup window, | |
269 | + * it will be closed instead of redirect. Set $jsRedirect=true if you want | |
270 | + * to redirect anyway. | |
271 | + * | |
272 | + * @param mixed $url url to redirect. Can be route or normal url. See {@link CHtml::normalizeUrl}. | |
273 | + * @param boolean $jsRedirect whether to use redirect while popup window is used. Defaults to true. | |
274 | + * @param array $params | |
275 | + */ | |
276 | + public function redirect($url, $jsRedirect = true, $params = []) | |
277 | + { | |
278 | + /** @var RedirectWidget $widget */ | |
279 | + $widget = Yii::createObject([ | |
280 | + 'class' => $this->redirectWidget, | |
281 | + 'url' => Url::to($url), | |
282 | + 'redirect' => $jsRedirect, | |
283 | + 'params' => $params | |
284 | + ]); | |
285 | + ob_start(); | |
286 | + $widget->run(); | |
287 | + $output = ob_get_clean(); | |
288 | + $response = Yii::$app->getResponse(); | |
289 | + $response->content = $output; | |
290 | + $response->send(); | |
291 | + exit(); | |
292 | + } | |
293 | + | |
294 | + /** | |
295 | + * Serialize the identity class. | |
296 | + * | |
297 | + * @param ServiceBase $identity the class instance. | |
298 | + * @return string serialized value. | |
299 | + */ | |
300 | + public function toString($identity) | |
301 | + { | |
302 | + return serialize($identity); | |
303 | + } | |
304 | + | |
305 | + /** | |
306 | + * Serialize the identity class. | |
307 | + * | |
308 | + * @param string $identity serialized value. | |
309 | + * @return ServiceBase the class instance. | |
310 | + */ | |
311 | + public function fromString($identity) | |
312 | + { | |
313 | + return unserialize($identity); | |
314 | + } | |
315 | + | |
316 | +} | ... | ... |
common/components/nodge/eauth/src/ErrorException.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * ErrorException class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace common\modules\nodge\eauth\src\eauth; | |
11 | + | |
12 | +class ErrorException extends \yii\base\ErrorException | |
13 | +{ | |
14 | + | |
15 | +} | |
0 | 16 | \ No newline at end of file | ... | ... |
1 | +<?php | |
2 | +/** | |
3 | + * IAuthService interface file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace common\modules\nodge\eauth\src\eauth; | |
11 | + | |
12 | +/** | |
13 | + * IAuthService is the interface for all service types and providers. | |
14 | + * | |
15 | + * @package application.extensions.eauth | |
16 | + */ | |
17 | +interface IAuthService | |
18 | +{ | |
19 | + | |
20 | + /** | |
21 | + * Returns service name(id). | |
22 | + */ | |
23 | + public function getServiceName(); | |
24 | + | |
25 | + /** | |
26 | + * Returns service title. | |
27 | + */ | |
28 | + public function getServiceTitle(); | |
29 | + | |
30 | + /** | |
31 | + * Returns service type (e.g. OpenID, OAuth). | |
32 | + */ | |
33 | + public function getServiceType(); | |
34 | + | |
35 | + /** | |
36 | + * Returns arguments for the jQuery.eauth() javascript function. | |
37 | + */ | |
38 | + public function getJsArguments(); | |
39 | + | |
40 | + | |
41 | + /** | |
42 | + * Sets {@link EAuth} application component | |
43 | + * | |
44 | + * @param EAuth $component the application auth component. | |
45 | + */ | |
46 | + public function setComponent($component); | |
47 | + | |
48 | + /** | |
49 | + * Returns the {@link EAuth} application component. | |
50 | + */ | |
51 | + public function getComponent(); | |
52 | + | |
53 | + | |
54 | + /** | |
55 | + * Sets redirect url after successful authorization. | |
56 | + * | |
57 | + * @param string $url url to redirect. | |
58 | + */ | |
59 | + public function setRedirectUrl($url); | |
60 | + | |
61 | + /** | |
62 | + * Returns the redirect url after successful authorization. | |
63 | + */ | |
64 | + public function getRedirectUrl(); | |
65 | + | |
66 | + | |
67 | + /** | |
68 | + * Sets redirect url after unsuccessful authorization (e.g. user canceled). | |
69 | + * | |
70 | + * @param string $url url to redirect. | |
71 | + */ | |
72 | + public function setCancelUrl($url); | |
73 | + | |
74 | + /** | |
75 | + * Returns the redirect url after unsuccessful authorization (e.g. user canceled). | |
76 | + */ | |
77 | + public function getCancelUrl(); | |
78 | + | |
79 | + | |
80 | + /** | |
81 | + * Authenticate the user. | |
82 | + */ | |
83 | + public function authenticate(); | |
84 | + | |
85 | + /** | |
86 | + * Whether user was successfuly authenticated. | |
87 | + */ | |
88 | + public function getIsAuthenticated(); | |
89 | + | |
90 | + | |
91 | + /** | |
92 | + * Redirect to the url. If url is null, {@link redirectUrl} will be used. | |
93 | + * | |
94 | + * @param string $url url to redirect. | |
95 | + */ | |
96 | + public function redirect($url = null); | |
97 | + | |
98 | + /** | |
99 | + * Redirect to the {@link cancelUrl} or simply close the popup window. | |
100 | + */ | |
101 | + public function cancel(); | |
102 | + | |
103 | + | |
104 | + /** | |
105 | + * Returns the user unique id. | |
106 | + */ | |
107 | + public function getId(); | |
108 | + | |
109 | + /** | |
110 | + * Returns the array that contains all available authorization attributes. | |
111 | + */ | |
112 | + public function getAttributes(); | |
113 | + | |
114 | + /** | |
115 | + * Returns the authorization attribute value. | |
116 | + * | |
117 | + * @param string $key the attribute name. | |
118 | + * @param mixed $default the default value. | |
119 | + */ | |
120 | + public function getAttribute($key, $default = null); | |
121 | + | |
122 | + /** | |
123 | + * Whether the authorization attribute exists. | |
124 | + * | |
125 | + * @param string $key the attribute name. | |
126 | + */ | |
127 | + public function hasAttribute($key); | |
128 | + | |
129 | +} | |
0 | 130 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/RedirectWidget.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * AuthRedirectWidget class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace common\modules\nodge\eauth\src\eauth; | |
11 | + | |
12 | +use \Yii; | |
13 | +use yii\helpers\ArrayHelper; | |
14 | + | |
15 | +/** | |
16 | + * The EAuthRedirectWidget widget displays the redirect page after returning from provider. | |
17 | + * | |
18 | + * @package application.extensions.eauth | |
19 | + */ | |
20 | +class RedirectWidget extends Widget | |
21 | +{ | |
22 | + | |
23 | + /** | |
24 | + * @var mixed the widget mode. Default to "login". | |
25 | + */ | |
26 | + public $url = null; | |
27 | + | |
28 | + /** | |
29 | + * @var boolean whether to use redirect inside the popup window. | |
30 | + */ | |
31 | + public $redirect = true; | |
32 | + | |
33 | + /** | |
34 | + * @var string | |
35 | + */ | |
36 | + public $view = 'redirect'; | |
37 | + | |
38 | + /** | |
39 | + * @var array | |
40 | + */ | |
41 | + public $params = []; | |
42 | + | |
43 | + /** | |
44 | + * Executes the widget. | |
45 | + */ | |
46 | + public function run() | |
47 | + { | |
48 | + echo $this->render($this->view, | |
49 | + ArrayHelper::merge([ | |
50 | + 'id' => $this->getId(), | |
51 | + 'url' => $this->url, | |
52 | + 'redirect' => $this->redirect, | |
53 | + ], $this->params) | |
54 | + ); | |
55 | + } | |
56 | +} | ... | ... |
1 | +<?php | |
2 | +/** | |
3 | + * ServiceBase class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace common\modules\nodge\eauth\src\eauth; | |
11 | + | |
12 | +use Yii; | |
13 | +use yii\base\Object; | |
14 | +use yii\helpers\Url; | |
15 | + | |
16 | +/** | |
17 | + * EAuthServiceBase is a base class for providers. | |
18 | + * | |
19 | + * @package application.extensions.eauth | |
20 | + */ | |
21 | +abstract class ServiceBase extends Object implements IAuthService | |
22 | +{ | |
23 | + | |
24 | + /** | |
25 | + * @var string the service name. | |
26 | + */ | |
27 | + protected $name; | |
28 | + | |
29 | + /** | |
30 | + * | |
31 | + * @var string the service title to display in views. | |
32 | + */ | |
33 | + protected $title; | |
34 | + | |
35 | + /** | |
36 | + * @var string the service type (e.g. OpenID, OAuth). | |
37 | + */ | |
38 | + protected $type; | |
39 | + | |
40 | + /** | |
41 | + * @var array arguments for the jQuery.eauth() javascript function. | |
42 | + */ | |
43 | + protected $jsArguments = []; | |
44 | + | |
45 | + /** | |
46 | + * @var array authorization attributes. | |
47 | + * @see getAttribute | |
48 | + * @see getItem | |
49 | + */ | |
50 | + protected $attributes = []; | |
51 | + | |
52 | + /** | |
53 | + * @var boolean whether user was successfuly authenticated. | |
54 | + * @see getIsAuthenticated | |
55 | + */ | |
56 | + protected $authenticated = false; | |
57 | + | |
58 | + /** | |
59 | + * @var boolean whether is attributes was fetched. | |
60 | + */ | |
61 | + private $fetched = false; | |
62 | + | |
63 | + /** | |
64 | + * @var EAuth the {@link EAuth} application component. | |
65 | + */ | |
66 | + private $component; | |
67 | + | |
68 | + /** | |
69 | + * @var string the redirect url after successful authorization. | |
70 | + */ | |
71 | + private $redirectUrl = ''; | |
72 | + | |
73 | + /** | |
74 | + * @var string the redirect url after unsuccessful authorization (e.g. user canceled). | |
75 | + */ | |
76 | + private $cancelUrl = ''; | |
77 | + | |
78 | + /** | |
79 | + * PHP getter magic method. | |
80 | + * This method is overridden so that service attributes can be accessed like properties. | |
81 | + * | |
82 | + * @param string $name property name. | |
83 | + * @return mixed property value. | |
84 | + * @see getAttribute | |
85 | + */ | |
86 | + public function __get($name) | |
87 | + { | |
88 | + if ($this->hasAttribute($name)) { | |
89 | + return $this->getAttribute($name); | |
90 | + } else { | |
91 | + return parent::__get($name); | |
92 | + } | |
93 | + } | |
94 | + | |
95 | + /** | |
96 | + * Checks if a attribute value is null. | |
97 | + * This method overrides the parent implementation by checking | |
98 | + * if the attribute is null or not. | |
99 | + * | |
100 | + * @param string $name the attribute name. | |
101 | + * @return boolean whether the attribute value is null. | |
102 | + */ | |
103 | + public function __isset($name) | |
104 | + { | |
105 | + if ($this->hasAttribute($name)) { | |
106 | + return true; | |
107 | + } else { | |
108 | + return parent::__isset($name); | |
109 | + } | |
110 | + } | |
111 | + | |
112 | + /** | |
113 | + * Initialize the component. | |
114 | + * Sets the default {@link redirectUrl} and {@link cancelUrl}. | |
115 | + */ | |
116 | + public function init() | |
117 | + { | |
118 | + parent::init(); | |
119 | + | |
120 | + $this->setRedirectUrl(Yii::$app->getUser()->getReturnUrl()); | |
121 | + | |
122 | + $service = Yii::$app->getRequest()->getQueryParam('service'); | |
123 | + $cancelUrl = Url::to(['', 'service' => $service], true); | |
124 | + | |
125 | + $this->setCancelUrl($cancelUrl); | |
126 | + } | |
127 | + | |
128 | + /** | |
129 | + * Returns service name(id). | |
130 | + * | |
131 | + * @return string the service name(id). | |
132 | + */ | |
133 | + public function getServiceName() | |
134 | + { | |
135 | + return $this->name; | |
136 | + } | |
137 | + | |
138 | + /** | |
139 | + * Returns service title. | |
140 | + * | |
141 | + * @return string the service title. | |
142 | + */ | |
143 | + public function getServiceTitle() | |
144 | + { | |
145 | + return Yii::t('eauth', $this->title); | |
146 | + } | |
147 | + | |
148 | + /** | |
149 | + * Returns service type (e.g. OpenID, OAuth). | |
150 | + * | |
151 | + * @return string the service type (e.g. OpenID, OAuth). | |
152 | + */ | |
153 | + public function getServiceType() | |
154 | + { | |
155 | + return $this->type; | |
156 | + } | |
157 | + | |
158 | + /** | |
159 | + * Returns arguments for the jQuery.eauth() javascript function. | |
160 | + * | |
161 | + * @return array the arguments for the jQuery.eauth() javascript function. | |
162 | + */ | |
163 | + public function getJsArguments() | |
164 | + { | |
165 | + return $this->jsArguments; | |
166 | + } | |
167 | + | |
168 | + /** | |
169 | + * Sets {@link EAuth} application component | |
170 | + * | |
171 | + * @param EAuth $component the application auth component. | |
172 | + */ | |
173 | + public function setComponent($component) | |
174 | + { | |
175 | + $this->component = $component; | |
176 | + } | |
177 | + | |
178 | + /** | |
179 | + * Returns the {@link EAuth} application component. | |
180 | + * | |
181 | + * @return EAuth the {@link EAuth} application component. | |
182 | + */ | |
183 | + public function getComponent() | |
184 | + { | |
185 | + return $this->component; | |
186 | + } | |
187 | + | |
188 | + /** | |
189 | + * Sets redirect url after successful authorization. | |
190 | + * | |
191 | + * @param string $url to redirect. | |
192 | + */ | |
193 | + public function setRedirectUrl($url) | |
194 | + { | |
195 | + $this->redirectUrl = $url; | |
196 | + } | |
197 | + | |
198 | + /** | |
199 | + * @return string the redirect url after successful authorization. | |
200 | + */ | |
201 | + public function getRedirectUrl() | |
202 | + { | |
203 | + return $this->redirectUrl; | |
204 | + } | |
205 | + | |
206 | + /** | |
207 | + * Sets redirect url after unsuccessful authorization (e.g. user canceled). | |
208 | + * | |
209 | + * @param string $url | |
210 | + */ | |
211 | + public function setCancelUrl($url) | |
212 | + { | |
213 | + $this->cancelUrl = $url; | |
214 | + } | |
215 | + | |
216 | + /** | |
217 | + * @return string the redirect url after unsuccessful authorization (e.g. user canceled). | |
218 | + */ | |
219 | + public function getCancelUrl() | |
220 | + { | |
221 | + return $this->cancelUrl; | |
222 | + } | |
223 | + | |
224 | + /** | |
225 | + * @param string $title | |
226 | + */ | |
227 | + public function setTitle($title) | |
228 | + { | |
229 | + $this->title = $title; | |
230 | + } | |
231 | + | |
232 | + /** | |
233 | + * Authenticate the user. | |
234 | + * | |
235 | + * @return boolean whether user was successfuly authenticated. | |
236 | + */ | |
237 | + public function authenticate() | |
238 | + { | |
239 | + return $this->getIsAuthenticated(); | |
240 | + } | |
241 | + | |
242 | + /** | |
243 | + * Whether user was successfuly authenticated. | |
244 | + * | |
245 | + * @return boolean whether user was successfuly authenticated. | |
246 | + */ | |
247 | + public function getIsAuthenticated() | |
248 | + { | |
249 | + return $this->authenticated; | |
250 | + } | |
251 | + | |
252 | + /** | |
253 | + * Redirect to the url. If url is null, {@link redirectUrl} will be used. | |
254 | + * | |
255 | + * @param string $url url to redirect. | |
256 | + * @param array $params | |
257 | + */ | |
258 | + public function redirect($url = null, $params = []) | |
259 | + { | |
260 | + $this->component->redirect(isset($url) ? $url : $this->redirectUrl, true, $params); | |
261 | + } | |
262 | + | |
263 | + /** | |
264 | + * Redirect to the {@link cancelUrl} or simply close the popup window. | |
265 | + */ | |
266 | + public function cancel($url = null) | |
267 | + { | |
268 | + $this->component->redirect(isset($url) ? $url : $this->cancelUrl, !$this->component->popup); | |
269 | + } | |
270 | + | |
271 | + /** | |
272 | + * Fetch attributes array. | |
273 | + * | |
274 | + * @return boolean whether the attributes was successfully fetched. | |
275 | + */ | |
276 | + protected function fetchAttributes() | |
277 | + { | |
278 | + return true; | |
279 | + } | |
280 | + | |
281 | + /** | |
282 | + * Fetch attributes array. | |
283 | + * This function is internally used to handle fetched state. | |
284 | + */ | |
285 | + protected function _fetchAttributes() | |
286 | + { | |
287 | + if (!$this->fetched) { | |
288 | + $this->fetched = true; | |
289 | + $result = $this->fetchAttributes(); | |
290 | + if (isset($result)) { | |
291 | + $this->fetched = $result; | |
292 | + } | |
293 | + } | |
294 | + } | |
295 | + | |
296 | + /** | |
297 | + * Returns the user unique id. | |
298 | + * | |
299 | + * @return mixed the user id. | |
300 | + */ | |
301 | + public function getId() | |
302 | + { | |
303 | + $this->_fetchAttributes(); | |
304 | + return $this->attributes['id']; | |
305 | + } | |
306 | + | |
307 | + /** | |
308 | + * Returns the array that contains all available authorization attributes. | |
309 | + * | |
310 | + * @return array the attributes. | |
311 | + */ | |
312 | + public function getAttributes() | |
313 | + { | |
314 | + $this->_fetchAttributes(); | |
315 | + $attributes = []; | |
316 | + foreach ($this->attributes as $key => $val) { | |
317 | + $attributes[$key] = $this->getAttribute($key); | |
318 | + } | |
319 | + return $attributes; | |
320 | + } | |
321 | + | |
322 | + /** | |
323 | + * Returns the authorization attribute value. | |
324 | + * | |
325 | + * @param string $key the attribute name. | |
326 | + * @param mixed $default the default value. | |
327 | + * @return mixed the attribute value. | |
328 | + */ | |
329 | + public function getAttribute($key, $default = null) | |
330 | + { | |
331 | + $this->_fetchAttributes(); | |
332 | + $getter = 'get' . $key; | |
333 | + if (method_exists($this, $getter)) { | |
334 | + return $this->$getter(); | |
335 | + } else { | |
336 | + return isset($this->attributes[$key]) ? $this->attributes[$key] : $default; | |
337 | + } | |
338 | + } | |
339 | + | |
340 | + /** | |
341 | + * Whether the authorization attribute exists. | |
342 | + * | |
343 | + * @param string $key the attribute name. | |
344 | + * @return boolean true if attribute exists, false otherwise. | |
345 | + */ | |
346 | + public function hasAttribute($key) | |
347 | + { | |
348 | + $this->_fetchAttributes(); | |
349 | + return isset($this->attributes[$key]); | |
350 | + } | |
351 | + | |
352 | + /** | |
353 | + * @return bool | |
354 | + */ | |
355 | + public function getIsInsidePopup() | |
356 | + { | |
357 | + return isset($_GET['js']); | |
358 | + } | |
359 | +} | ... | ... |
1 | +<?php | |
2 | +/** | |
3 | + * Widget class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace common\modules\nodge\eauth\src\eauth; | |
11 | + | |
12 | +use Yii; | |
13 | + | |
14 | +/** | |
15 | + * The EAuthWidget widget prints buttons to authenticate user with OpenID and OAuth providers. | |
16 | + * | |
17 | + * @package application.extensions.eauth | |
18 | + */ | |
19 | +class Widget extends \yii\base\Widget | |
20 | +{ | |
21 | + | |
22 | + /** | |
23 | + * @var string EAuth component name. | |
24 | + */ | |
25 | + public $component = 'eauth'; | |
26 | + | |
27 | + /** | |
28 | + * @var array the services. | |
29 | + * @see EAuth::getServices() | |
30 | + */ | |
31 | + public $services = null; | |
32 | + | |
33 | + /** | |
34 | + * @var array predefined services. If null then use all services. Default is null. | |
35 | + */ | |
36 | + public $predefinedServices = null; | |
37 | + | |
38 | + /** | |
39 | + * @var boolean whether to use popup window for authorization dialog. Javascript required. | |
40 | + */ | |
41 | + public $popup = null; | |
42 | + | |
43 | + /** | |
44 | + * @var string the action to use for dialog destination. Default: the current route. | |
45 | + */ | |
46 | + public $action = null; | |
47 | + | |
48 | + /** | |
49 | + * @var boolean include the CSS file. Default is true. | |
50 | + * If this is set false, you are responsible to explicitly include the necessary CSS file in your page. | |
51 | + */ | |
52 | + public $assetBundle = 'nodge\\eauth\\assets\\WidgetAssetBundle'; | |
53 | + | |
54 | + /** | |
55 | + * Initializes the widget. | |
56 | + * This method is called by {@link CBaseController::createWidget} | |
57 | + * and {@link CBaseController::beginWidget} after the widget's | |
58 | + * properties have been initialized. | |
59 | + */ | |
60 | + public function init() | |
61 | + { | |
62 | + parent::init(); | |
63 | + | |
64 | + // EAuth component | |
65 | + /** @var $component \nodge\eauth\EAuth */ | |
66 | + $component = Yii::$app->get($this->component); | |
67 | + | |
68 | + // Some default properties from component configuration | |
69 | + if (!isset($this->services)) { | |
70 | + $this->services = $component->getServices(); | |
71 | + } | |
72 | + | |
73 | + if (is_array($this->predefinedServices)) { | |
74 | + $_services = []; | |
75 | + foreach ($this->predefinedServices as $_serviceName) { | |
76 | + if (isset($this->services[$_serviceName])) { | |
77 | + $_services[$_serviceName] = $this->services[$_serviceName]; | |
78 | + } | |
79 | + } | |
80 | + $this->services = $_services; | |
81 | + } | |
82 | + | |
83 | + if (!isset($this->popup)) { | |
84 | + $this->popup = $component->popup; | |
85 | + } | |
86 | + | |
87 | + // Set the current route, if it is not set. | |
88 | + if (!isset($this->action)) { | |
89 | + $this->action = '/' . Yii::$app->requestedRoute; | |
90 | + } | |
91 | + } | |
92 | + | |
93 | + /** | |
94 | + * Executes the widget. | |
95 | + * This method is called by {@link CBaseController::endWidget}. | |
96 | + */ | |
97 | + public function run() | |
98 | + { | |
99 | + parent::run(); | |
100 | + echo $this->render('widget', [ | |
101 | + 'id' => $this->getId(), | |
102 | + 'services' => $this->services, | |
103 | + 'action' => $this->action, | |
104 | + 'popup' => $this->popup, | |
105 | + 'assetBundle' => $this->assetBundle, | |
106 | + ]); | |
107 | + } | |
108 | +} | ... | ... |
common/components/nodge/eauth/src/assets/WidgetAssetBundle.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * @link http://www.yiiframework.com/ | |
4 | + * @copyright Copyright (c) 2008 Yii Software LLC | |
5 | + * @license http://www.yiiframework.com/license/ | |
6 | + */ | |
7 | + | |
8 | +namespace nodge\eauth\assets; | |
9 | + | |
10 | +use yii\web\AssetBundle; | |
11 | + | |
12 | +/** | |
13 | + * @author Qiang Xue <qiang.xue@gmail.com> | |
14 | + * @since 2.0 | |
15 | + */ | |
16 | +class WidgetAssetBundle extends AssetBundle | |
17 | +{ | |
18 | + public $sourcePath = '@eauth/assets'; | |
19 | + public $css = [ | |
20 | + 'css/eauth.css', | |
21 | + ]; | |
22 | + public $js = [ | |
23 | + 'js/eauth.js', | |
24 | + ]; | |
25 | + public $depends = [ | |
26 | + 'yii\web\JqueryAsset', | |
27 | + ]; | |
28 | +} | ... | ... |
common/components/nodge/eauth/src/assets/css/eauth.css
0 → 100644
1 | + | |
2 | +.eauth { | |
3 | + overflow: hidden; | |
4 | +} | |
5 | + | |
6 | +.eauth-list { | |
7 | + margin: -1em 0 0; | |
8 | + padding: 0; | |
9 | + list-style: none; | |
10 | +} | |
11 | + | |
12 | +.eauth-service { | |
13 | + display: inline-block; | |
14 | + vertical-align: top; | |
15 | + margin: 1em 1em 0 0; | |
16 | +} | |
17 | + | |
18 | +.eauth-service-link { | |
19 | + position: relative; | |
20 | + display: block; | |
21 | + width: 60px; | |
22 | + padding-top: 34px; | |
23 | + text-align: center; | |
24 | +} | |
25 | + | |
26 | +.eauth-service-link:before, | |
27 | +.eauth-service-link:after { | |
28 | + content: ''; | |
29 | + position: absolute; | |
30 | + top: 0; | |
31 | + left: 50%; | |
32 | + width: 32px; | |
33 | + height: 32px; | |
34 | + margin-left: -16px; | |
35 | + background: url("../images/auth.png") 0 0 no-repeat; | |
36 | +} | |
37 | + | |
38 | +.eauth-service-link:after { | |
39 | + display: none; | |
40 | +} | |
41 | + | |
42 | +.eauth-service-link:hover:after { | |
43 | + display: block; | |
44 | +} | |
45 | + | |
46 | +/* --- Services --- */ | |
47 | + | |
48 | +.eauth-service-id-google_oauth .eauth-service-link:before { | |
49 | + background-position: 0 -34px; | |
50 | +} | |
51 | + | |
52 | +.eauth-service-id-yandex_oauth .eauth-service-link:before { | |
53 | + background-position: 0 -102px; | |
54 | +} | |
55 | + | |
56 | +.eauth-service-id-twitter .eauth-service-link:before { | |
57 | + background-position: 0 -68px; | |
58 | +} | |
59 | + | |
60 | +.eauth-service-id-vkontakte .eauth-service-link:before { | |
61 | + background-position: 0 -136px; | |
62 | +} | |
63 | + | |
64 | +.eauth-service-id-facebook .eauth-service-link:before { | |
65 | + background-position: 0 -170px; | |
66 | +} | |
67 | + | |
68 | +.eauth-service-id-mailru .eauth-service-link:before { | |
69 | + background-position: 0 -204px; | |
70 | +} | |
71 | + | |
72 | +.eauth-service-id-moikrug .eauth-service-link:before { | |
73 | + background-position: 0 -238px; | |
74 | +} | |
75 | + | |
76 | +.eauth-service-id-odnoklassniki .eauth-service-link:before { | |
77 | + background-position: 0 -272px; | |
78 | +} | |
79 | + | |
80 | +.eauth-service-id-linkedin .eauth-service-link:before, | |
81 | +.eauth-service-id-linkedin_oauth2 .eauth-service-link:before { | |
82 | + background-position: 0 -306px; | |
83 | +} | |
84 | + | |
85 | +.eauth-service-id-github .eauth-service-link:before { | |
86 | + background-position: 0 -340px; | |
87 | +} | |
88 | + | |
89 | +.eauth-service-id-live .eauth-service-link:before { | |
90 | + background-position: 0 -372px; | |
91 | +} | |
92 | + | |
93 | +.eauth-service-id-yahoo .eauth-service-link:before { | |
94 | + background-position: 0 -406px; | |
95 | +} | |
96 | + | |
97 | +.eauth-service-id-steam .eauth-service-link:before { | |
98 | + background-position: 0 -440px; | |
99 | +} | |
100 | + | |
101 | +.eauth-service-id-instagram .eauth-service-link:before { | |
102 | + background-position: 0 -474px; | |
103 | +} | |
0 | 104 | \ No newline at end of file | ... | ... |
19 KB
6.18 KB
common/components/nodge/eauth/src/assets/js/eauth.js
0 → 100644
1 | +/* | |
2 | + * Yii EAuth extension. | |
3 | + * @author Maxim Zemskov | |
4 | + * @link http://github.com/Nodge/yii2-eauth/ | |
5 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
6 | + */ | |
7 | +(function ($) { | |
8 | + var popup, | |
9 | + defaults = { | |
10 | + popup: { | |
11 | + width: 450, | |
12 | + height: 380 | |
13 | + } | |
14 | + }; | |
15 | + | |
16 | + function openPopup(options) { | |
17 | + if (popup != null) | |
18 | + popup.close(); | |
19 | + | |
20 | + var redirect_uri, | |
21 | + url = redirect_uri = options.url; | |
22 | + | |
23 | + url += url.indexOf('?') >= 0 ? '&' : '?'; | |
24 | + if (url.indexOf('redirect_uri=') === -1) | |
25 | + url += 'redirect_uri=' + encodeURIComponent(redirect_uri) + '&'; | |
26 | + url += 'js='; | |
27 | + | |
28 | + var centerWidth = (window.screen.width - options.popup.width) / 2, | |
29 | + centerHeight = (window.screen.height - options.popup.height) / 2; | |
30 | + | |
31 | + popup = window.open(url, "yii_eauth_popup", "width=" + options.popup.width + ",height=" + options.popup.height + ",left=" + centerWidth + ",top=" + centerHeight + ",resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=yes"); | |
32 | + popup.focus(); | |
33 | + } | |
34 | + | |
35 | + $.fn.eauth = function (services) { | |
36 | + $(this).on('click', '[data-eauth-service]', function (e) { | |
37 | + e.preventDefault(); | |
38 | + | |
39 | + var service = $(this).data('eauthService'), | |
40 | + options = $.extend({ | |
41 | + url: this.href | |
42 | + }, defaults, services[service]); | |
43 | + | |
44 | + openPopup(options); | |
45 | + }); | |
46 | + }; | |
47 | +})(jQuery); | ... | ... |
common/components/nodge/eauth/src/messages/blank/eauth.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +return [ | |
4 | + 'Undefined service name: {service}.' => '{service}', | |
5 | + 'Invalid response http code: {code}.' => '{code}', | |
6 | + 'Invalid response format.' => '', | |
7 | + 'Unable to complete the authentication because the required data was not received.' => '{provider}', | |
8 | + 'Unable to complete the request because the user was not authenticated.' => '', | |
9 | + | |
10 | + 'Redirecting back to the application...' => '', | |
11 | + 'Click here to return to the application.' => '', | |
12 | + | |
13 | + 'Google' => 'Google', | |
14 | + 'Twitter' => 'Twitter', | |
15 | + 'Yandex' => 'Yandex', | |
16 | + 'VK.com' => 'VK.com', | |
17 | + 'Facebook' => 'Facebook', | |
18 | + 'Mail.ru' => 'Mail.ru', | |
19 | + 'Moikrug.ru' => 'Moikrug.ru', | |
20 | + 'Odnoklassniki' => 'Odnoklassniki', | |
21 | + 'LinkedIn' => 'LinkedIn', | |
22 | + 'GitHub' => 'GitHub', | |
23 | +]; | |
0 | 24 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/messages/de/eauth.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +return [ | |
4 | + 'Undefined service name: {service}.' => 'Undefinierter Servicename: {service}', | |
5 | + 'Invalid response http code: {code}.' => 'Ungültiger HTTP Code: {code}', | |
6 | + 'Invalid response format.' => 'Ungültiges Antwortformat.', | |
7 | + 'Unable to complete the authentication because the required data was not received.' => 'Die Authentifizierung konnte nicht durchgeführt werden, da keine Daten empfangen wurden.', | |
8 | + 'Unable to complete the request because the user was not authenticated.' => 'Die Anfrage konnte nicht durchgeführt werden, da der Nutzer nicht authentifiziert war.', | |
9 | + | |
10 | + 'Redirecting back to the application...' => 'Weiterleitung zur Applikation...', | |
11 | + 'Click here to return to the application.' => 'Klicke hier um zur Applikation zurückzukehren', | |
12 | + | |
13 | + 'Google' => 'Google', | |
14 | + 'Twitter' => 'Twitter', | |
15 | + 'Yandex' => 'Yandex', | |
16 | + 'VK.com' => 'VK.com', | |
17 | + 'Facebook' => 'Facebook', | |
18 | + 'Mail.ru' => 'Mail.ru', | |
19 | + 'Moikrug.ru' => 'Moikrug.ru', | |
20 | + 'Odnoklassniki' => 'Odnoklassniki', | |
21 | + 'LinkedIn' => 'LinkedIn', | |
22 | + 'GitHub' => 'GitHub', | |
23 | +]; | |
0 | 24 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/messages/en/eauth.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +return [ | |
4 | + 'Undefined service name: {service}.' => 'Undefined service name: {service}.', | |
5 | + 'Invalid response http code: {code}.' => 'Invalid response http code: {code}.', | |
6 | + 'Invalid response format.' => 'Invalid response format.', | |
7 | + 'Unable to complete the authentication because the required data was not received.' => 'Unable to complete the authentication because the required data was not received.', | |
8 | + 'Unable to complete the request because the user was not authenticated.' => 'Unable to complete the request because the user was not authenticated.', | |
9 | + | |
10 | + 'Redirecting back to the application...' => 'Redirecting back to the application...', | |
11 | + 'Click here to return to the application.' => 'Click here to return to the application.', | |
12 | + | |
13 | + 'Google' => 'Google', | |
14 | + 'Twitter' => 'Twitter', | |
15 | + 'Yandex' => 'Yandex', | |
16 | + 'VK.com' => 'VK.com', | |
17 | + 'Facebook' => 'Facebook', | |
18 | + 'Mail.ru' => 'Mail.ru', | |
19 | + 'Moikrug.ru' => 'Moikrug.ru', | |
20 | + 'Odnoklassniki' => 'Odnoklassniki', | |
21 | + 'LinkedIn' => 'LinkedIn', | |
22 | + 'GitHub' => 'GitHub', | |
23 | +]; | |
0 | 24 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/messages/ru/eauth.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +return [ | |
4 | + 'Undefined service name: {service}.' => 'Авторизация с помощью {service} не поддерживается.', | |
5 | + 'Invalid response http code: {code}.' => 'Неверный ответ от сервера авторизации: {code}.', | |
6 | + 'Invalid response format.' => 'Сервер авторизации вернул данные в неправильном формате.', | |
7 | + 'Unable to complete the authentication because the required data was not received.' => 'Невозможно завершить авторизацию пользователя, потому что {provider} не передает необходимую информацию.', | |
8 | + 'Unable to complete the request because the user was not authenticated.' => 'Невозможно выполнить защищенный запрос, потому что пользователь не был авторизован.', | |
9 | + | |
10 | + 'Redirecting back to the application...' => 'Перенаправление обратно в приложение...', | |
11 | + 'Click here to return to the application.' => 'Нажмите сюда чтобы вернуться обратно в приложение.', | |
12 | + | |
13 | + 'Google' => 'Google', | |
14 | + 'Twitter' => 'Twitter', | |
15 | + 'Yandex' => 'Яндекс', | |
16 | + 'VK.com' => 'ВКонтакте', | |
17 | + 'Facebook' => 'Facebook', | |
18 | + 'Mail.ru' => 'Mail.ru', | |
19 | + 'Moikrug.ru' => 'Мой круг', | |
20 | + 'Odnoklassniki' => 'Одноклассники', | |
21 | + 'LinkedIn' => 'LinkedIn', | |
22 | + 'GitHub' => 'GitHub', | |
23 | +]; | |
0 | 24 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/messages/uk/eauth.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +return [ | |
4 | + 'Undefined service name: {service}.' => 'Авторизація за допомогою {service} не підтримується.', | |
5 | + 'Invalid response http code: {code}.' => 'Невірна відповідь від сервера авторизації: {code}.', | |
6 | + 'Invalid response format.' => 'Сервер авторизації повернув данні в невірному форматі.', | |
7 | + 'Unable to complete the authentication because the required data was not received.' => 'Неможливо завершити авторизацію користувача, так як {provider} не передає необхідну інформацію.', | |
8 | + 'Unable to complete the request because the user was not authenticated.' => 'Неможливо виконати захищений запит, так як користувач не був авторизований.', | |
9 | + | |
10 | + 'Redirecting back to the application...' => 'Redirecting back to the application...', | |
11 | + 'Click here to return to the application.' => 'Click here to return to the application.', | |
12 | + | |
13 | + 'Google' => 'Google', | |
14 | + 'Twitter' => 'Twitter', | |
15 | + 'Yandex' => 'Яндекс', | |
16 | + 'VK.com' => 'ВКонтакте', | |
17 | + 'Facebook' => 'Facebook', | |
18 | + 'Mail.ru' => 'Mail.ru', | |
19 | + 'Moikrug.ru' => 'Мой круг', | |
20 | + 'Odnoklassniki' => 'Одноклассники', | |
21 | + 'LinkedIn' => 'LinkedIn', | |
22 | + 'GitHub' => 'GitHub', | |
23 | +]; | ... | ... |
common/components/nodge/eauth/src/oauth/HttpClient.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * HttpClient class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\oauth; | |
11 | + | |
12 | +use Yii; | |
13 | +use OAuth\Common\Http\Client\AbstractClient; | |
14 | +use OAuth\Common\Http\Exception\TokenResponseException; | |
15 | +use OAuth\Common\Http\Uri\UriInterface; | |
16 | + | |
17 | +/** | |
18 | + * Client implementation for cURL | |
19 | + */ | |
20 | +class HttpClient extends AbstractClient | |
21 | +{ | |
22 | + | |
23 | + /** | |
24 | + * If true, explicitly sets cURL to use SSL version 3. Use this if cURL | |
25 | + * compiles with GnuTLS SSL. | |
26 | + * | |
27 | + * @var bool | |
28 | + */ | |
29 | + protected $forceSSL3 = false; | |
30 | + | |
31 | + /** | |
32 | + * If true and you are working in safe_mode environment or inside open_basedir | |
33 | + * it will use streams instead of curl. | |
34 | + * | |
35 | + * @var bool | |
36 | + */ | |
37 | + protected $useStreamsFallback = false; | |
38 | + | |
39 | + /** | |
40 | + * @var UriInterface | |
41 | + */ | |
42 | + protected $endpoint; | |
43 | + | |
44 | + /** | |
45 | + * @var mixed | |
46 | + */ | |
47 | + protected $requestBody; | |
48 | + | |
49 | + /** | |
50 | + * @var array | |
51 | + */ | |
52 | + protected $extraHeaders = []; | |
53 | + | |
54 | + /** | |
55 | + * @var string | |
56 | + */ | |
57 | + protected $method = 'POST'; | |
58 | + | |
59 | + /** | |
60 | + * @param bool $force | |
61 | + */ | |
62 | + public function setForceSSL3($force) | |
63 | + { | |
64 | + $this->forceSSL3 = $force; | |
65 | + } | |
66 | + | |
67 | + /** | |
68 | + * @return boolean | |
69 | + */ | |
70 | + public function getForceSSL3() | |
71 | + { | |
72 | + return $this->forceSSL3; | |
73 | + } | |
74 | + | |
75 | + /** | |
76 | + * @param bool $useStreamsFallback | |
77 | + */ | |
78 | + public function setUseStreamsFallback($useStreamsFallback) | |
79 | + { | |
80 | + $this->useStreamsFallback = $useStreamsFallback; | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * @return bool | |
85 | + */ | |
86 | + public function getUseStreamsFallback() | |
87 | + { | |
88 | + return $this->useStreamsFallback; | |
89 | + } | |
90 | + | |
91 | + /** | |
92 | + * Any implementing HTTP providers should send a request to the provided endpoint with the parameters. | |
93 | + * They should return, in string form, the response body and throw an exception on error. | |
94 | + * | |
95 | + * @param UriInterface $endpoint | |
96 | + * @param mixed $requestBody | |
97 | + * @param array $extraHeaders | |
98 | + * @param string $method | |
99 | + * @return string | |
100 | + */ | |
101 | + public function retrieveResponse(UriInterface $endpoint, $requestBody, array $extraHeaders = [], $method = 'POST') | |
102 | + { | |
103 | + $this->endpoint = $endpoint; | |
104 | + $this->requestBody = $requestBody; | |
105 | + $this->extraHeaders = $extraHeaders; | |
106 | + $this->method = $method; | |
107 | + | |
108 | + if ($this->useStreamsFallback && !$this->allowFollowLocation()) { | |
109 | + return $this->streams(); | |
110 | + } | |
111 | + | |
112 | + return $this->curl(); | |
113 | + } | |
114 | + | |
115 | + /** | |
116 | + * @return bool | |
117 | + */ | |
118 | + protected function allowFollowLocation() | |
119 | + { | |
120 | + return !ini_get('safe_mode') && !ini_get('open_basedir'); | |
121 | + } | |
122 | + | |
123 | + /** | |
124 | + * | |
125 | + */ | |
126 | + protected function prepareRequest() | |
127 | + { | |
128 | + $this->method = strtoupper($this->method); | |
129 | + $this->normalizeHeaders($this->extraHeaders); | |
130 | + | |
131 | + if ($this->method === 'GET' && !empty($this->requestBody)) { | |
132 | + throw new \InvalidArgumentException('No body expected for "GET" request.'); | |
133 | + } | |
134 | + | |
135 | + if (!isset($this->extraHeaders['Content-type']) && $this->method === 'POST' && is_array($this->requestBody)) { | |
136 | + $this->extraHeaders['Content-type'] = 'Content-type: application/x-www-form-urlencoded'; | |
137 | + } | |
138 | + | |
139 | + // Some of services requires User-Agent header (e.g. GitHub) | |
140 | + if (!isset($this->extraHeaders['User-Agent'])) { | |
141 | + $this->extraHeaders['User-Agent'] = 'User-Agent: yii2-eauth'; | |
142 | + } | |
143 | + | |
144 | + $this->extraHeaders['Host'] = 'Host: ' . $this->endpoint->getHost(); | |
145 | + $this->extraHeaders['Connection'] = 'Connection: close'; | |
146 | + | |
147 | + if (YII_DEBUG) { | |
148 | + Yii::trace('EAuth http request: ' . PHP_EOL . var_export([ | |
149 | + 'url' => $this->endpoint->getAbsoluteUri(), | |
150 | + 'method' => $this->method, | |
151 | + 'headers' => $this->extraHeaders, | |
152 | + 'body' => $this->requestBody, | |
153 | + ], true), __NAMESPACE__); | |
154 | + } | |
155 | + | |
156 | + if (is_array($this->requestBody)) { | |
157 | + $this->requestBody = http_build_query($this->requestBody, null, '&'); | |
158 | + } | |
159 | + } | |
160 | + | |
161 | + /** | |
162 | + * @return string | |
163 | + * @throws TokenResponseException | |
164 | + */ | |
165 | + protected function curl() | |
166 | + { | |
167 | + $this->prepareRequest(); | |
168 | + | |
169 | + $ch = curl_init(); | |
170 | + curl_setopt($ch, CURLOPT_URL, $this->endpoint->getAbsoluteUri()); | |
171 | + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); | |
172 | + | |
173 | + if ($this->method === 'POST' || $this->method === 'PUT') { | |
174 | + if ($this->method === 'PUT') { | |
175 | + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); | |
176 | + } else { | |
177 | + curl_setopt($ch, CURLOPT_POST, true); | |
178 | + } | |
179 | + curl_setopt($ch, CURLOPT_POSTFIELDS, $this->requestBody); | |
180 | + } else { | |
181 | + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->method); | |
182 | + } | |
183 | + | |
184 | + if ($this->allowFollowLocation() && $this->maxRedirects > 0) { | |
185 | + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); | |
186 | + curl_setopt($ch, CURLOPT_MAXREDIRS, $this->maxRedirects); | |
187 | + } | |
188 | + | |
189 | + curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); | |
190 | + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
191 | + curl_setopt($ch, CURLOPT_HEADER, false); | |
192 | + curl_setopt($ch, CURLOPT_HTTPHEADER, $this->extraHeaders); | |
193 | + | |
194 | + if ($this->forceSSL3) { | |
195 | + curl_setopt($ch, CURLOPT_SSLVERSION, 3); | |
196 | + } | |
197 | + | |
198 | + $response = curl_exec($ch); | |
199 | + $responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
200 | + | |
201 | + if (YII_DEBUG) { | |
202 | + Yii::trace('EAuth http response: ' . PHP_EOL . var_export($response, true), __NAMESPACE__); | |
203 | + } | |
204 | + | |
205 | + if (false === $response) { | |
206 | + $errNo = curl_errno($ch); | |
207 | + $errStr = curl_error($ch); | |
208 | + curl_close($ch); | |
209 | + | |
210 | + if (empty($errStr)) { | |
211 | + $errStr = 'Failed to request resource.'; | |
212 | + } else { | |
213 | + $errStr = 'cURL Error # ' . $errNo . ': ' . $errStr; | |
214 | + } | |
215 | + | |
216 | + Yii::error('EAuth curl error (' . $responseCode . '): ' . $errStr, __NAMESPACE__); | |
217 | + throw new TokenResponseException($errStr, $responseCode); | |
218 | + } | |
219 | + | |
220 | + curl_close($ch); | |
221 | + | |
222 | + return $response; | |
223 | + } | |
224 | + | |
225 | + /** | |
226 | + * @return string | |
227 | + * @throws TokenResponseException | |
228 | + */ | |
229 | + protected function streams() | |
230 | + { | |
231 | + $this->prepareRequest(); | |
232 | + | |
233 | + $context = stream_context_create([ | |
234 | + 'http' => [ | |
235 | + 'method' => $this->method, | |
236 | + 'header' => array_values($this->extraHeaders), | |
237 | + 'content' => $this->requestBody, | |
238 | + 'protocol_version' => '1.1', | |
239 | + 'user_agent' => 'Yii2 EAuth Client', | |
240 | + 'max_redirects' => $this->maxRedirects, | |
241 | + 'timeout' => $this->timeout, | |
242 | + ], | |
243 | + ]); | |
244 | + | |
245 | + $level = error_reporting(0); | |
246 | + $response = file_get_contents($this->endpoint->getAbsoluteUri(), false, $context); | |
247 | + error_reporting($level); | |
248 | + | |
249 | + if (YII_DEBUG) { | |
250 | + Yii::trace('EAuth http response: ' . PHP_EOL . var_export($response, true), __NAMESPACE__); | |
251 | + } | |
252 | + | |
253 | + if (false === $response) { | |
254 | + $lastError = error_get_last(); | |
255 | + | |
256 | + if (is_null($lastError)) { | |
257 | + $errStr = 'Failed to request resource.'; | |
258 | + } else { | |
259 | + $errStr = $lastError['message']; | |
260 | + } | |
261 | + | |
262 | + Yii::error('EAuth streams error: ' . $errStr, __NAMESPACE__); | |
263 | + throw new TokenResponseException($errStr); | |
264 | + } | |
265 | + | |
266 | + return $response; | |
267 | + } | |
268 | + | |
269 | +} | ... | ... |
common/components/nodge/eauth/src/oauth/ServiceBase.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * OAuthService class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\oauth; | |
11 | + | |
12 | +use Yii; | |
13 | +use OAuth\Common\Http\Uri\Uri; | |
14 | +use OAuth\Common\Http\Client\ClientInterface; | |
15 | +use OAuth\Common\Token\TokenInterface; | |
16 | +use OAuth\Common\Storage\TokenStorageInterface; | |
17 | +use nodge\eauth\EAuth; | |
18 | +use nodge\eauth\IAuthService; | |
19 | +use nodge\eauth\ErrorException; | |
20 | +use yii\helpers\ArrayHelper; | |
21 | +use yii\helpers\Url; | |
22 | + | |
23 | +/** | |
24 | + * EOAuthService is a base class for all OAuth providers. | |
25 | + * | |
26 | + * @package application.extensions.eauth | |
27 | + */ | |
28 | +abstract class ServiceBase extends \nodge\eauth\ServiceBase implements IAuthService | |
29 | +{ | |
30 | + | |
31 | + /** | |
32 | + * @var string Base url for API calls. | |
33 | + */ | |
34 | + protected $baseApiUrl; | |
35 | + | |
36 | + /** | |
37 | + * @var int Default token lifetime. Used when service wont provide expires_in param. | |
38 | + */ | |
39 | + protected $tokenDefaultLifetime = null; | |
40 | + | |
41 | + /** | |
42 | + * @var array TokenStorage class. Null means default value from EAuth component config. | |
43 | + */ | |
44 | + protected $tokenStorage; | |
45 | + | |
46 | + /** | |
47 | + * @var array HttpClient class. Null means default value from EAuth component config. | |
48 | + */ | |
49 | + protected $httpClient; | |
50 | + | |
51 | + /** | |
52 | + * @var TokenStorageInterface | |
53 | + */ | |
54 | + private $_tokenStorage; | |
55 | + | |
56 | + /** | |
57 | + * @var ClientInterface | |
58 | + */ | |
59 | + private $_httpClient; | |
60 | + | |
61 | + /** | |
62 | + * Initialize the component. | |
63 | + * | |
64 | + * @param EAuth $component the component instance. | |
65 | + * @param array $options properties initialization. | |
66 | + */ | |
67 | +// public function init($component, $options = []) { | |
68 | +// parent::init($component, $options); | |
69 | +// } | |
70 | + | |
71 | + /** | |
72 | + * For OAuth we can check existing access token. | |
73 | + * Useful for API calls. | |
74 | + * | |
75 | + * @return bool | |
76 | + * @throws ErrorException | |
77 | + */ | |
78 | + public function getIsAuthenticated() | |
79 | + { | |
80 | + if (!$this->authenticated) { | |
81 | + try { | |
82 | + $proxy = $this->getProxy(); | |
83 | + $this->authenticated = $proxy->hasValidAccessToken(); | |
84 | + } catch (\OAuth\Common\Exception\Exception $e) { | |
85 | + throw new ErrorException($e->getMessage(), $e->getCode(), 1, $e->getFile(), $e->getLine(), $e); | |
86 | + } | |
87 | + } | |
88 | + return parent::getIsAuthenticated(); | |
89 | + } | |
90 | + | |
91 | + /** | |
92 | + * @return \nodge\eauth\oauth1\ServiceProxy|\nodge\eauth\oauth2\ServiceProxy | |
93 | + */ | |
94 | + abstract protected function getProxy(); | |
95 | + | |
96 | + /** | |
97 | + * @return string the current url | |
98 | + */ | |
99 | + protected function getCallbackUrl() | |
100 | + { | |
101 | + return Url::to('', true); | |
102 | + } | |
103 | + | |
104 | + /** | |
105 | + * @param array $config | |
106 | + */ | |
107 | + public function setTokenStorage(array $config) | |
108 | + { | |
109 | + $this->tokenStorage = ArrayHelper::merge($this->tokenStorage, $config); | |
110 | + } | |
111 | + | |
112 | + /** | |
113 | + * @return TokenStorageInterface | |
114 | + */ | |
115 | + protected function getTokenStorage() | |
116 | + { | |
117 | + if (!isset($this->_tokenStorage)) { | |
118 | + $config = $this->tokenStorage; | |
119 | + if (!isset($config)) { | |
120 | + $config = $this->getComponent()->getTokenStorage(); | |
121 | + } | |
122 | + $this->_tokenStorage = Yii::createObject($config); | |
123 | + } | |
124 | + return $this->_tokenStorage; | |
125 | + } | |
126 | + | |
127 | + /** | |
128 | + * @param array $config | |
129 | + */ | |
130 | + public function setHttpClient(array $config) | |
131 | + { | |
132 | + $this->httpClient = ArrayHelper::merge($this->httpClient, $config); | |
133 | + } | |
134 | + | |
135 | + /** | |
136 | + * @return ClientInterface | |
137 | + */ | |
138 | + protected function getHttpClient() | |
139 | + { | |
140 | + if (!isset($this->_httpClient)) { | |
141 | + $config = $this->httpClient; | |
142 | + if (!isset($config)) { | |
143 | + $config = $this->getComponent()->getHttpClient(); | |
144 | + } | |
145 | + $this->_httpClient = Yii::createObject($config); | |
146 | + } | |
147 | + return $this->_httpClient; | |
148 | + } | |
149 | + | |
150 | + /** | |
151 | + * @return int | |
152 | + */ | |
153 | + public function getTokenDefaultLifetime() | |
154 | + { | |
155 | + return $this->tokenDefaultLifetime; | |
156 | + } | |
157 | + | |
158 | + /** | |
159 | + * Returns the protected resource. | |
160 | + * | |
161 | + * @param string $url url to request. | |
162 | + * @param array $options HTTP request options. Keys: query, data, headers. | |
163 | + * @param boolean $parseResponse Whether to parse response. | |
164 | + * @return mixed the response. | |
165 | + * @throws ErrorException | |
166 | + */ | |
167 | + public function makeSignedRequest($url, $options = [], $parseResponse = true) | |
168 | + { | |
169 | + if (!$this->getIsAuthenticated()) { | |
170 | + throw new ErrorException(Yii::t('eauth', 'Unable to complete the signed request because the user was not authenticated.'), 401); | |
171 | + } | |
172 | + | |
173 | + if (stripos($url, 'http') !== 0) { | |
174 | + $url = $this->baseApiUrl . $url; | |
175 | + } | |
176 | + | |
177 | + $url = new Uri($url); | |
178 | + if (isset($options['query'])) { | |
179 | + foreach ($options['query'] as $key => $value) { | |
180 | + $url->addToQuery($key, $value); | |
181 | + } | |
182 | + } | |
183 | + | |
184 | + $data = isset($options['data']) ? $options['data'] : []; | |
185 | + $method = !empty($data) ? 'POST' : 'GET'; | |
186 | + $headers = isset($options['headers']) ? $options['headers'] : []; | |
187 | + | |
188 | + $response = $this->getProxy()->request($url, $method, $data, $headers); | |
189 | + | |
190 | + if ($parseResponse) { | |
191 | + $response = $this->parseResponseInternal($response); | |
192 | + } | |
193 | + | |
194 | + return $response; | |
195 | + } | |
196 | + | |
197 | + /** | |
198 | + * Returns the public resource. | |
199 | + * | |
200 | + * @param string $url url to request. | |
201 | + * @param array $options HTTP request options. Keys: query, data, headers. | |
202 | + * @param boolean $parseResponse Whether to parse response. | |
203 | + * @return mixed the response. | |
204 | + */ | |
205 | + public function makeRequest($url, $options = [], $parseResponse = true) { | |
206 | + if (stripos($url, 'http') !== 0) { | |
207 | + $url = $this->baseApiUrl . $url; | |
208 | + } | |
209 | + | |
210 | + $url = new Uri($url); | |
211 | + if (isset($options['query'])) { | |
212 | + foreach ($options['query'] as $key => $value) { | |
213 | + $url->addToQuery($key, $value); | |
214 | + } | |
215 | + } | |
216 | + | |
217 | + $data = isset($options['data']) ? $options['data'] : []; | |
218 | + $method = !empty($data) ? 'POST' : 'GET'; | |
219 | + | |
220 | + $headers = isset($options['headers']) ? $options['headers'] : []; | |
221 | + $headers = array_merge($this->getProxy()->getExtraApiHeaders(), $headers); | |
222 | + | |
223 | + $response = $this->getHttpClient()->retrieveResponse($url, $data, $headers, $method); | |
224 | + if ($parseResponse) { | |
225 | + $response = $this->parseResponseInternal($response); | |
226 | + } | |
227 | + | |
228 | + return $response; | |
229 | + } | |
230 | + | |
231 | + /** | |
232 | + * Parse response and check for errors. | |
233 | + * | |
234 | + * @param string $response | |
235 | + * @return mixed | |
236 | + * @throws ErrorException | |
237 | + */ | |
238 | + protected function parseResponseInternal($response) | |
239 | + { | |
240 | + try { | |
241 | + $result = $this->parseResponse($response); | |
242 | + if (!isset($result)) { | |
243 | + throw new ErrorException(Yii::t('eauth', 'Invalid response format.'), 500); | |
244 | + } | |
245 | + | |
246 | + $error = $this->fetchResponseError($result); | |
247 | + if (isset($error) && !empty($error['message'])) { | |
248 | + throw new ErrorException($error['message'], $error['code']); | |
249 | + } | |
250 | + | |
251 | + return $result; | |
252 | + } catch (\Exception $e) { | |
253 | + throw new ErrorException($e->getMessage(), $e->getCode()); | |
254 | + } | |
255 | + } | |
256 | + | |
257 | + /** | |
258 | + * @param string $response | |
259 | + * @return mixed | |
260 | + */ | |
261 | + protected function parseResponse($response) | |
262 | + { | |
263 | + return json_decode($response, true); | |
264 | + } | |
265 | + | |
266 | + /** | |
267 | + * Returns the error array. | |
268 | + * | |
269 | + * @param array $response | |
270 | + * @return array the error array with 2 keys: code and message. Should be null if no errors. | |
271 | + */ | |
272 | + protected function fetchResponseError($response) | |
273 | + { | |
274 | + if (isset($response['error'])) { | |
275 | + return [ | |
276 | + 'code' => 500, | |
277 | + 'message' => 'Unknown error occurred.', | |
278 | + ]; | |
279 | + } | |
280 | + return null; | |
281 | + } | |
282 | + | |
283 | + /** | |
284 | + * @return array|null An array with valid access_token information. | |
285 | + */ | |
286 | + protected function getAccessTokenData() | |
287 | + { | |
288 | + if (!$this->getIsAuthenticated()) { | |
289 | + return null; | |
290 | + } | |
291 | + | |
292 | + $token = $this->getProxy()->getAccessToken(); | |
293 | + if (!isset($token)) { | |
294 | + return null; | |
295 | + } | |
296 | + | |
297 | + return [ | |
298 | + 'access_token' => $token->getAccessToken(), | |
299 | + 'refresh_token' => $token->getRefreshToken(), | |
300 | + 'expires' => $token->getEndOfLife(), | |
301 | + 'params' => $token->getExtraParams(), | |
302 | + ]; | |
303 | + } | |
304 | + | |
305 | + /** | |
306 | + * @param array $data | |
307 | + * @return string|null | |
308 | + */ | |
309 | + public function getAccessTokenResponseError($data) | |
310 | + { | |
311 | + return isset($data['error']) ? $data['error'] : null; | |
312 | + } | |
313 | +} | |
0 | 314 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/oauth/SessionTokenStorage.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * SessionTokenStorage class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\oauth; | |
11 | + | |
12 | +use Yii; | |
13 | +use OAuth\Common\Storage\TokenStorageInterface; | |
14 | +use OAuth\Common\Token\TokenInterface; | |
15 | +use OAuth\Common\Storage\Exception\TokenNotFoundException; | |
16 | +use OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException; | |
17 | + | |
18 | +/** | |
19 | + * Stores a token in a PHP session. | |
20 | + */ | |
21 | +class SessionTokenStorage implements TokenStorageInterface | |
22 | +{ | |
23 | + | |
24 | + const SESSION_TOKEN_PREFIX = 'eauth-token-'; | |
25 | + const SESSION_STATE_PREFIX = 'eauth-state-'; | |
26 | + | |
27 | + /** | |
28 | + * @var | |
29 | + */ | |
30 | + protected $componentName; | |
31 | + | |
32 | + /** | |
33 | + * @param string $componentName | |
34 | + */ | |
35 | + public function __construct($componentName = 'session') | |
36 | + { | |
37 | + $this->componentName = $componentName; | |
38 | + } | |
39 | + | |
40 | + /** | |
41 | + * @return null|object | |
42 | + */ | |
43 | + protected function getSession() | |
44 | + { | |
45 | + return Yii::$app->get($this->componentName); | |
46 | + } | |
47 | + | |
48 | + /** | |
49 | + * @param string $service | |
50 | + * @return TokenInterface | |
51 | + * @throws TokenNotFoundException | |
52 | + */ | |
53 | + public function retrieveAccessToken($service) | |
54 | + { | |
55 | + if ($this->hasAccessToken($service)) { | |
56 | + return $this->getSession()->get(self::SESSION_TOKEN_PREFIX . $service); | |
57 | + } | |
58 | + throw new TokenNotFoundException('Token not found in session, are you sure you stored it?'); | |
59 | + } | |
60 | + | |
61 | + /** | |
62 | + * @param string $service | |
63 | + * @param TokenInterface $token | |
64 | + * @return TokenInterface | |
65 | + */ | |
66 | + public function storeAccessToken($service, TokenInterface $token) | |
67 | + { | |
68 | + $this->getSession()->set(self::SESSION_TOKEN_PREFIX . $service, $token); | |
69 | + return $token; | |
70 | + } | |
71 | + | |
72 | + /** | |
73 | + * @param string $service | |
74 | + * @return bool | |
75 | + */ | |
76 | + public function hasAccessToken($service) | |
77 | + { | |
78 | + return $this->getSession()->has(self::SESSION_TOKEN_PREFIX . $service); | |
79 | + } | |
80 | + | |
81 | + /** | |
82 | + * Delete the users token. Aka, log out. | |
83 | + * | |
84 | + * @param string $service | |
85 | + * @return TokenStorageInterface | |
86 | + */ | |
87 | + public function clearToken($service) | |
88 | + { | |
89 | + $this->getSession()->remove(self::SESSION_TOKEN_PREFIX . $service); | |
90 | + return $this; | |
91 | + } | |
92 | + | |
93 | + /** | |
94 | + * Delete *ALL* user tokens. | |
95 | + * | |
96 | + * @return TokenStorageInterface | |
97 | + */ | |
98 | + public function clearAllTokens() | |
99 | + { | |
100 | + $session = $this->getSession(); | |
101 | + foreach ($session as $key => $value) { | |
102 | + if (strpos($key, self::SESSION_TOKEN_PREFIX) === 0) { | |
103 | + $session->remove($key); | |
104 | + } | |
105 | + } | |
106 | + return $this; | |
107 | + } | |
108 | + | |
109 | + /** | |
110 | + * Store the authorization state related to a given service | |
111 | + * | |
112 | + * @param string $service | |
113 | + * @param string $state | |
114 | + * @return TokenStorageInterface | |
115 | + */ | |
116 | + public function storeAuthorizationState($service, $state) | |
117 | + { | |
118 | + $this->getSession()->set(self::SESSION_STATE_PREFIX . $service, $state); | |
119 | + return $this; | |
120 | + } | |
121 | + | |
122 | + /** | |
123 | + * Check if an authorization state for a given service exists | |
124 | + * | |
125 | + * @param string $service | |
126 | + * @return bool | |
127 | + */ | |
128 | + public function hasAuthorizationState($service) | |
129 | + { | |
130 | + return $this->getSession()->has(self::SESSION_STATE_PREFIX . $service); | |
131 | + } | |
132 | + | |
133 | + /** | |
134 | + * Retrieve the authorization state for a given service | |
135 | + * | |
136 | + * @param string $service | |
137 | + * @return string | |
138 | + * @throws AuthorizationStateNotFoundException | |
139 | + */ | |
140 | + public function retrieveAuthorizationState($service) | |
141 | + { | |
142 | + if ($this->hasAuthorizationState($service)) { | |
143 | + return $this->getSession()->get(self::SESSION_STATE_PREFIX . $service); | |
144 | + } | |
145 | + throw new AuthorizationStateNotFoundException('State not found in session, are you sure you stored it?'); | |
146 | + } | |
147 | + | |
148 | + /** | |
149 | + * Clear the authorization state of a given service | |
150 | + * | |
151 | + * @param string $service | |
152 | + * @return TokenStorageInterface | |
153 | + */ | |
154 | + public function clearAuthorizationState($service) | |
155 | + { | |
156 | + $this->getSession()->remove(self::SESSION_STATE_PREFIX . $service); | |
157 | + return $this; | |
158 | + } | |
159 | + | |
160 | + /** | |
161 | + * Delete *ALL* user authorization states. Use with care. Most of the time you will likely | |
162 | + * want to use clearAuthorizationState() instead. | |
163 | + * | |
164 | + * @return TokenStorageInterface | |
165 | + */ | |
166 | + public function clearAllAuthorizationStates() | |
167 | + { | |
168 | + $session = $this->getSession(); | |
169 | + foreach ($session as $key => $value) { | |
170 | + if (strpos($key, self::SESSION_STATE_PREFIX) === 0) { | |
171 | + $session->remove($key); | |
172 | + } | |
173 | + } | |
174 | + return $this; | |
175 | + } | |
176 | + | |
177 | +} | ... | ... |
common/components/nodge/eauth/src/oauth1/Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * OAuth1 Service class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\oauth1; | |
11 | + | |
12 | +use Yii; | |
13 | +use OAuth\Common\Exception\Exception as OAuthException; | |
14 | +use OAuth\Common\Http\Uri\Uri; | |
15 | +use OAuth\Common\Consumer\Credentials; | |
16 | +use OAuth\OAuth1\Signature\Signature; | |
17 | +use nodge\eauth\EAuth; | |
18 | +use nodge\eauth\ErrorException; | |
19 | +use nodge\eauth\IAuthService; | |
20 | +use nodge\eauth\oauth\ServiceBase; | |
21 | + | |
22 | +/** | |
23 | + * EOAuthService is a base class for all OAuth providers. | |
24 | + * | |
25 | + * @package application.extensions.eauth | |
26 | + */ | |
27 | +abstract class Service extends ServiceBase implements IAuthService | |
28 | +{ | |
29 | + | |
30 | + /** | |
31 | + * @var string OAuth2 client id. | |
32 | + */ | |
33 | + protected $key; | |
34 | + | |
35 | + /** | |
36 | + * @var string OAuth2 client secret key. | |
37 | + */ | |
38 | + protected $secret; | |
39 | + | |
40 | + /** | |
41 | + * @var array Provider options. Must contain the keys: request, authorize, access. | |
42 | + */ | |
43 | + protected $providerOptions = [ | |
44 | + 'request' => '', | |
45 | + 'authorize' => '', | |
46 | + 'access' => '', | |
47 | + ]; | |
48 | + | |
49 | + /** | |
50 | + * @var ServiceProxy | |
51 | + */ | |
52 | + private $_proxy; | |
53 | + | |
54 | + /** | |
55 | + * Initialize the component. | |
56 | + * | |
57 | + * @param EAuth $component the component instance. | |
58 | + * @param array $options properties initialization. | |
59 | + */ | |
60 | +// public function init($component, $options = []) { | |
61 | +// parent::init($component, $options); | |
62 | +// } | |
63 | + | |
64 | + /** | |
65 | + * @param string $key | |
66 | + */ | |
67 | + public function setKey($key) | |
68 | + { | |
69 | + $this->key = $key; | |
70 | + } | |
71 | + | |
72 | + /** | |
73 | + * @param string $secret | |
74 | + */ | |
75 | + public function setSecret($secret) | |
76 | + { | |
77 | + $this->secret = $secret; | |
78 | + } | |
79 | + | |
80 | + /** | |
81 | + * @return ServiceProxy | |
82 | + */ | |
83 | + protected function getProxy() | |
84 | + { | |
85 | + if (!isset($this->_proxy)) { | |
86 | + $storage = $this->getTokenStorage(); | |
87 | + $httpClient = $this->getHttpClient(); | |
88 | + $credentials = new Credentials($this->key, $this->secret, $this->getCallbackUrl()); | |
89 | + $signature = new Signature($credentials); | |
90 | + $this->_proxy = new ServiceProxy($credentials, $httpClient, $storage, $signature, null, $this); | |
91 | + } | |
92 | + return $this->_proxy; | |
93 | + } | |
94 | + | |
95 | + /** | |
96 | + * Authenticate the user. | |
97 | + * | |
98 | + * @return boolean whether user was successfuly authenticated. | |
99 | + * @throws ErrorException | |
100 | + */ | |
101 | + public function authenticate() | |
102 | + { | |
103 | + try { | |
104 | + $proxy = $this->getProxy(); | |
105 | + | |
106 | + if (!empty($_GET['oauth_token'])) { | |
107 | + $token = $proxy->retrieveAccessToken(); | |
108 | + | |
109 | + // This was a callback request, get the token now | |
110 | + $proxy->requestAccessToken($_GET['oauth_token'], $_GET['oauth_verifier'], $token->getRequestTokenSecret()); | |
111 | + | |
112 | + $this->authenticated = true; | |
113 | + } else if ($proxy->hasValidAccessToken()) { | |
114 | + $this->authenticated = true; | |
115 | + } else { | |
116 | + // extra request needed for oauth1 to request a request token :-) | |
117 | + $token = $proxy->requestRequestToken(); | |
118 | + /** @var $url Uri */ | |
119 | + $url = $proxy->getAuthorizationUri(['oauth_token' => $token->getRequestToken()]); | |
120 | + Yii::$app->getResponse()->redirect($url->getAbsoluteUri())->send(); | |
121 | + } | |
122 | + } catch (OAuthException $e) { | |
123 | + throw new ErrorException($e->getMessage(), $e->getCode(), 1, $e->getFile(), $e->getLine(), $e); | |
124 | + } | |
125 | + | |
126 | + return $this->getIsAuthenticated(); | |
127 | + } | |
128 | + | |
129 | + /** | |
130 | + * @return string | |
131 | + */ | |
132 | + public function getRequestTokenEndpoint() | |
133 | + { | |
134 | + return $this->providerOptions['request']; | |
135 | + } | |
136 | + | |
137 | + /** | |
138 | + * @return string | |
139 | + */ | |
140 | + public function getAuthorizationEndpoint() | |
141 | + { | |
142 | + return $this->providerOptions['authorize']; | |
143 | + } | |
144 | + | |
145 | + /** | |
146 | + * @return string | |
147 | + */ | |
148 | + public function getAccessTokenEndpoint() | |
149 | + { | |
150 | + return $this->providerOptions['access']; | |
151 | + } | |
152 | + | |
153 | + /** | |
154 | + * @return array | |
155 | + */ | |
156 | + public function getAccessTokenArgumentNames() | |
157 | + { | |
158 | + return [ | |
159 | + 'oauth_token' => 'oauth_token', | |
160 | + 'oauth_token_secret' => 'oauth_token_secret', | |
161 | + 'oauth_expires_in' => 'oauth_expires_in', | |
162 | + ]; | |
163 | + } | |
164 | +} | |
0 | 165 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/oauth1/ServiceProxy.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * OAuth1 ServiceProxy class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\oauth1; | |
11 | + | |
12 | +use OAuth\Common\Consumer\CredentialsInterface; | |
13 | +use OAuth\Common\Http\Client\ClientInterface; | |
14 | +use OAuth\Common\Http\Exception\TokenResponseException; | |
15 | +use OAuth\Common\Http\Uri\Uri; | |
16 | +use OAuth\Common\Http\Uri\UriInterface; | |
17 | +use OAuth\Common\Storage\TokenStorageInterface; | |
18 | +use OAuth\Common\Token\TokenInterface; | |
19 | +use OAuth\OAuth1\Service\AbstractService; | |
20 | +use OAuth\OAuth1\Signature\SignatureInterface; | |
21 | +use OAuth\OAuth1\Token\StdOAuth1Token; | |
22 | + | |
23 | +class ServiceProxy extends AbstractService | |
24 | +{ | |
25 | + | |
26 | + /** | |
27 | + * @var Service the currently used service class | |
28 | + */ | |
29 | + protected $service; | |
30 | + | |
31 | + /** | |
32 | + * {@inheritDoc} | |
33 | + */ | |
34 | + public function __construct( | |
35 | + CredentialsInterface $credentials, | |
36 | + ClientInterface $httpClient, | |
37 | + TokenStorageInterface $storage, | |
38 | + SignatureInterface $signature, | |
39 | + UriInterface $baseApiUri = null, | |
40 | + Service $service | |
41 | + ) | |
42 | + { | |
43 | + $this->service = $service; | |
44 | + parent::__construct($credentials, $httpClient, $storage, $signature, $baseApiUri); | |
45 | + } | |
46 | + | |
47 | + /** | |
48 | + * @return string | |
49 | + */ | |
50 | + public function service() | |
51 | + { | |
52 | + return $this->service->getServiceName(); | |
53 | + } | |
54 | + | |
55 | + /** | |
56 | + * @return StdOAuth1Token | |
57 | + */ | |
58 | + public function retrieveAccessToken() | |
59 | + { | |
60 | + return $this->storage->retrieveAccessToken($this->service()); | |
61 | + } | |
62 | + | |
63 | + /** | |
64 | + * | |
65 | + */ | |
66 | + public function hasValidAccessToken() | |
67 | + { | |
68 | + $serviceName = $this->service(); | |
69 | + | |
70 | + if (!$this->storage->hasAccessToken($serviceName)) { | |
71 | + return false; | |
72 | + } | |
73 | + | |
74 | + /** @var $token StdOAuth1Token */ | |
75 | + $token = $this->storage->retrieveAccessToken($serviceName); | |
76 | + | |
77 | + $params = $token->getExtraParams(); | |
78 | + if (isset($params['is_request_token'])) { | |
79 | + return false; | |
80 | + } | |
81 | + | |
82 | + return $this->checkTokenLifetime($token); | |
83 | + } | |
84 | + | |
85 | + /** | |
86 | + * @param TokenInterface $token | |
87 | + * @return bool | |
88 | + */ | |
89 | + protected function checkTokenLifetime($token) | |
90 | + { | |
91 | + // assume that we have at least a minute to execute a queries. | |
92 | + return $token->getEndOfLife() - 60 > time() | |
93 | + || $token->getEndOfLife() === TokenInterface::EOL_NEVER_EXPIRES | |
94 | + || $token->getEndOfLife() === TokenInterface::EOL_UNKNOWN; | |
95 | + } | |
96 | + | |
97 | + /** | |
98 | + * @return null|TokenInterface | |
99 | + */ | |
100 | + public function getAccessToken() | |
101 | + { | |
102 | + if (!$this->hasValidAccessToken()) { | |
103 | + return null; | |
104 | + } | |
105 | + | |
106 | + $serviceName = $this->service(); | |
107 | + return $this->storage->retrieveAccessToken($serviceName); | |
108 | + } | |
109 | + | |
110 | + /** | |
111 | + * @return UriInterface | |
112 | + */ | |
113 | + public function getRequestTokenEndpoint() | |
114 | + { | |
115 | + return new Uri($this->service->getRequestTokenEndpoint()); | |
116 | + } | |
117 | + | |
118 | + /** | |
119 | + * @return UriInterface | |
120 | + */ | |
121 | + public function getAuthorizationEndpoint() | |
122 | + { | |
123 | + return new Uri($this->service->getAuthorizationEndpoint()); | |
124 | + } | |
125 | + | |
126 | + /** | |
127 | + * @return UriInterface | |
128 | + */ | |
129 | + public function getAccessTokenEndpoint() | |
130 | + { | |
131 | + return new Uri($this->service->getAccessTokenEndpoint()); | |
132 | + } | |
133 | + | |
134 | + /** | |
135 | + * We need a separate request token parser only to verify the `oauth_callback_confirmed` parameter. For the actual | |
136 | + * parsing we can just use the default access token parser. | |
137 | + * | |
138 | + * @param string $responseBody | |
139 | + * @return StdOAuth1Token | |
140 | + * @throws TokenResponseException | |
141 | + */ | |
142 | + protected function parseRequestTokenResponse($responseBody) | |
143 | + { | |
144 | + parse_str($responseBody, $data); | |
145 | + | |
146 | + if (!isset($data) || !is_array($data)) { | |
147 | + throw new TokenResponseException('Unable to parse response.'); | |
148 | + } else if (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] != 'true') { | |
149 | + throw new TokenResponseException('Error in retrieving token.'); | |
150 | + } | |
151 | + | |
152 | + $data['is_request_token'] = true; | |
153 | + return $this->parseAccessTokenResponse($data); | |
154 | + } | |
155 | + | |
156 | + /** | |
157 | + * @param string|array $responseBody | |
158 | + * @return StdOAuth1Token | |
159 | + * @throws TokenResponseException | |
160 | + */ | |
161 | + protected function parseAccessTokenResponse($responseBody) | |
162 | + { | |
163 | + if (!is_array($responseBody)) { | |
164 | + parse_str($responseBody, $data); | |
165 | + | |
166 | + if (!isset($data) || !is_array($data)) { | |
167 | + throw new TokenResponseException('Unable to parse response.'); | |
168 | + } | |
169 | + } else { | |
170 | + $data = $responseBody; | |
171 | + } | |
172 | + | |
173 | + $error = $this->service->getAccessTokenResponseError($data); | |
174 | + if (isset($error)) { | |
175 | + throw new TokenResponseException('Error in retrieving token: "' . $error . '"'); | |
176 | + } | |
177 | + | |
178 | + $token = new StdOAuth1Token(); | |
179 | + $names = $this->service->getAccessTokenArgumentNames(); | |
180 | + | |
181 | + $token->setRequestToken($data[$names['oauth_token']]); | |
182 | + $token->setRequestTokenSecret($data[$names['oauth_token_secret']]); | |
183 | + $token->setAccessToken($data[$names['oauth_token']]); | |
184 | + $token->setAccessTokenSecret($data[$names['oauth_token_secret']]); | |
185 | + unset($data[$names['oauth_token']], $data[$names['oauth_token_secret']]); | |
186 | + | |
187 | + if (isset($data[$names['oauth_expires_in']])) { | |
188 | + $token->setLifeTime($data[$names['oauth_expires_in']]); | |
189 | + unset($data[$names['oauth_expires_in']]); | |
190 | + } else { | |
191 | + $token->setLifetime($this->service->getTokenDefaultLifetime()); | |
192 | + } | |
193 | + | |
194 | + $token->setExtraParams($data); | |
195 | + | |
196 | + return $token; | |
197 | + } | |
198 | +} | |
0 | 199 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/oauth2/Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * OAuth2 Service class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\oauth2; | |
11 | + | |
12 | +use Yii; | |
13 | +use yii\helpers\Url; | |
14 | +use OAuth\Common\Exception\Exception as OAuthException; | |
15 | +use OAuth\Common\Http\Uri\Uri; | |
16 | +use OAuth\Common\Consumer\Credentials; | |
17 | +use OAuth\OAuth2\Service\ServiceInterface; | |
18 | +use nodge\eauth\EAuth; | |
19 | +use nodge\eauth\ErrorException; | |
20 | +use nodge\eauth\IAuthService; | |
21 | +use nodge\eauth\oauth\ServiceBase; | |
22 | + | |
23 | +/** | |
24 | + * EOAuthService is a base class for all OAuth providers. | |
25 | + * | |
26 | + * @package application.extensions.eauth | |
27 | + */ | |
28 | +abstract class Service extends ServiceBase implements IAuthService | |
29 | +{ | |
30 | + | |
31 | + /** | |
32 | + * @var string OAuth2 client id. | |
33 | + */ | |
34 | + protected $clientId; | |
35 | + | |
36 | + /** | |
37 | + * @var string OAuth2 client secret key. | |
38 | + */ | |
39 | + protected $clientSecret; | |
40 | + | |
41 | + /** | |
42 | + * @var array OAuth scopes. | |
43 | + */ | |
44 | + protected $scopes = []; | |
45 | + | |
46 | + /** | |
47 | + * @var string | |
48 | + */ | |
49 | + protected $scopeSeparator = ' '; | |
50 | + | |
51 | + /** | |
52 | + * @var array Provider options. Must contain the keys: authorize, access_token. | |
53 | + */ | |
54 | + protected $providerOptions = [ | |
55 | + 'authorize' => '', | |
56 | + 'access_token' => '', | |
57 | + ]; | |
58 | + | |
59 | + /** | |
60 | + * @var string Error key name in _GET options. | |
61 | + */ | |
62 | + protected $errorParam = 'error'; | |
63 | + | |
64 | + /** | |
65 | + * @var string Error description key name in _GET options. | |
66 | + */ | |
67 | + protected $errorDescriptionParam = 'error_description'; | |
68 | + | |
69 | + /** | |
70 | + * @var string Error code for access_denied response. | |
71 | + */ | |
72 | + protected $errorAccessDeniedCode = 'access_denied'; | |
73 | + | |
74 | + /** | |
75 | + * @var string The display name for popup window. False to disable display mode. | |
76 | + */ | |
77 | + protected $popupDisplayName = 'popup'; | |
78 | + | |
79 | + /** | |
80 | + * @var bool Whether to use the State param to improve security. | |
81 | + */ | |
82 | + protected $validateState = true; | |
83 | + | |
84 | + /** | |
85 | + * @var ServiceProxy | |
86 | + */ | |
87 | + private $_proxy; | |
88 | + | |
89 | + /** | |
90 | + * Initialize the component. | |
91 | + * | |
92 | + * @param EAuth $component the component instance. | |
93 | + * @param array $options properties initialization. | |
94 | + */ | |
95 | +// public function init($component, $options = []) { | |
96 | +// parent::init($component, $options); | |
97 | +// } | |
98 | + | |
99 | + /** | |
100 | + * @param string $id | |
101 | + */ | |
102 | + public function setClientId($id) | |
103 | + { | |
104 | + $this->clientId = $id; | |
105 | + } | |
106 | + | |
107 | + /** | |
108 | + * @param string $secret | |
109 | + */ | |
110 | + public function setClientSecret($secret) | |
111 | + { | |
112 | + $this->clientSecret = $secret; | |
113 | + } | |
114 | + | |
115 | + /** | |
116 | + * @param string|array $scopes | |
117 | + */ | |
118 | + public function setScope($scopes) | |
119 | + { | |
120 | + if (!is_array($scopes)) { | |
121 | + $scopes = [$scopes]; | |
122 | + } | |
123 | + | |
124 | + $resolvedScopes = []; | |
125 | + $reflClass = new \ReflectionClass($this); | |
126 | + $constants = $reflClass->getConstants(); | |
127 | + | |
128 | + foreach ($scopes as $scope) { | |
129 | + $key = strtoupper('SCOPE_' . $scope); | |
130 | + | |
131 | + // try to find a class constant with this name | |
132 | + if (array_key_exists($key, $constants)) { | |
133 | + $resolvedScopes[] = $constants[$key]; | |
134 | + } else { | |
135 | + $resolvedScopes[] = $scope; | |
136 | + } | |
137 | + } | |
138 | + | |
139 | + $this->scopes = $resolvedScopes; | |
140 | + } | |
141 | + | |
142 | + /** | |
143 | + * @param bool $validate | |
144 | + */ | |
145 | + public function setValidateState($validate) | |
146 | + { | |
147 | + $this->validateState = $validate; | |
148 | + } | |
149 | + | |
150 | + /** | |
151 | + * @return bool | |
152 | + */ | |
153 | + public function getValidateState() | |
154 | + { | |
155 | + return $this->validateState; | |
156 | + } | |
157 | + | |
158 | + /** | |
159 | + * @return ServiceProxy | |
160 | + */ | |
161 | + protected function getProxy() | |
162 | + { | |
163 | + if (!isset($this->_proxy)) { | |
164 | + $tokenStorage = $this->getTokenStorage(); | |
165 | + $httpClient = $this->getHttpClient(); | |
166 | + $credentials = new Credentials($this->clientId, $this->clientSecret, $this->getCallbackUrl()); | |
167 | + $this->_proxy = new ServiceProxy($credentials, $httpClient, $tokenStorage, $this->scopes, null, $this); | |
168 | + } | |
169 | + return $this->_proxy; | |
170 | + } | |
171 | + | |
172 | + /** | |
173 | + * @return string the current url | |
174 | + */ | |
175 | + protected function getCallbackUrl() | |
176 | + { | |
177 | + if (isset($_GET['redirect_uri'])) { | |
178 | + $url = $_GET['redirect_uri']; | |
179 | + } | |
180 | + else { | |
181 | + $route = Yii::$app->getRequest()->getQueryParams(); | |
182 | + array_unshift($route, ''); | |
183 | + | |
184 | + // Can not use these params in OAuth2 callbacks | |
185 | + foreach (['code', 'state', 'redirect_uri'] as $param) { | |
186 | + if (isset($route[$param])) { | |
187 | + unset($route[$param]); | |
188 | + } | |
189 | + } | |
190 | + | |
191 | + $url = Url::to($route, true); | |
192 | + } | |
193 | + | |
194 | + return $url; | |
195 | + } | |
196 | + | |
197 | + /** | |
198 | + * Authenticate the user. | |
199 | + * | |
200 | + * @return boolean whether user was successfuly authenticated. | |
201 | + * @throws ErrorException | |
202 | + */ | |
203 | + public function authenticate() | |
204 | + { | |
205 | + if (!$this->checkError()) { | |
206 | + return false; | |
207 | + } | |
208 | + | |
209 | + try { | |
210 | + $proxy = $this->getProxy(); | |
211 | + | |
212 | + if (!empty($_GET['code'])) { | |
213 | + // This was a callback request from a service, get the token | |
214 | + $proxy->requestAccessToken($_GET['code']); | |
215 | + $this->authenticated = true; | |
216 | + } else if ($proxy->hasValidAccessToken()) { | |
217 | + $this->authenticated = true; | |
218 | + } else { | |
219 | + /** @var $url Uri */ | |
220 | + $url = $proxy->getAuthorizationUri(); | |
221 | + Yii::$app->getResponse()->redirect($url->getAbsoluteUri())->send(); | |
222 | + } | |
223 | + } catch (OAuthException $e) { | |
224 | + throw new ErrorException($e->getMessage(), $e->getCode(), 1, $e->getFile(), $e->getLine(), $e); | |
225 | + } | |
226 | + | |
227 | + return $this->getIsAuthenticated(); | |
228 | + } | |
229 | + | |
230 | + /** | |
231 | + * Check request params for error code and message. | |
232 | + * | |
233 | + * @return bool | |
234 | + * @throws ErrorException | |
235 | + */ | |
236 | + protected function checkError() | |
237 | + { | |
238 | + if (isset($_GET[$this->errorParam])) { | |
239 | + $error_code = $_GET[$this->errorParam]; | |
240 | + if ($error_code === $this->errorAccessDeniedCode) { | |
241 | + // access_denied error (user canceled) | |
242 | + $this->cancel(); | |
243 | + } else { | |
244 | + $error = $error_code; | |
245 | + if (isset($_GET[$this->errorDescriptionParam])) { | |
246 | + $error = $_GET[$this->errorDescriptionParam] . ' (' . $error . ')'; | |
247 | + } | |
248 | + throw new ErrorException($error); | |
249 | + } | |
250 | + return false; | |
251 | + } | |
252 | + | |
253 | + return true; | |
254 | + } | |
255 | + | |
256 | + /** | |
257 | + * @return string | |
258 | + */ | |
259 | + public function getAuthorizationEndpoint() | |
260 | + { | |
261 | + $url = $this->providerOptions['authorize']; | |
262 | + if ($this->popupDisplayName !== false && $this->getIsInsidePopup()) { | |
263 | + $url = new Uri($url); | |
264 | + $url->addToQuery('display', $this->popupDisplayName); | |
265 | + $url = $url->getAbsoluteUri(); | |
266 | + } | |
267 | + return $url; | |
268 | + } | |
269 | + | |
270 | + /** | |
271 | + * @return string | |
272 | + */ | |
273 | + public function getAccessTokenEndpoint() | |
274 | + { | |
275 | + return $this->providerOptions['access_token']; | |
276 | + } | |
277 | + | |
278 | + /** | |
279 | + * @param string $response | |
280 | + * @return array | |
281 | + */ | |
282 | + public function parseAccessTokenResponse($response) | |
283 | + { | |
284 | + return json_decode($response, true); | |
285 | + } | |
286 | + | |
287 | + /** | |
288 | + * @return array | |
289 | + */ | |
290 | + public function getAccessTokenArgumentNames() | |
291 | + { | |
292 | + return [ | |
293 | + 'access_token' => 'access_token', | |
294 | + 'expires_in' => 'expires_in', | |
295 | + 'refresh_token' => 'refresh_token', | |
296 | + ]; | |
297 | + } | |
298 | + | |
299 | + /** | |
300 | + * Return any additional headers always needed for this service implementation's OAuth calls. | |
301 | + * | |
302 | + * @return array | |
303 | + */ | |
304 | + public function getExtraOAuthHeaders() | |
305 | + { | |
306 | + return []; | |
307 | + } | |
308 | + | |
309 | + /** | |
310 | + * Return any additional headers always needed for this service implementation's API calls. | |
311 | + * | |
312 | + * @return array | |
313 | + */ | |
314 | + public function getExtraApiHeaders() | |
315 | + { | |
316 | + return []; | |
317 | + } | |
318 | + | |
319 | + /** | |
320 | + * Returns a class constant from ServiceInterface defining the authorization method used for the API | |
321 | + * Header is the sane default. | |
322 | + * | |
323 | + * @return int | |
324 | + */ | |
325 | + public function getAuthorizationMethod() | |
326 | + { | |
327 | + return ServiceInterface::AUTHORIZATION_METHOD_HEADER_OAUTH; | |
328 | + } | |
329 | + | |
330 | + /** | |
331 | + * @return string | |
332 | + */ | |
333 | + public function getScopeSeparator() | |
334 | + { | |
335 | + return $this->scopeSeparator; | |
336 | + } | |
337 | +} | |
0 | 338 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/oauth2/ServiceProxy.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * OAuth2 ServiceProxy class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\oauth2; | |
11 | + | |
12 | +use OAuth\Common\Consumer\CredentialsInterface; | |
13 | +use OAuth\Common\Http\Client\ClientInterface; | |
14 | +use OAuth\Common\Http\Exception\TokenResponseException; | |
15 | +use OAuth\Common\Http\Uri\Uri; | |
16 | +use OAuth\Common\Http\Uri\UriInterface; | |
17 | +use OAuth\Common\Storage\TokenStorageInterface; | |
18 | +use OAuth\Common\Token\TokenInterface; | |
19 | +use OAuth\OAuth2\Service\AbstractService; | |
20 | +use OAuth\OAuth2\Token\StdOAuth2Token; | |
21 | + | |
22 | +class ServiceProxy extends AbstractService | |
23 | +{ | |
24 | + | |
25 | + /** | |
26 | + * @var Service the currently used service class | |
27 | + */ | |
28 | + protected $service; | |
29 | + | |
30 | + /** | |
31 | + * @param CredentialsInterface $credentials | |
32 | + * @param ClientInterface $httpClient | |
33 | + * @param TokenStorageInterface $storage | |
34 | + * @param array $scopes | |
35 | + * @param UriInterface $baseApiUri | |
36 | + * @param Service $service | |
37 | + */ | |
38 | + public function __construct( | |
39 | + CredentialsInterface $credentials, | |
40 | + ClientInterface $httpClient, | |
41 | + TokenStorageInterface $storage, | |
42 | + $scopes = [], | |
43 | + UriInterface $baseApiUri = null, | |
44 | + Service $service | |
45 | + ) | |
46 | + { | |
47 | + $this->service = $service; | |
48 | + parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri, $service->getValidateState()); | |
49 | + } | |
50 | + | |
51 | + /** | |
52 | + * @return string | |
53 | + */ | |
54 | + public function service() | |
55 | + { | |
56 | + return $this->service->getServiceName(); | |
57 | + } | |
58 | + | |
59 | + /** | |
60 | + * Validate scope | |
61 | + * | |
62 | + * @param string $scope | |
63 | + * @return bool | |
64 | + */ | |
65 | + public function isValidScope($scope) | |
66 | + { | |
67 | + $reflectionClass = new \ReflectionClass(get_class($this->service)); | |
68 | + return in_array($scope, $reflectionClass->getConstants(), true); | |
69 | + } | |
70 | + | |
71 | + /** | |
72 | + * @return bool | |
73 | + */ | |
74 | + public function hasValidAccessToken() | |
75 | + { | |
76 | + $serviceName = $this->service(); | |
77 | + | |
78 | + if (!$this->storage->hasAccessToken($serviceName)) { | |
79 | + return false; | |
80 | + } | |
81 | + | |
82 | + /** @var $token StdOAuth2Token */ | |
83 | + $token = $this->storage->retrieveAccessToken($serviceName); | |
84 | + $valid = $this->checkTokenLifetime($token); | |
85 | + | |
86 | + if (!$valid) { | |
87 | + $refreshToken = $token->getRefreshToken(); | |
88 | + if (isset($refreshToken)) { | |
89 | + $token = $this->refreshAccessToken($token); | |
90 | + return $this->checkTokenLifetime($token); | |
91 | + } | |
92 | + } | |
93 | + | |
94 | + return $valid; | |
95 | + } | |
96 | + | |
97 | + /** | |
98 | + * @param TokenInterface $token | |
99 | + * @return bool | |
100 | + */ | |
101 | + protected function checkTokenLifetime($token) | |
102 | + { | |
103 | + // assume that we have at least a minute to execute a queries. | |
104 | + return $token->getEndOfLife() - 60 > time() | |
105 | + || $token->getEndOfLife() === TokenInterface::EOL_NEVER_EXPIRES | |
106 | + || $token->getEndOfLife() === TokenInterface::EOL_UNKNOWN; | |
107 | + } | |
108 | + | |
109 | + /** | |
110 | + * @return null|TokenInterface | |
111 | + */ | |
112 | + public function getAccessToken() | |
113 | + { | |
114 | + if (!$this->hasValidAccessToken()) { | |
115 | + return null; | |
116 | + } | |
117 | + | |
118 | + $serviceName = $this->service(); | |
119 | + return $this->storage->retrieveAccessToken($serviceName); | |
120 | + } | |
121 | + | |
122 | + /** | |
123 | + * @return UriInterface | |
124 | + */ | |
125 | + public function getAuthorizationEndpoint() | |
126 | + { | |
127 | + return new Uri($this->service->getAuthorizationEndpoint()); | |
128 | + } | |
129 | + | |
130 | + /** | |
131 | + * @return UriInterface | |
132 | + */ | |
133 | + public function getAccessTokenEndpoint() | |
134 | + { | |
135 | + return new Uri($this->service->getAccessTokenEndpoint()); | |
136 | + } | |
137 | + | |
138 | + /** | |
139 | + * @param string $responseBody | |
140 | + * @return StdOAuth2Token | |
141 | + * @throws TokenResponseException | |
142 | + */ | |
143 | + protected function parseAccessTokenResponse($responseBody) | |
144 | + { | |
145 | + $data = $this->service->parseAccessTokenResponse($responseBody); | |
146 | + | |
147 | + if (!isset($data) || !is_array($data)) { | |
148 | + throw new TokenResponseException('Unable to parse response.'); | |
149 | + } | |
150 | + | |
151 | + $error = $this->service->getAccessTokenResponseError($data); | |
152 | + if (isset($error)) { | |
153 | + throw new TokenResponseException('Error in retrieving token: "' . $error . '"'); | |
154 | + } | |
155 | + | |
156 | + $token = new StdOAuth2Token(); | |
157 | + $names = $this->service->getAccessTokenArgumentNames(); | |
158 | + | |
159 | + $token->setAccessToken($data[$names['access_token']]); | |
160 | + unset($data[$names['access_token']]); | |
161 | + | |
162 | + if (isset($data[$names['expires_in']])) { | |
163 | + $token->setLifeTime($data[$names['expires_in']]); | |
164 | + unset($data[$names['expires_in']]); | |
165 | + } else { | |
166 | + $token->setLifetime($this->service->getTokenDefaultLifetime()); | |
167 | + } | |
168 | + | |
169 | + if (isset($data[$names['refresh_token']])) { | |
170 | + $token->setRefreshToken($data[$names['refresh_token']]); | |
171 | + unset($data[$names['refresh_token']]); | |
172 | + } | |
173 | + | |
174 | + $token->setExtraParams($data); | |
175 | + | |
176 | + return $token; | |
177 | + } | |
178 | + | |
179 | + /** | |
180 | + * Return any additional headers always needed for this service implementation's OAuth calls. | |
181 | + * | |
182 | + * @return array | |
183 | + */ | |
184 | + protected function getExtraOAuthHeaders() | |
185 | + { | |
186 | + return $this->service->getExtraOAuthHeaders(); | |
187 | + } | |
188 | + | |
189 | + /** | |
190 | + * Return any additional headers always needed for this service implementation's API calls. | |
191 | + * | |
192 | + * @return array | |
193 | + */ | |
194 | + protected function getExtraApiHeaders() | |
195 | + { | |
196 | + return $this->service->getExtraApiHeaders(); | |
197 | + } | |
198 | + | |
199 | + /** | |
200 | + * Returns a class constant from ServiceInterface defining the authorization method used for the API | |
201 | + * Header is the sane default. | |
202 | + * | |
203 | + * @return int | |
204 | + */ | |
205 | + protected function getAuthorizationMethod() | |
206 | + { | |
207 | + return $this->service->getAuthorizationMethod(); | |
208 | + } | |
209 | + | |
210 | + /** | |
211 | + * Returns the url to redirect to for authorization purposes. | |
212 | + * | |
213 | + * @param array $additionalParameters | |
214 | + * @return Uri | |
215 | + */ | |
216 | + public function getAuthorizationUri(array $additionalParameters = []) | |
217 | + { | |
218 | + $parameters = array_merge($additionalParameters, [ | |
219 | + 'type' => 'web_server', | |
220 | + 'client_id' => $this->credentials->getConsumerId(), | |
221 | + 'redirect_uri' => $this->credentials->getCallbackUrl(), | |
222 | + 'response_type' => 'code', | |
223 | + ]); | |
224 | + | |
225 | + $parameters['scope'] = implode($this->service->getScopeSeparator(), $this->scopes); | |
226 | + | |
227 | + if ($this->needsStateParameterInAuthUrl()) { | |
228 | + if (!isset($parameters['state'])) { | |
229 | + $parameters['state'] = $this->generateAuthorizationState(); | |
230 | + } | |
231 | + $this->storeAuthorizationState($parameters['state']); | |
232 | + } | |
233 | + | |
234 | + // Build the url | |
235 | + $url = clone $this->getAuthorizationEndpoint(); | |
236 | + foreach ($parameters as $key => $val) { | |
237 | + $url->addToQuery($key, $val); | |
238 | + } | |
239 | + | |
240 | + return $url; | |
241 | + } | |
242 | +} | ... | ... |
common/components/nodge/eauth/src/openid/ControllerBehavior.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * ControllerBehavior class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\openid; | |
11 | + | |
12 | +use Yii; | |
13 | +use yii\base\Action; | |
14 | +use yii\base\ActionFilter; | |
15 | + | |
16 | +/** | |
17 | + * @package application.extensions.eauth | |
18 | + */ | |
19 | +class ControllerBehavior extends ActionFilter | |
20 | +{ | |
21 | + /** | |
22 | + * This method is invoked right before an action is to be executed (after all possible filters.) | |
23 | + * You may override this method to do last-minute preparation for the action. | |
24 | + * | |
25 | + * @param Action $action the action to be executed. | |
26 | + * @return boolean whether the action should continue to be executed. | |
27 | + */ | |
28 | + public function beforeAction($action) | |
29 | + { | |
30 | + $request = Yii::$app->getRequest(); | |
31 | + | |
32 | + if (in_array($request->getBodyParam('openid_mode', ''), ['id_res', 'cancel'])) { | |
33 | + $request->enableCsrfValidation = false; | |
34 | + } | |
35 | + | |
36 | + return parent::beforeAction($action); | |
37 | + } | |
38 | +} | ... | ... |
common/components/nodge/eauth/src/openid/Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * OpenID Service class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\openid; | |
11 | + | |
12 | +use \Yii; | |
13 | +use \LightOpenID; | |
14 | +use yii\web\HttpException; | |
15 | +use nodge\eauth\ServiceBase; | |
16 | +use nodge\eauth\IAuthService; | |
17 | +use nodge\eauth\ErrorException; | |
18 | + | |
19 | +/** | |
20 | + * EOpenIDService is a base class for all OpenID providers. | |
21 | + * | |
22 | + * @package application.extensions.eauth | |
23 | + */ | |
24 | +abstract class Service extends ServiceBase implements IAuthService | |
25 | +{ | |
26 | + | |
27 | + /** | |
28 | + * @var string a pattern that represents the part of URL-space for which an OpenID Authentication request is valid. | |
29 | + * See the spec for more info: http://openid.net/specs/openid-authentication-2_0.html#realms | |
30 | + * Note: a pattern can be without http(s):// part | |
31 | + */ | |
32 | + public $realm; | |
33 | + | |
34 | + /** | |
35 | + * @var LightOpenID the openid library instance. | |
36 | + */ | |
37 | + private $auth; | |
38 | + | |
39 | + /** | |
40 | + * @var string the OpenID authorization url. | |
41 | + */ | |
42 | + protected $url; | |
43 | + | |
44 | + /** | |
45 | + * @var array the OpenID required attributes. | |
46 | + */ | |
47 | + protected $requiredAttributes = []; | |
48 | + | |
49 | + /** | |
50 | + * @var array the OpenID optional attributes. | |
51 | + */ | |
52 | + protected $optionalAttributes = []; | |
53 | + | |
54 | + | |
55 | + /** | |
56 | + * Initialize the component. | |
57 | + */ | |
58 | + public function init() | |
59 | + { | |
60 | + parent::init(); | |
61 | + $this->auth = new LightOpenID(Yii::$app->getRequest()->getHostInfo()); | |
62 | + } | |
63 | + | |
64 | + /** | |
65 | + * Authenticate the user. | |
66 | + * | |
67 | + * @return boolean whether user was successfuly authenticated. | |
68 | + * @throws ErrorException | |
69 | + * @throws HttpException | |
70 | + */ | |
71 | + public function authenticate() | |
72 | + { | |
73 | + if (!empty($_REQUEST['openid_mode'])) { | |
74 | + switch ($_REQUEST['openid_mode']) { | |
75 | + case 'id_res': | |
76 | + $this->id_res(); | |
77 | + return true; | |
78 | + break; | |
79 | + | |
80 | + case 'cancel': | |
81 | + $this->cancel(); | |
82 | + break; | |
83 | + | |
84 | + default: | |
85 | + throw new HttpException(400, Yii::t('yii', 'Your request is invalid.')); | |
86 | + break; | |
87 | + } | |
88 | + } else { | |
89 | + $this->request(); | |
90 | + } | |
91 | + | |
92 | + return false; | |
93 | + } | |
94 | + | |
95 | + /** | |
96 | + * @throws ErrorException | |
97 | + */ | |
98 | + protected function id_res() | |
99 | + { | |
100 | + try { | |
101 | + if ($this->auth->validate()) { | |
102 | + $this->attributes['id'] = $this->auth->identity; | |
103 | + $this->loadRequiredAttributes(); | |
104 | + $this->loadOptionalAttributes(); | |
105 | + $this->authenticated = true; | |
106 | + } else { | |
107 | + throw new ErrorException(Yii::t('eauth', 'Unable to complete the authentication because the required data was not received.', ['provider' => $this->getServiceTitle()])); | |
108 | + } | |
109 | + } catch (\Exception $e) { | |
110 | + throw new ErrorException($e->getMessage(), $e->getCode()); | |
111 | + } | |
112 | + } | |
113 | + | |
114 | + /** | |
115 | + * @throws ErrorException | |
116 | + */ | |
117 | + protected function loadOptionalAttributes() | |
118 | + { | |
119 | + $attributes = $this->auth->getAttributes(); | |
120 | + foreach ($this->optionalAttributes as $key => $attr) { | |
121 | + if (isset($attributes[$attr[1]])) { | |
122 | + $this->attributes[$key] = $attributes[$attr[1]]; | |
123 | + } | |
124 | + } | |
125 | + } | |
126 | + | |
127 | + /** | |
128 | + * | |
129 | + */ | |
130 | + protected function loadRequiredAttributes() | |
131 | + { | |
132 | + $attributes = $this->auth->getAttributes(); | |
133 | + foreach ($this->requiredAttributes as $key => $attr) { | |
134 | + if (isset($attributes[$attr[1]])) { | |
135 | + $this->attributes[$key] = $attributes[$attr[1]]; | |
136 | + } else { | |
137 | + throw new ErrorException(Yii::t('eauth', 'Unable to complete the authentication because the required data was not received.', ['provider' => $this->getServiceTitle()])); | |
138 | + } | |
139 | + } | |
140 | + } | |
141 | + | |
142 | + /** | |
143 | + * @throws ErrorException | |
144 | + */ | |
145 | + protected function request() | |
146 | + { | |
147 | + $this->auth->identity = $this->url; //Setting identifier | |
148 | + | |
149 | + $this->auth->required = []; //Try to get info from openid provider | |
150 | + foreach ($this->requiredAttributes as $attribute) { | |
151 | + $this->auth->required[$attribute[0]] = $attribute[1]; | |
152 | + } | |
153 | + foreach ($this->optionalAttributes as $attribute) { | |
154 | + $this->auth->required[$attribute[0]] = $attribute[1]; | |
155 | + } | |
156 | + | |
157 | + $this->auth->realm = $this->getRealm(); | |
158 | + $this->auth->returnUrl = Yii::$app->getRequest()->getHostInfo() . Yii::$app->getRequest()->getUrl(); //getting return URL | |
159 | + | |
160 | + try { | |
161 | + $url = $this->auth->authUrl(); | |
162 | + Yii::$app->getResponse()->redirect($url)->send(); | |
163 | + } catch (\Exception $e) { | |
164 | + throw new ErrorException($e->getMessage(), $e->getCode()); | |
165 | + } | |
166 | + } | |
167 | + | |
168 | + /** | |
169 | + * @return string | |
170 | + */ | |
171 | + protected function getRealm() | |
172 | + { | |
173 | + if (isset($this->realm)) { | |
174 | + if (!preg_match('#^[a-z]+\://#', $this->realm)) { | |
175 | + return 'http' . (Yii::$app->getRequest()->getIsSecureConnection() ? 's' : '') . '://' . $this->realm; | |
176 | + } else { | |
177 | + return $this->realm; | |
178 | + } | |
179 | + } else { | |
180 | + return Yii::$app->getRequest()->getHostInfo(); | |
181 | + } | |
182 | + } | |
183 | +} | ... | ... |
common/components/nodge/eauth/src/services/FacebookOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * FacebookOAuth2Service class file. | |
4 | + * | |
5 | + * Register application: https://developers.facebook.com/apps/ | |
6 | + * | |
7 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
8 | + * @link http://github.com/Nodge/yii2-eauth/ | |
9 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
10 | + */ | |
11 | +namespace common\components\nodge\eauth\src\services; | |
12 | +use nodge\eauth\oauth2\Service; | |
13 | +/** | |
14 | + * Facebook provider class. | |
15 | + * | |
16 | + * @package application.extensions.eauth.services | |
17 | + */ | |
18 | +class FacebookOAuth2Service extends Service | |
19 | +{ | |
20 | + /** | |
21 | + * Full list of scopes may be found here: | |
22 | + * https://developers.facebook.com/docs/authentication/permissions/ | |
23 | + */ | |
24 | + const SCOPE_EMAIL = 'email'; | |
25 | + const SCOPE_USER_BIRTHDAY = 'user_birthday'; | |
26 | + const SCOPE_USER_HOMETOWN = 'user_hometown'; | |
27 | + const SCOPE_USER_LOCATION = 'user_location'; | |
28 | + const SCOPE_USER_PHOTOS = 'user_photos'; | |
29 | + protected $name = 'facebook'; | |
30 | + protected $title = 'Facebook'; | |
31 | + protected $type = 'OAuth2'; | |
32 | + protected $jsArguments = ['popup' => ['width' => 585, 'height' => 290]]; | |
33 | + protected $scopes = []; | |
34 | + protected $providerOptions = [ | |
35 | + 'authorize' => 'https://www.facebook.com/dialog/oauth', | |
36 | + 'access_token' => 'https://graph.facebook.com/oauth/access_token', | |
37 | + ]; | |
38 | + protected $baseApiUrl = 'https://graph.facebook.com/'; | |
39 | + protected $errorParam = 'error_code'; | |
40 | + protected $errorDescriptionParam = 'error_message'; | |
41 | + protected function fetchAttributes() | |
42 | + { | |
43 | + $info = $this->makeSignedRequest('me'); | |
44 | + $this->attributes['id'] = $info['id']; | |
45 | + $this->attributes['name'] = $info['name']; | |
46 | + $this->attributes['url'] = $info['link']; | |
47 | + return true; | |
48 | + } | |
49 | + /** | |
50 | + * @return array | |
51 | + */ | |
52 | + public function getAccessTokenArgumentNames() | |
53 | + { | |
54 | + $names = parent::getAccessTokenArgumentNames(); | |
55 | + $names['expires_in'] = 'expires'; | |
56 | + return $names; | |
57 | + } | |
58 | + /** | |
59 | + * @param string $response | |
60 | + * @return array | |
61 | + */ | |
62 | + public function parseAccessTokenResponse($response) | |
63 | + { | |
64 | + // Facebook gives us a query string or json | |
65 | + if ($response[0] === '{') { | |
66 | + return json_decode($response, true); | |
67 | + } | |
68 | + else { | |
69 | + parse_str($response, $data); | |
70 | + return $data; | |
71 | + } | |
72 | + } | |
73 | + /** | |
74 | + * Returns the error array. | |
75 | + * | |
76 | + * @param array $response | |
77 | + * @return array the error array with 2 keys: code and message. Should be null if no errors. | |
78 | + */ | |
79 | + protected function fetchResponseError($response) | |
80 | + { | |
81 | + if (isset($response['error'])) { | |
82 | + return [ | |
83 | + 'code' => $response['error']['code'], | |
84 | + 'message' => $response['error']['message'], | |
85 | + ]; | |
86 | + } else { | |
87 | + return null; | |
88 | + } | |
89 | + } | |
90 | + /** | |
91 | + * @param array $data | |
92 | + * @return string|null | |
93 | + */ | |
94 | + public function getAccessTokenResponseError($data) | |
95 | + { | |
96 | + $error = $this->fetchResponseError($data); | |
97 | + if (!$error) { | |
98 | + return null; | |
99 | + } | |
100 | + return $error['code'].': '.$error['message']; | |
101 | + } | |
102 | +} | |
0 | 103 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/GitHubOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * GithubOAuth2Service class file. | |
4 | + * | |
5 | + * Register application: https://github.com/settings/applications | |
6 | + * | |
7 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
8 | + * @link http://github.com/Nodge/yii2-eauth/ | |
9 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
10 | + */ | |
11 | + | |
12 | +namespace common\components\nodge\eauth\src\services; | |
13 | + | |
14 | +use OAuth\Common\Token\TokenInterface; | |
15 | +use OAuth\OAuth2\Service\ServiceInterface; | |
16 | +use nodge\eauth\oauth2\Service; | |
17 | + | |
18 | +/** | |
19 | + * GitHub provider class. | |
20 | + * | |
21 | + * @package application.extensions.eauth.services | |
22 | + */ | |
23 | +class GitHubOAuth2Service extends Service | |
24 | +{ | |
25 | + | |
26 | + /** | |
27 | + * Defined scopes, see http://developer.github.com/v3/oauth/ for definitions | |
28 | + */ | |
29 | + const SCOPE_USER = 'user'; | |
30 | + const SCOPE_PUBLIC_REPO = 'public_repo'; | |
31 | + const SCOPE_REPO = 'repo'; | |
32 | + const SCOPE_DELETE_REPO = 'delete_repo'; | |
33 | + const SCOPE_GIST = 'gist'; | |
34 | + | |
35 | + protected $name = 'github'; | |
36 | + protected $title = 'GitHub'; | |
37 | + protected $type = 'OAuth2'; | |
38 | + protected $jsArguments = ['popup' => ['width' => 600, 'height' => 450]]; | |
39 | + | |
40 | + protected $scopes = []; | |
41 | + protected $providerOptions = [ | |
42 | + 'authorize' => 'https://github.com/login/oauth/authorize', | |
43 | + 'access_token' => 'https://github.com/login/oauth/access_token', | |
44 | + ]; | |
45 | + protected $baseApiUrl = 'https://api.github.com/'; | |
46 | + | |
47 | + protected $tokenDefaultLifetime = TokenInterface::EOL_NEVER_EXPIRES; | |
48 | + protected $errorAccessDeniedCode = 'user_denied'; | |
49 | + | |
50 | + protected function fetchAttributes() | |
51 | + { | |
52 | + $info = $this->makeSignedRequest('user'); | |
53 | + | |
54 | + $this->attributes['id'] = $info['id']; | |
55 | + $this->attributes['name'] = $info['login']; | |
56 | + $this->attributes['url'] = $info['html_url']; | |
57 | + | |
58 | + return true; | |
59 | + } | |
60 | + | |
61 | + /** | |
62 | + * Used to configure response type -- we want JSON from github, default is query string format | |
63 | + * | |
64 | + * @return array | |
65 | + */ | |
66 | + public function getExtraOAuthHeaders() | |
67 | + { | |
68 | + return ['Accept' => 'application/json']; | |
69 | + } | |
70 | + | |
71 | + /** | |
72 | + * Required for GitHub API calls. | |
73 | + * | |
74 | + * @return array | |
75 | + */ | |
76 | + public function getExtraApiHeaders() | |
77 | + { | |
78 | + return ['Accept' => 'application/vnd.github.beta+json']; | |
79 | + } | |
80 | + | |
81 | + /** | |
82 | + * @return int | |
83 | + */ | |
84 | + public function getAuthorizationMethod() | |
85 | + { | |
86 | + return ServiceInterface::AUTHORIZATION_METHOD_QUERY_STRING; | |
87 | + } | |
88 | + | |
89 | + /** | |
90 | + * Returns the error array. | |
91 | + * | |
92 | + * @param array $response | |
93 | + * @return array the error array with 2 keys: code and message. Should be null if no errors. | |
94 | + */ | |
95 | + protected function fetchResponseError($response) | |
96 | + { | |
97 | + if (isset($response['message'])) { | |
98 | + return [ | |
99 | + 'code' => isset($response['error']) ? $response['code'] : 0, | |
100 | + 'message' => $response['message'], | |
101 | + ]; | |
102 | + } else { | |
103 | + return null; | |
104 | + } | |
105 | + } | |
106 | + | |
107 | +} | |
0 | 108 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/GoogleOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * GoogleOAuth2Service class file. | |
4 | + * | |
5 | + * Register application: https://code.google.com/apis/console/ | |
6 | + * | |
7 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
8 | + * @link http://github.com/Nodge/yii2-eauth/ | |
9 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
10 | + */ | |
11 | + | |
12 | +namespace common\components\nodge\eauth\src\services; | |
13 | + | |
14 | +use nodge\eauth\oauth2\Service; | |
15 | + | |
16 | +/** | |
17 | + * Google provider class. | |
18 | + * | |
19 | + * @package application.extensions.eauth.services | |
20 | + */ | |
21 | +class GoogleOAuth2Service extends Service | |
22 | +{ | |
23 | + | |
24 | + /** | |
25 | + * Defined scopes - More scopes are listed here: | |
26 | + * https://developers.google.com/oauthplayground/ | |
27 | + */ | |
28 | + | |
29 | + // Basic | |
30 | + const SCOPE_EMAIL = 'email'; | |
31 | + const SCOPE_PROFILE = 'profile'; | |
32 | + | |
33 | + const SCOPE_USERINFO_EMAIL = 'https://www.googleapis.com/auth/userinfo.email'; | |
34 | + const SCOPE_USERINFO_PROFILE = 'https://www.googleapis.com/auth/userinfo.profile'; | |
35 | + | |
36 | + // Google+ | |
37 | + const SCOPE_GPLUS_ME = 'https://www.googleapis.com/auth/plus.me'; | |
38 | + const SCOPE_GPLUS_LOGIN = 'https://www.googleapis.com/auth/plus.login'; | |
39 | + | |
40 | + // Google Drive | |
41 | + const SCOPE_DOCUMENTSLIST = 'https://docs.google.com/feeds/'; | |
42 | + const SCOPE_SPREADSHEETS = 'https://spreadsheets.google.com/feeds/'; | |
43 | + const SCOPE_GOOGLEDRIVE = 'https://www.googleapis.com/auth/drive'; | |
44 | + const SCOPE_DRIVE_APPS = 'https://www.googleapis.com/auth/drive.appdata'; | |
45 | + const SCOPE_DRIVE_APPS_READ_ONLY = 'https://www.googleapis.com/auth/drive.apps.readonly'; | |
46 | + const SCOPE_GOOGLEDRIVE_FILES = 'https://www.googleapis.com/auth/drive.file'; | |
47 | + const SCOPE_DRIVE_METADATA_READ_ONLY = 'https://www.googleapis.com/auth/drive.metadata.readonly'; | |
48 | + const SCOPE_DRIVE_READ_ONLY = 'https://www.googleapis.com/auth/drive.readonly'; | |
49 | + const SCOPE_DRIVE_SCRIPTS = 'https://www.googleapis.com/auth/drive.scripts'; | |
50 | + | |
51 | + // Adwords | |
52 | + const SCOPE_ADSENSE = 'https://www.googleapis.com/auth/adsense'; | |
53 | + const SCOPE_ADWORDS = 'https://adwords.google.com/api/adwords/'; | |
54 | + const SCOPE_GAN = 'https://www.googleapis.com/auth/gan'; // google affiliate network...? | |
55 | + | |
56 | + // Google Analytics | |
57 | + const SCOPE_ANALYTICS = 'https://www.googleapis.com/auth/analytics'; | |
58 | + const SCOPE_ANALYTICS_EDIT = 'https://www.googleapis.com/auth/analytics.edit'; | |
59 | + const SCOPE_ANALYTICS_MANAGE_USERS = 'https://www.googleapis.com/auth/analytics.manage.users'; | |
60 | + const SCOPE_ANALYTICS_READ_ONLY = 'https://www.googleapis.com/auth/analytics.readonly'; | |
61 | + | |
62 | + // Other services | |
63 | + const SCOPE_BOOKS = 'https://www.googleapis.com/auth/books'; | |
64 | + const SCOPE_BLOGGER = 'https://www.googleapis.com/auth/blogger'; | |
65 | + const SCOPE_CALENDAR = 'https://www.googleapis.com/auth/calendar'; | |
66 | + const SCOPE_CONTACT = 'https://www.google.com/m8/feeds/'; | |
67 | + const SCOPE_CHROMEWEBSTORE = 'https://www.googleapis.com/auth/chromewebstore.readonly'; | |
68 | + const SCOPE_GMAIL = 'https://mail.google.com/mail/feed/atom'; | |
69 | + const SCOPE_PICASAWEB = 'https://picasaweb.google.com/data/'; | |
70 | + const SCOPE_SITES = 'https://sites.google.com/feeds/'; | |
71 | + const SCOPE_URLSHORTENER = 'https://www.googleapis.com/auth/urlshortener'; | |
72 | + const SCOPE_WEBMASTERTOOLS = 'https://www.google.com/webmasters/tools/feeds/'; | |
73 | + const SCOPE_TASKS = 'https://www.googleapis.com/auth/tasks'; | |
74 | + | |
75 | + // Cloud services | |
76 | + const SCOPE_CLOUDSTORAGE = 'https://www.googleapis.com/auth/devstorage.read_write'; | |
77 | + const SCOPE_CONTENTFORSHOPPING = 'https://www.googleapis.com/auth/structuredcontent'; // what even is this | |
78 | + const SCOPE_USER_PROVISIONING = 'https://apps-apis.google.com/a/feeds/user/'; | |
79 | + const SCOPE_GROUPS_PROVISIONING = 'https://apps-apis.google.com/a/feeds/groups/'; | |
80 | + const SCOPE_NICKNAME_PROVISIONING = 'https://apps-apis.google.com/a/feeds/alias/'; | |
81 | + | |
82 | + // Old | |
83 | + const SCOPE_ORKUT = 'https://www.googleapis.com/auth/orkut'; | |
84 | + const SCOPE_GOOGLELATITUDE = | |
85 | + 'https://www.googleapis.com/auth/latitude.all.best https://www.googleapis.com/auth/latitude.all.city'; | |
86 | + const SCOPE_OPENID = 'openid'; | |
87 | + | |
88 | + // YouTube | |
89 | + const SCOPE_YOUTUBE_GDATA = 'https://gdata.youtube.com'; | |
90 | + const SCOPE_YOUTUBE_ANALYTICS_MONETARY = 'https://www.googleapis.com/auth/yt-analytics-monetary.readonly'; | |
91 | + const SCOPE_YOUTUBE_ANALYTICS = 'https://www.googleapis.com/auth/yt-analytics.readonly'; | |
92 | + const SCOPE_YOUTUBE = 'https://www.googleapis.com/auth/youtube'; | |
93 | + const SCOPE_YOUTUBE_READ_ONLY = 'https://www.googleapis.com/auth/youtube.readonly'; | |
94 | + const SCOPE_YOUTUBE_UPLOAD = 'https://www.googleapis.com/auth/youtube.upload'; | |
95 | + const SCOPE_YOUTUBE_PATNER = 'https://www.googleapis.com/auth/youtubepartner'; | |
96 | + const SCOPE_YOUTUBE_PARTNER_EDIT = 'https://www.googleapis.com/auth/youtubepartner-channel-edit'; | |
97 | + | |
98 | + // Google Glass | |
99 | + const SCOPE_GLASS_TIMELINE = 'https://www.googleapis.com/auth/glass.timeline'; | |
100 | + const SCOPE_GLASS_LOCATION = 'https://www.googleapis.com/auth/glass.location'; | |
101 | + | |
102 | + protected $name = 'google_oauth'; | |
103 | + protected $title = 'Google'; | |
104 | + protected $type = 'OAuth2'; | |
105 | + protected $jsArguments = ['popup' => ['width' => 500, 'height' => 450]]; | |
106 | + | |
107 | + protected $scopes = [self::SCOPE_USERINFO_PROFILE]; | |
108 | + protected $providerOptions = [ | |
109 | + 'authorize' => 'https://accounts.google.com/o/oauth2/auth', | |
110 | + 'access_token' => 'https://accounts.google.com/o/oauth2/token', | |
111 | + ]; | |
112 | + | |
113 | + protected function fetchAttributes() | |
114 | + { | |
115 | + $info = $this->makeSignedRequest('https://www.googleapis.com/oauth2/v1/userinfo'); | |
116 | + | |
117 | + $this->attributes['id'] = $info['id']; | |
118 | + $this->attributes['name'] = $info['name']; | |
119 | + | |
120 | + if (!empty($info['link'])) { | |
121 | + $this->attributes['url'] = $info['link']; | |
122 | + } | |
123 | + | |
124 | + /*if (!empty($info['gender'])) | |
125 | + $this->attributes['gender'] = $info['gender'] == 'male' ? 'M' : 'F'; | |
126 | + | |
127 | + if (!empty($info['picture'])) | |
128 | + $this->attributes['photo'] = $info['picture']; | |
129 | + | |
130 | + $info['given_name']; // first name | |
131 | + $info['family_name']; // last name | |
132 | + $info['birthday']; // format: 0000-00-00 | |
133 | + $info['locale']; // format: en*/ | |
134 | + } | |
135 | + | |
136 | + /** | |
137 | + * Returns the protected resource. | |
138 | + * | |
139 | + * @param string $url url to request. | |
140 | + * @param array $options HTTP request options. Keys: query, data, referer. | |
141 | + * @param boolean $parseResponse Whether to parse response. | |
142 | + * @return mixed the response. | |
143 | + */ | |
144 | + public function makeSignedRequest($url, $options = [], $parseResponse = true) | |
145 | + { | |
146 | + if (!isset($options['query']['alt'])) { | |
147 | + $options['query']['alt'] = 'json'; | |
148 | + } | |
149 | + return parent::makeSignedRequest($url, $options, $parseResponse); | |
150 | + } | |
151 | + | |
152 | + /** | |
153 | + * Returns the error array. | |
154 | + * | |
155 | + * @param array $response | |
156 | + * @return array the error array with 2 keys: code and message. Should be null if no errors. | |
157 | + */ | |
158 | + protected function fetchResponseError($response) | |
159 | + { | |
160 | + if (isset($response['error'])) { | |
161 | + return [ | |
162 | + 'code' => $response['error']['code'], | |
163 | + 'message' => $response['error']['message'], | |
164 | + ]; | |
165 | + } else { | |
166 | + return null; | |
167 | + } | |
168 | + } | |
169 | +} | |
0 | 170 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/InstagramOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * FacebookOAuth2Service class file. | |
4 | + * | |
5 | + * Register application: https://instagram.com/developer/register/ | |
6 | + * | |
7 | + * @author PhucPNT. <mail@phucpnt.com> | |
8 | + * @link http://github.com/Nodge/yii2-eauth/ | |
9 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
10 | + */ | |
11 | + | |
12 | +namespace common\components\nodge\eauth\src\services; | |
13 | + | |
14 | +use nodge\eauth\oauth2\Service; | |
15 | +use OAuth\Common\Token\TokenInterface; | |
16 | +use OAuth\OAuth2\Service\ServiceInterface; | |
17 | + | |
18 | +/** | |
19 | + * Instagram provider class. | |
20 | + * | |
21 | + * @package application.extensions.eauth.services | |
22 | + */ | |
23 | +class InstagramOAuth2Service extends Service | |
24 | +{ | |
25 | + | |
26 | + /** | |
27 | + * Defined scopes | |
28 | + * @link https://instagram.com/developer/authentication/ | |
29 | + */ | |
30 | + const SCOPE_BASIC = 'basic'; | |
31 | + const SCOPE_COMMENTS = 'comments'; | |
32 | + const SCOPE_RELATIONSHIPS = 'relationships'; | |
33 | + const SCOPE_LIKES = 'likes'; | |
34 | + | |
35 | + protected $name = 'instagram'; | |
36 | + protected $title = 'Instagram'; | |
37 | + protected $type = 'OAuth2'; | |
38 | + protected $jsArguments = ['popup' => ['width' => 900, 'height' => 550]]; | |
39 | + protected $popupDisplayName = false; | |
40 | + | |
41 | + protected $scopes = [self::SCOPE_BASIC]; | |
42 | + protected $providerOptions = [ | |
43 | + 'authorize' => 'https://api.instagram.com/oauth/authorize/', | |
44 | + 'access_token' => 'https://api.instagram.com/oauth/access_token', | |
45 | + ]; | |
46 | + protected $baseApiUrl = 'https://api.instagram.com/v1/'; | |
47 | + | |
48 | + protected $tokenDefaultLifetime = TokenInterface::EOL_NEVER_EXPIRES; | |
49 | + | |
50 | + protected function fetchAttributes() | |
51 | + { | |
52 | + $info = $this->makeSignedRequest('users/self'); | |
53 | + $data = $info['data']; | |
54 | + | |
55 | + $this->attributes = array_merge($this->attributes, [ | |
56 | + 'id' => $data['id'], | |
57 | + 'username' => $data['username'], | |
58 | + 'full_name' => $data['full_name'], | |
59 | + 'profile_picture' => $data['profile_picture'], | |
60 | + 'bio' => $data['bio'], | |
61 | + 'website' => $data['website'], | |
62 | + 'counts' => $data['counts'] | |
63 | + ]); | |
64 | + | |
65 | + return true; | |
66 | + } | |
67 | + | |
68 | + /** | |
69 | + * @return int | |
70 | + */ | |
71 | + public function getAuthorizationMethod() | |
72 | + { | |
73 | + return ServiceInterface::AUTHORIZATION_METHOD_QUERY_STRING; | |
74 | + } | |
75 | + | |
76 | + /** | |
77 | + * Returns the protected resource. | |
78 | + * | |
79 | + * @param string $url url to request. | |
80 | + * @param array $options HTTP request options. Keys: query, data, referer. | |
81 | + * @param boolean $parseResponse Whether to parse response. | |
82 | + * @return mixed the response. | |
83 | + */ | |
84 | + public function makeSignedRequest($url, $options = [], $parseResponse = true) | |
85 | + { | |
86 | + $options['query']['format'] = 'json'; | |
87 | + return parent::makeSignedRequest($url, $options, $parseResponse); | |
88 | + } | |
89 | + | |
90 | +} | |
0 | 91 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/LinkedinOAuth1Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * LinkedinOAuthService class file. | |
4 | + * | |
5 | + * Register application: https://www.linkedin.com/secure/developer | |
6 | + * Note: Integration URL should be filled with a valid callback url. | |
7 | + * | |
8 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
9 | + * @link http://github.com/Nodge/yii2-eauth/ | |
10 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
11 | + */ | |
12 | + | |
13 | +namespace common\components\nodge\eauth\src\services; | |
14 | + | |
15 | +use nodge\eauth\oauth1\Service; | |
16 | + | |
17 | +/** | |
18 | + * LinkedIn provider class. | |
19 | + * | |
20 | + * @package application.extensions.eauth.services | |
21 | + */ | |
22 | +class LinkedinOAuth1Service extends Service | |
23 | +{ | |
24 | + | |
25 | + protected $name = 'linkedin'; | |
26 | + protected $title = 'LinkedIn'; | |
27 | + protected $type = 'OAuth1'; | |
28 | + protected $jsArguments = ['popup' => ['width' => 900, 'height' => 550]]; | |
29 | + | |
30 | + protected $providerOptions = [ | |
31 | + 'request' => 'https://api.linkedin.com/uas/oauth/requestToken', | |
32 | + 'authorize' => 'https://www.linkedin.com/uas/oauth/authenticate', // https://www.linkedin.com/uas/oauth/authorize | |
33 | + 'access' => 'https://api.linkedin.com/uas/oauth/accessToken', | |
34 | + ]; | |
35 | + protected $baseApiUrl = 'http://api.linkedin.com/v1/'; | |
36 | + | |
37 | + protected function fetchAttributes() | |
38 | + { | |
39 | + $info = $this->makeSignedRequest('people/~:(id,first-name,last-name,public-profile-url)', [ | |
40 | + 'query' => [ | |
41 | + 'format' => 'json', | |
42 | + ], | |
43 | + ]); | |
44 | + | |
45 | + $this->attributes['id'] = $info['id']; | |
46 | + $this->attributes['name'] = $info['firstName'] . ' ' . $info['lastName']; | |
47 | + $this->attributes['url'] = $info['publicProfileUrl']; | |
48 | + | |
49 | + return true; | |
50 | + } | |
51 | + | |
52 | + /** | |
53 | + * Returns the error array. | |
54 | + * | |
55 | + * @param array $response | |
56 | + * @return array the error array with 2 keys: code and message. Should be null if no errors. | |
57 | + */ | |
58 | + protected function fetchResponseError($response) | |
59 | + { | |
60 | + if (isset($response['error-code'])) { | |
61 | + return [ | |
62 | + 'code' => $response['error-code'], | |
63 | + 'message' => $response['message'], | |
64 | + ]; | |
65 | + } else if (isset($response['errorCode'])) { | |
66 | + return [ | |
67 | + 'code' => $response['errorCode'], | |
68 | + 'message' => $response['message'], | |
69 | + ]; | |
70 | + } | |
71 | + return null; | |
72 | + } | |
73 | +} | |
0 | 74 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/LinkedinOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * LinkedinOAuth2Service class file. | |
4 | + * | |
5 | + * Register application: https://www.linkedin.com/secure/developer | |
6 | + * Note: Integration URL should be filled with a valid callback url. | |
7 | + * | |
8 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
9 | + * @link http://github.com/Nodge/yii2-eauth/ | |
10 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
11 | + */ | |
12 | + | |
13 | +namespace common\components\nodge\eauth\src\services; | |
14 | + | |
15 | +use OAuth\OAuth2\Service\ServiceInterface; | |
16 | +use nodge\eauth\oauth2\Service; | |
17 | + | |
18 | +/** | |
19 | + * LinkedIn provider class. | |
20 | + * | |
21 | + * @package application.extensions.eauth.services | |
22 | + */ | |
23 | +class LinkedinOAuth2Service extends Service | |
24 | +{ | |
25 | + | |
26 | + /** | |
27 | + * Defined scopes | |
28 | + * | |
29 | + * @link http://developer.linkedin.com/documents/authentication#granting | |
30 | + */ | |
31 | + const SCOPE_R_BASICPROFILE = 'r_basicprofile'; | |
32 | + const SCOPE_R_FULLPROFILE = 'r_fullprofile'; | |
33 | + const SCOPE_R_EMAILADDRESS = 'r_emailaddress'; | |
34 | + const SCOPE_R_NETWORK = 'r_network'; | |
35 | + const SCOPE_R_CONTACTINFO = 'r_contactinfo'; | |
36 | + const SCOPE_RW_NUS = 'rw_nus'; | |
37 | + const SCOPE_RW_GROUPS = 'rw_groups'; | |
38 | + const SCOPE_W_MESSAGES = 'w_messages'; | |
39 | + | |
40 | + protected $name = 'linkedin_oauth2'; | |
41 | + protected $title = 'LinkedIn'; | |
42 | + protected $type = 'OAuth2'; | |
43 | + protected $jsArguments = ['popup' => ['width' => 900, 'height' => 550]]; | |
44 | + | |
45 | + protected $scopes = [self::SCOPE_R_BASICPROFILE]; | |
46 | + protected $providerOptions = [ | |
47 | + 'authorize' => 'https://www.linkedin.com/uas/oauth2/authorization', | |
48 | + 'access_token' => 'https://www.linkedin.com/uas/oauth2/accessToken', | |
49 | + ]; | |
50 | + protected $baseApiUrl = 'https://api.linkedin.com/v1/'; | |
51 | + | |
52 | + protected function fetchAttributes() | |
53 | + { | |
54 | + $info = $this->makeSignedRequest('people/~:(id,first-name,last-name,public-profile-url)', [ | |
55 | + 'query' => [ | |
56 | + 'format' => 'json', | |
57 | + ], | |
58 | + ]); | |
59 | + | |
60 | + $this->attributes['id'] = $info['id']; | |
61 | + $this->attributes['name'] = $info['firstName'] . ' ' . $info['lastName']; | |
62 | + $this->attributes['url'] = $info['publicProfileUrl']; | |
63 | + $this->attributes['email'] = $info['emailAddress']; | |
64 | + return true; | |
65 | + } | |
66 | + | |
67 | + /** | |
68 | + * @return int | |
69 | + */ | |
70 | + public function getAuthorizationMethod() | |
71 | + { | |
72 | + return ServiceInterface::AUTHORIZATION_METHOD_QUERY_STRING_V2; | |
73 | + } | |
74 | +} | ... | ... |
common/components/nodge/eauth/src/services/LiveOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * LiveOAuth2Service class file. | |
4 | + * | |
5 | + * Register application: https://account.live.com/developers/applications/index | |
6 | + * | |
7 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
8 | + * @link http://github.com/Nodge/yii2-eauth/ | |
9 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
10 | + */ | |
11 | + | |
12 | +namespace common\components\nodge\eauth\src\services; | |
13 | + | |
14 | +use OAuth\OAuth2\Service\ServiceInterface; | |
15 | +use nodge\eauth\oauth2\Service; | |
16 | + | |
17 | +/** | |
18 | + * Microsoft Live provider class. | |
19 | + * | |
20 | + * @package application.extensions.eauth.services | |
21 | + */ | |
22 | +class LiveOAuth2Service extends Service | |
23 | +{ | |
24 | + | |
25 | + const SCOPE_BASIC = 'wl.basic'; | |
26 | + const SCOPE_OFFLINE = 'wl.offline_access'; | |
27 | + const SCOPE_SIGNIN = 'wl.signin'; | |
28 | + const SCOPE_BIRTHDAY = 'wl.birthday'; | |
29 | + const SCOPE_CALENDARS = 'wl.calendars'; | |
30 | + const SCOPE_CALENDARS_UPDATE = 'wl.calendars_update'; | |
31 | + const SCOPE_CONTACTS_BIRTHDAY = 'wl.contacts_birthday'; | |
32 | + const SCOPE_CONTACTS_CREATE = 'wl.contacts_create'; | |
33 | + const SCOPE_CONTACTS_CALENDARS = 'wl.contacts_calendars'; | |
34 | + const SCOPE_CONTACTS_PHOTOS = 'wl.contacts_photos'; | |
35 | + const SCOPE_CONTACTS_SKYDRIVE = 'wl.contacts_skydrive'; | |
36 | + const SCOPE_EMAILS = 'wl.emails'; | |
37 | + const sCOPE_EVENTS_CREATE = 'wl.events_create'; | |
38 | + const SCOPE_MESSENGER = 'wl.messenger'; | |
39 | + const SCOPE_PHONE_NUMBERS = 'wl.phone_numbers'; | |
40 | + const SCOPE_PHOTOS = 'wl.photos'; | |
41 | + const SCOPE_POSTAL_ADDRESSES = 'wl.postal_addresses'; | |
42 | + const SCOPE_SHARE = 'wl.share'; | |
43 | + const SCOPE_SKYDRIVE = 'wl.skydrive'; | |
44 | + const SCOPE_SKYDRIVE_UPDATE = 'wl.skydrive_update'; | |
45 | + const SCOPE_WORK_PROFILE = 'wl.work_profile'; | |
46 | + const SCOPE_APPLICATIONS = 'wl.applications'; | |
47 | + const SCOPE_APPLICATIONS_CREATE = 'wl.applications_create'; | |
48 | + | |
49 | + protected $name = 'live'; | |
50 | + protected $title = 'Live'; | |
51 | + protected $type = 'OAuth2'; | |
52 | + protected $jsArguments = ['popup' => ['width' => 500, 'height' => 600]]; | |
53 | + | |
54 | + protected $scopes = [self::SCOPE_BASIC]; | |
55 | + protected $providerOptions = [ | |
56 | + 'authorize' => 'https://login.live.com/oauth20_authorize.srf', | |
57 | + 'access_token' => 'https://login.live.com/oauth20_token.srf', | |
58 | + ]; | |
59 | + protected $baseApiUrl = 'https://apis.live.net/v5.0/'; | |
60 | + | |
61 | + protected function fetchAttributes() | |
62 | + { | |
63 | + $info = $this->makeSignedRequest('me'); | |
64 | + | |
65 | + $this->attributes['id'] = $info['id']; | |
66 | + $this->attributes['name'] = $info['name']; | |
67 | + $this->attributes['url'] = 'https://profile.live.com/cid-' . $info['id'] . '/'; | |
68 | + | |
69 | + $this->attributes['email'] = $info['emails']['account']; | |
70 | + $this->attributes['first_name'] = $info['first_name']; | |
71 | + $this->attributes['last_name'] = $info['last_name']; | |
72 | + $this->attributes['gender'] = $info['gender']; | |
73 | + $this->attributes['locale'] = $info['locale']; | |
74 | + | |
75 | + return true; | |
76 | + } | |
77 | + | |
78 | + /** | |
79 | + * @return int | |
80 | + */ | |
81 | + public function getAuthorizationMethod() | |
82 | + { | |
83 | + return ServiceInterface::AUTHORIZATION_METHOD_QUERY_STRING; | |
84 | + } | |
85 | +} | |
0 | 86 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/MailruOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * MailruOAuth2Service class file. | |
4 | + * | |
5 | + * Register application: http://api.mail.ru/sites/my/add | |
6 | + * | |
7 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
8 | + * @link http://github.com/Nodge/yii2-eauth/ | |
9 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
10 | + */ | |
11 | + | |
12 | +namespace common\components\nodge\eauth\src\services; | |
13 | + | |
14 | +use nodge\eauth\oauth2\Service; | |
15 | + | |
16 | +/** | |
17 | + * Mail.Ru provider class. | |
18 | + * | |
19 | + * @package application.extensions.eauth.services | |
20 | + */ | |
21 | +class MailruOAuth2Service extends Service | |
22 | +{ | |
23 | + | |
24 | + protected $name = 'mailru'; | |
25 | + protected $title = 'Mail.ru'; | |
26 | + protected $type = 'OAuth2'; | |
27 | + protected $jsArguments = ['popup' => ['width' => 580, 'height' => 400]]; | |
28 | + | |
29 | + protected $scopes = []; | |
30 | + protected $providerOptions = [ | |
31 | + 'authorize' => 'https://connect.mail.ru/oauth/authorize', | |
32 | + 'access_token' => 'https://connect.mail.ru/oauth/token', | |
33 | + ]; | |
34 | + protected $baseApiUrl = 'http://www.appsmail.ru/platform/api'; | |
35 | + | |
36 | + protected function fetchAttributes() | |
37 | + { | |
38 | + $tokenData = $this->getAccessTokenData(); | |
39 | + | |
40 | + $info = $this->makeSignedRequest('/', [ | |
41 | + 'query' => [ | |
42 | + 'uids' => $tokenData['params']['x_mailru_vid'], | |
43 | + 'method' => 'users.getInfo', | |
44 | + 'app_id' => $this->clientId, | |
45 | + ], | |
46 | + ]); | |
47 | + | |
48 | + $info = $info[0]; | |
49 | + | |
50 | + $this->attributes['id'] = $info['uid']; | |
51 | + $this->attributes['name'] = $info['first_name'] . ' ' . $info['last_name']; | |
52 | + $this->attributes['url'] = $info['link']; | |
53 | + | |
54 | + return true; | |
55 | + } | |
56 | + | |
57 | + /** | |
58 | + * Returns the protected resource. | |
59 | + * | |
60 | + * @param string $url url to request. | |
61 | + * @param array $options HTTP request options. Keys: query, data, referer. | |
62 | + * @param boolean $parseResponse Whether to parse response. | |
63 | + * @return mixed the response. | |
64 | + */ | |
65 | + public function makeSignedRequest($url, $options = [], $parseResponse = true) | |
66 | + { | |
67 | + $token = $this->getAccessTokenData(); | |
68 | + if (isset($token)) { | |
69 | + $options['query']['secure'] = 1; | |
70 | + $options['query']['session_key'] = $token['access_token']; | |
71 | + $params = ''; | |
72 | + ksort($options['query']); | |
73 | + foreach ($options['query'] as $k => $v) { | |
74 | + $params .= $k . '=' . $v; | |
75 | + } | |
76 | + $options['query']['sig'] = md5($params . $this->clientSecret); | |
77 | + } | |
78 | + return parent::makeSignedRequest($url, $options, $parseResponse); | |
79 | + } | |
80 | + | |
81 | + /** | |
82 | + * Returns the error array. | |
83 | + * | |
84 | + * @param array $response | |
85 | + * @return array the error array with 2 keys: code and message. Should be null if no errors. | |
86 | + */ | |
87 | + protected function fetchResponseError($response) | |
88 | + { | |
89 | + if (isset($response['error'])) { | |
90 | + return [ | |
91 | + 'code' => $response['error']['error_code'], | |
92 | + 'message' => $response['error']['error_msg'], | |
93 | + ]; | |
94 | + } else { | |
95 | + return null; | |
96 | + } | |
97 | + } | |
98 | +} | |
0 | 99 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/OdnoklassnikiOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * OdnoklassnikiOAuthService class file. | |
4 | + * | |
5 | + * Register application: http://dev.odnoklassniki.ru/wiki/pages/viewpage.action?pageId=13992188 | |
6 | + * Manage your applications: http://www.odnoklassniki.ru/dk?st.cmd=appsInfoMyDevList&st._aid=Apps_Info_MyDev | |
7 | + * Note: Enabling this service a little more difficult because of the authorization policy of the service. | |
8 | + * | |
9 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
10 | + * @link http://github.com/Nodge/yii2-eauth/ | |
11 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
12 | + */ | |
13 | + | |
14 | +namespace common\components\nodge\eauth\src\services; | |
15 | + | |
16 | +use nodge\eauth\oauth2\Service; | |
17 | + | |
18 | +/** | |
19 | + * Odnoklassniki.Ru provider class. | |
20 | + * | |
21 | + * @package application.extensions.eauth.services | |
22 | + */ | |
23 | +class OdnoklassnikiOAuth2Service extends Service | |
24 | +{ | |
25 | + | |
26 | + const SCOPE_VALUABLE_ACCESS = 'VALUABLE ACCESS'; | |
27 | + const SCOPE_SET_STATUS = 'SET STATUS'; | |
28 | + const SCOPE_PHOTO_CONTENT = 'PHOTO CONTENT'; | |
29 | + | |
30 | + protected $name = 'odnoklassniki'; | |
31 | + protected $title = 'Odnoklassniki'; | |
32 | + protected $type = 'OAuth2'; | |
33 | + protected $jsArguments = ['popup' => ['width' => 680, 'height' => 500]]; | |
34 | + | |
35 | + protected $clientPublic; | |
36 | + protected $scopes = []; | |
37 | + protected $scopeSeparator = ';'; | |
38 | + protected $providerOptions = [ | |
39 | + 'authorize' => 'http://www.odnoklassniki.ru/oauth/authorize', | |
40 | + 'access_token' => 'http://api.odnoklassniki.ru/oauth/token.do', | |
41 | + ]; | |
42 | + protected $baseApiUrl = 'http://api.odnoklassniki.ru/fb.do'; | |
43 | + | |
44 | + protected $tokenDefaultLifetime = 1500; // about 25 minutes | |
45 | + protected $validateState = false; | |
46 | + | |
47 | + protected function fetchAttributes() | |
48 | + { | |
49 | + $info = $this->makeSignedRequest('', [ | |
50 | + 'query' => [ | |
51 | + 'method' => 'users.getCurrentUser', | |
52 | + 'format' => 'JSON', | |
53 | + 'application_key' => $this->clientPublic, | |
54 | + 'client_id' => $this->clientId, | |
55 | + ], | |
56 | + ]); | |
57 | + | |
58 | + $this->attributes['id'] = $info['uid']; | |
59 | + $this->attributes['name'] = $info['first_name'] . ' ' . $info['last_name']; | |
60 | + | |
61 | + return true; | |
62 | + } | |
63 | + | |
64 | + /** | |
65 | + * @return string | |
66 | + */ | |
67 | + public function getClientPublic() | |
68 | + { | |
69 | + return $this->clientPublic; | |
70 | + } | |
71 | + | |
72 | + /** | |
73 | + * @param string $clientPublic | |
74 | + */ | |
75 | + public function setClientPublic($clientPublic) | |
76 | + { | |
77 | + $this->clientPublic = $clientPublic; | |
78 | + } | |
79 | + | |
80 | + /** | |
81 | + * Returns the protected resource. | |
82 | + * | |
83 | + * @param string $url url to request. | |
84 | + * @param array $options HTTP request options. Keys: query, data, referer. | |
85 | + * @param boolean $parseResponse Whether to parse response. | |
86 | + * @return mixed the response. | |
87 | + */ | |
88 | + public function makeSignedRequest($url, $options = [], $parseResponse = true) | |
89 | + { | |
90 | + $token = $this->getAccessTokenData(); | |
91 | + if (isset($token)) { | |
92 | + $params = ''; | |
93 | + ksort($options['query']); | |
94 | + foreach ($options['query'] as $k => $v) { | |
95 | + $params .= $k . '=' . $v; | |
96 | + } | |
97 | + $options['query']['sig'] = md5($params . md5($token['access_token'] . $this->clientSecret)); | |
98 | + $options['query']['access_token'] = $token['access_token']; | |
99 | + } | |
100 | + return parent::makeSignedRequest($url, $options, $parseResponse); | |
101 | + } | |
102 | + | |
103 | + /** | |
104 | + * Returns the error array. | |
105 | + * | |
106 | + * @param array $response | |
107 | + * @return array the error array with 2 keys: code and message. Should be null if no errors. | |
108 | + */ | |
109 | + protected function fetchResponseError($response) | |
110 | + { | |
111 | + if (isset($response['error_code'])) { | |
112 | + return [ | |
113 | + 'code' => $response['error_code'], | |
114 | + 'message' => $response['error_msg'], | |
115 | + ]; | |
116 | + } else { | |
117 | + return null; | |
118 | + } | |
119 | + } | |
120 | + | |
121 | +} | ... | ... |
common/components/nodge/eauth/src/services/SteamOpenIDService.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * SteamOpenIDService class file. | |
4 | + * | |
5 | + * @author Dmitry Ananichev <a@qozz.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace common\components\nodge\eauth\src\services; | |
11 | + | |
12 | +use nodge\eauth\openid\Service; | |
13 | + | |
14 | +/** | |
15 | + * Steam provider class. | |
16 | + * | |
17 | + * @package application.extensions.eauth.services | |
18 | + */ | |
19 | +class SteamOpenIDService extends Service | |
20 | +{ | |
21 | + | |
22 | + protected $name = 'steam'; | |
23 | + protected $title = 'Steam'; | |
24 | + protected $type = 'OpenID'; | |
25 | + protected $jsArguments = ['popup' => ['width' => 990, 'height' => 615]]; | |
26 | + | |
27 | + protected $url = 'http://steamcommunity.com/openid/'; | |
28 | + | |
29 | + protected function fetchAttributes() | |
30 | + { | |
31 | + if (isset($this->attributes['id'])) { | |
32 | + $urlChunks = explode('/', $this->attributes['id']); | |
33 | + if ($count = count($urlChunks)) { | |
34 | + $name = $urlChunks[$count - 1]; | |
35 | + $this->attributes['name'] = $name; | |
36 | + } | |
37 | + } | |
38 | + } | |
39 | + | |
40 | +} | |
0 | 41 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/TwitterOAuth1Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * TwitterOAuthService class file. | |
4 | + * | |
5 | + * Register application: https://dev.twitter.com/apps/new | |
6 | + * | |
7 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
8 | + * @link http://github.com/Nodge/yii2-eauth/ | |
9 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
10 | + */ | |
11 | + | |
12 | +namespace common\components\nodge\eauth\src\services; | |
13 | + | |
14 | +use OAuth\OAuth1\Token\TokenInterface; | |
15 | +use nodge\eauth\oauth1\Service; | |
16 | + | |
17 | + | |
18 | +/** | |
19 | + * Twitter provider class. | |
20 | + * | |
21 | + * @package application.extensions.eauth.services | |
22 | + */ | |
23 | +class TwitterOAuth1Service extends Service | |
24 | +{ | |
25 | + | |
26 | + protected $name = 'twitter'; | |
27 | + protected $title = 'Twitter'; | |
28 | + protected $type = 'OAuth1'; | |
29 | + protected $jsArguments = ['popup' => ['width' => 900, 'height' => 550]]; | |
30 | + | |
31 | + protected $providerOptions = [ | |
32 | + 'request' => 'https://api.twitter.com/oauth/request_token', | |
33 | + 'authorize' => 'https://api.twitter.com/oauth/authenticate', //https://api.twitter.com/oauth/authorize | |
34 | + 'access' => 'https://api.twitter.com/oauth/access_token', | |
35 | + ]; | |
36 | + protected $baseApiUrl = 'https://api.twitter.com/1.1/'; | |
37 | + protected $tokenDefaultLifetime = TokenInterface::EOL_NEVER_EXPIRES; | |
38 | + | |
39 | + /** | |
40 | + * @return bool | |
41 | + */ | |
42 | + protected function fetchAttributes() | |
43 | + { | |
44 | + $info = $this->makeSignedRequest('account/verify_credentials.json'); | |
45 | + | |
46 | + $this->attributes['id'] = $info['id']; | |
47 | + $this->attributes['name'] = $info['name']; | |
48 | + $this->attributes['url'] = 'http://twitter.com/account/redirect_by_id?id=' . $info['id_str']; | |
49 | + | |
50 | + $this->attributes['username'] = $info['screen_name']; | |
51 | + $this->attributes['language'] = $info['lang']; | |
52 | + $this->attributes['timezone'] = timezone_name_from_abbr('', $info['utc_offset'], date('I')); | |
53 | + $this->attributes['photo'] = $info['profile_image_url']; | |
54 | + | |
55 | + return true; | |
56 | + } | |
57 | + | |
58 | + /** | |
59 | + * Authenticate the user. | |
60 | + * | |
61 | + * @return boolean whether user was successfuly authenticated. | |
62 | + */ | |
63 | + public function authenticate() | |
64 | + { | |
65 | + if (isset($_GET['denied'])) { | |
66 | + $this->cancel(); | |
67 | + } | |
68 | + | |
69 | + return parent::authenticate(); | |
70 | + } | |
71 | +} | |
0 | 72 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/VKontakteOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * VKontakteOAuth2Service class file. | |
4 | + * | |
5 | + * Register application: http://vk.com/editapp?act=create&site=1 | |
6 | + * | |
7 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
8 | + * @link http://github.com/Nodge/yii2-eauth/ | |
9 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
10 | + */ | |
11 | + | |
12 | +namespace common\components\nodge\eauth\src\services; | |
13 | + | |
14 | +use nodge\eauth\oauth2\Service; | |
15 | +use OAuth\OAuth2\Service\ServiceInterface; | |
16 | + | |
17 | +/** | |
18 | + * VKontakte provider class. | |
19 | + * | |
20 | + * @package application.extensions.eauth.services | |
21 | + */ | |
22 | +class VKontakteOAuth2Service extends Service | |
23 | +{ | |
24 | + | |
25 | + const SCOPE_FRIENDS = 'friends'; | |
26 | + | |
27 | + protected $name = 'vkontakte'; | |
28 | + protected $title = 'VK.com'; | |
29 | + protected $type = 'OAuth2'; | |
30 | + protected $jsArguments = ['popup' => ['width' => 585, 'height' => 350]]; | |
31 | + | |
32 | + protected $scopes = [self::SCOPE_FRIENDS]; | |
33 | + protected $providerOptions = [ | |
34 | + 'authorize' => 'http://api.vk.com/oauth/authorize', | |
35 | + 'access_token' => 'https://api.vk.com/oauth/access_token', | |
36 | + ]; | |
37 | + protected $baseApiUrl = 'https://api.vk.com/method/'; | |
38 | + | |
39 | + protected function fetchAttributes() | |
40 | + { | |
41 | + $tokenData = $this->getAccessTokenData(); | |
42 | + $info = $this->makeSignedRequest('users.get.json', [ | |
43 | + 'query' => [ | |
44 | + 'uids' => $tokenData['params']['user_id'], | |
45 | + 'fields' => '', // uid, first_name and last_name is always available | |
46 | + 'fields' => 'nickname, sex, bdate, city, country, timezone, photo, photo_medium, photo_big, photo_rec', | |
47 | + ], | |
48 | + ]); | |
49 | + | |
50 | + $info = $info['response'][0]; | |
51 | + | |
52 | + $this->attributes['id'] = $info['uid']; | |
53 | + $this->attributes['name'] = $info['first_name'] . ' ' . $info['last_name']; | |
54 | + $this->attributes['url'] = 'http://vk.com/id' . $info['uid']; | |
55 | + | |
56 | + if (!empty($info['nickname'])) | |
57 | + $this->attributes['username'] = $info['nickname']; | |
58 | + else | |
59 | + $this->attributes['username'] = 'id'.$info['uid']; | |
60 | + | |
61 | + $this->attributes['gender'] = $info['sex'] == 1 ? 'F' : 'M'; | |
62 | + | |
63 | + $this->attributes['city'] = $info['city']; | |
64 | + $this->attributes['country'] = $info['country']; | |
65 | + | |
66 | + $this->attributes['timezone'] = timezone_name_from_abbr('', $info['timezone']*3600, date('I'));; | |
67 | + | |
68 | + $this->attributes['photo'] = $info['photo']; | |
69 | + $this->attributes['photo_medium'] = $info['photo_medium']; | |
70 | + $this->attributes['photo_big'] = $info['photo_big']; | |
71 | + $this->attributes['photo_rec'] = $info['photo_rec']; | |
72 | + | |
73 | + return true; | |
74 | + } | |
75 | + | |
76 | + /** | |
77 | + * Returns the error array. | |
78 | + * | |
79 | + * @param array $response | |
80 | + * @return array the error array with 2 keys: code and message. Should be null if no errors. | |
81 | + */ | |
82 | + protected function fetchResponseError($response) | |
83 | + { | |
84 | + if (isset($response['error'])) { | |
85 | + return [ | |
86 | + 'code' => is_string($response['error']) ? 0 : $response['error']['error_code'], | |
87 | +// 'message' => is_string($response['error']) ? $response['error'] : $response['error']['error_msg'], | |
88 | +// 'message' => is_string($response['error']) ? $response['error'] : $response['error']['error_msg'], | |
89 | + ]; | |
90 | + } else { | |
91 | + return null; | |
92 | + } | |
93 | + } | |
94 | + | |
95 | + /** | |
96 | + * @param array $data | |
97 | + * @return string|null | |
98 | + */ | |
99 | + public function getAccessTokenResponseError($data) | |
100 | + { | |
101 | + if (!isset($data['error'])) { | |
102 | + return null; | |
103 | + } | |
104 | + $error = $data['error']; | |
105 | + if (isset($data['error_description'])) { | |
106 | + $error .= ': ' . $data['error_description']; | |
107 | + } | |
108 | + return $error; | |
109 | + } | |
110 | + | |
111 | + /** | |
112 | + * Returns a class constant from ServiceInterface defining the authorization method used for the API. | |
113 | + * | |
114 | + * @return int | |
115 | + */ | |
116 | + public function getAuthorizationMethod() | |
117 | + { | |
118 | + return ServiceInterface::AUTHORIZATION_METHOD_QUERY_STRING; | |
119 | + } | |
120 | + | |
121 | +} | |
0 | 122 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/YahooOpenIDService.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * YahooOpenIDService class file. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace common\components\nodge\eauth\src\services; | |
11 | + | |
12 | +use nodge\eauth\openid\Service; | |
13 | + | |
14 | +/** | |
15 | + * Yahoo provider class. | |
16 | + * | |
17 | + * @package application.extensions.eauth.services | |
18 | + */ | |
19 | +class YahooOpenIDService extends Service | |
20 | +{ | |
21 | + | |
22 | + protected $name = 'yahoo'; | |
23 | + protected $title = 'Yahoo'; | |
24 | + protected $type = 'OpenID'; | |
25 | + protected $jsArguments = ['popup' => ['width' => 880, 'height' => 520]]; | |
26 | + | |
27 | + protected $url = 'https://me.yahoo.com'; | |
28 | + protected $requiredAttributes = [ | |
29 | + 'name' => ['fullname', 'namePerson'], | |
30 | + 'login' => ['nickname', 'namePerson/friendly'], | |
31 | + 'email' => ['email', 'contact/email'], | |
32 | + ]; | |
33 | + protected $optionalAttributes = [ | |
34 | + 'language' => ['language', 'pref/language'], | |
35 | + 'gender' => ['gender', 'person/gender'], | |
36 | + 'timezone' => ['timezone', 'pref/timezone'], | |
37 | + 'image' => ['image', 'media/image/default'], | |
38 | + ]; | |
39 | + | |
40 | + /*protected function fetchAttributes() { | |
41 | + $this->attributes['fullname'] = $this->attributes['name'].' '.$this->attributes['lastname']; | |
42 | + return true; | |
43 | + }*/ | |
44 | +} | |
0 | 45 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/YandexOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * YandexOAuth2Service class file. | |
4 | + * | |
5 | + * Register application: https://oauth.yandex.ru/client/my | |
6 | + * | |
7 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
8 | + * @link http://github.com/Nodge/yii2-eauth/ | |
9 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
10 | + */ | |
11 | + | |
12 | +namespace common\components\nodge\eauth\src\services; | |
13 | + | |
14 | +use OAuth\Common\Token\TokenInterface; | |
15 | +use nodge\eauth\oauth2\Service; | |
16 | + | |
17 | +/** | |
18 | + * Yandex OAuth provider class. | |
19 | + * | |
20 | + * @package application.extensions.eauth.services | |
21 | + */ | |
22 | +class YandexOAuth2Service extends Service | |
23 | +{ | |
24 | + | |
25 | + protected $name = 'yandex_oauth'; | |
26 | + protected $title = 'Yandex'; | |
27 | + protected $type = 'OAuth2'; | |
28 | + protected $jsArguments = ['popup' => ['width' => 500, 'height' => 450]]; | |
29 | + protected $tokenDefaultLifetime = TokenInterface::EOL_NEVER_EXPIRES; | |
30 | + | |
31 | + protected $scope = []; | |
32 | + protected $providerOptions = [ | |
33 | + 'authorize' => 'https://oauth.yandex.ru/authorize', | |
34 | + 'access_token' => 'https://oauth.yandex.ru/token', | |
35 | + ]; | |
36 | + | |
37 | + protected function fetchAttributes() | |
38 | + { | |
39 | + $info = $this->makeSignedRequest('https://login.yandex.ru/info'); | |
40 | + | |
41 | + $this->attributes['id'] = $info['id']; | |
42 | + $this->attributes['name'] = $info['real_name']; | |
43 | + //$this->attributes['login'] = $info['display_name']; | |
44 | + //$this->attributes['email'] = $info['emails'][0]; | |
45 | + //$this->attributes['email'] = $info['default_email']; | |
46 | + $this->attributes['gender'] = ($info['sex'] == 'male') ? 'M' : 'F'; | |
47 | + | |
48 | + return true; | |
49 | + } | |
50 | + | |
51 | +} | |
0 | 52 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/extended/FacebookOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * An example of extending the provider class. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\services\extended; | |
11 | + | |
12 | +class FacebookOAuth2Service extends \nodge\eauth\services\FacebookOAuth2Service | |
13 | +{ | |
14 | + | |
15 | + protected $scopes = [ | |
16 | + self::SCOPE_EMAIL, | |
17 | + self::SCOPE_USER_BIRTHDAY, | |
18 | + self::SCOPE_USER_HOMETOWN, | |
19 | + self::SCOPE_USER_LOCATION, | |
20 | + self::SCOPE_USER_PHOTOS, | |
21 | + ]; | |
22 | + | |
23 | + /** | |
24 | + * http://developers.facebook.com/docs/reference/api/user/ | |
25 | + * | |
26 | + * @see FacebookOAuth2Service::fetchAttributes() | |
27 | + */ | |
28 | + protected function fetchAttributes() | |
29 | + { | |
30 | + $this->attributes = $this->makeSignedRequest('me'); | |
31 | + return true; | |
32 | + } | |
33 | +} | ... | ... |
common/components/nodge/eauth/src/services/extended/GitHubOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * An example of extending the provider class. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\services\extended; | |
11 | + | |
12 | +class GitHubOAuth2Service extends \nodge\eauth\services\GitHubOAuth2Service | |
13 | +{ | |
14 | + | |
15 | + protected function fetchAttributes() | |
16 | + { | |
17 | + $info = $this->makeSignedRequest('user'); | |
18 | + | |
19 | + $this->attributes['id'] = $info['id']; | |
20 | + $this->attributes['name'] = $info['login']; | |
21 | + $this->attributes['url'] = $info['html_url']; | |
22 | + | |
23 | + $this->attributes['following'] = $info['following']; | |
24 | + $this->attributes['followers'] = $info['followers']; | |
25 | + $this->attributes['public_repos'] = $info['public_repos']; | |
26 | + $this->attributes['public_gists'] = $info['public_gists']; | |
27 | + $this->attributes['avatar_url'] = $info['avatar_url']; | |
28 | + | |
29 | + return true; | |
30 | + } | |
31 | +} | |
0 | 32 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/extended/MailruOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * An example of extending the provider class. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\services\extended; | |
11 | + | |
12 | +class MailruOAuth2Service extends \nodge\eauth\services\MailruOAuth2Service | |
13 | +{ | |
14 | + | |
15 | + protected function fetchAttributes() | |
16 | + { | |
17 | + $tokenData = $this->getAccessTokenData(); | |
18 | + | |
19 | + $info = $this->makeSignedRequest('/', [ | |
20 | + 'query' => [ | |
21 | + 'uids' => $tokenData['params']['x_mailru_vid'], | |
22 | + 'method' => 'users.getInfo', | |
23 | + 'app_id' => $this->clientId, | |
24 | + ], | |
25 | + ]); | |
26 | + | |
27 | + $info = $info[0]; | |
28 | + | |
29 | + $this->attributes['id'] = $info['uid']; | |
30 | + $this->attributes['name'] = $info['first_name'] . ' ' . $info['last_name']; | |
31 | + $this->attributes['first_name'] = $info['first_name']; | |
32 | + $this->attributes['last_name'] = $info['last_name']; | |
33 | + $this->attributes['url'] = $info['link']; | |
34 | + $this->attributes['photo'] = $info['pic']; | |
35 | + | |
36 | + return true; | |
37 | + } | |
38 | + | |
39 | +} | ... | ... |
common/components/nodge/eauth/src/services/extended/OdnoklassnikiOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * An example of extending the provider class. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\services\extended; | |
11 | + | |
12 | +class OdnoklassnikiOAuth2Service extends \nodge\eauth\services\OdnoklassnikiOAuth2Service | |
13 | +{ | |
14 | + | |
15 | + protected $scopes = [self::SCOPE_VALUABLE_ACCESS]; | |
16 | + | |
17 | + protected function fetchAttributes() | |
18 | + { | |
19 | + parent::fetchAttributes(); | |
20 | + | |
21 | + $info = $this->makeSignedRequest('', [ | |
22 | + 'query' => [ | |
23 | + 'method' => 'users.getInfo', | |
24 | + 'uids' => $this->attributes['id'], | |
25 | + 'fields' => 'url_profile', | |
26 | + 'format' => 'JSON', | |
27 | + 'application_key' => $this->clientPublic, | |
28 | + 'client_id' => $this->clientId, | |
29 | + ], | |
30 | + ]); | |
31 | + | |
32 | + preg_match('/\d+\/{0,1}$/', $info[0]->url_profile, $matches); | |
33 | + $this->attributes['id'] = (int)$matches[0]; | |
34 | + $this->attributes['url'] = $info[0]->url_profile; | |
35 | + | |
36 | + return true; | |
37 | + } | |
38 | + | |
39 | + | |
40 | + /** | |
41 | + * @param string $link | |
42 | + * @param string $message | |
43 | + * @return array | |
44 | + */ | |
45 | + public function wallPost($link, $message) | |
46 | + { | |
47 | + return $this->makeSignedRequest('', [ | |
48 | + 'query' => [ | |
49 | + 'application_key' => $this->clientPublic, | |
50 | + 'method' => 'share.addLink', | |
51 | + 'format' => 'JSON', | |
52 | + 'linkUrl' => $link, | |
53 | + 'comment' => $message, | |
54 | + ], | |
55 | + ]); | |
56 | + } | |
57 | + | |
58 | +} | ... | ... |
common/components/nodge/eauth/src/services/extended/TwitterOAuth1Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * An example of extending the provider class. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\services\extended; | |
11 | + | |
12 | +class TwitterOAuth1Service extends \nodge\eauth\services\TwitterOAuth1Service | |
13 | +{ | |
14 | + | |
15 | + protected function fetchAttributes() | |
16 | + { | |
17 | + $info = $this->makeSignedRequest('account/verify_credentials.json'); | |
18 | + | |
19 | + $this->attributes['id'] = $info['id']; | |
20 | + $this->attributes['name'] = $info['name']; | |
21 | + $this->attributes['url'] = 'http://twitter.com/account/redirect_by_id?id=' . $info['id_str']; | |
22 | + | |
23 | + $this->attributes['username'] = $info['screen_name']; | |
24 | + $this->attributes['language'] = $info['lang']; | |
25 | + $this->attributes['timezone'] = timezone_name_from_abbr('', $info['utc_offset'], date('I')); | |
26 | + $this->attributes['photo'] = $info['profile_image_url']; | |
27 | + | |
28 | + return true; | |
29 | + } | |
30 | + | |
31 | + /** | |
32 | + * Returns the error array. | |
33 | + * | |
34 | + * @param array $response | |
35 | + * @return array the error array with 2 keys: code and message. Should be null if no errors. | |
36 | + */ | |
37 | + protected function fetchResponseError($response) | |
38 | + { | |
39 | + if (isset($response['errors'])) { | |
40 | + $first = reset($response['errors']); | |
41 | + return [ | |
42 | + 'code' => $first['code'], | |
43 | + 'message' => $first['message'], | |
44 | + ]; | |
45 | + } | |
46 | + return null; | |
47 | + } | |
48 | +} | |
0 | 49 | \ No newline at end of file | ... | ... |
common/components/nodge/eauth/src/services/extended/VKontakteOAuth2Service.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * An example of extending the provider class. | |
4 | + * | |
5 | + * @author Maxim Zemskov <nodge@yandex.ru> | |
6 | + * @link http://github.com/Nodge/yii2-eauth/ | |
7 | + * @license http://www.opensource.org/licenses/bsd-license.php | |
8 | + */ | |
9 | + | |
10 | +namespace nodge\eauth\services\extended; | |
11 | + | |
12 | +class VKontakteOAuth2Service extends \nodge\eauth\services\VKontakteOAuth2Service | |
13 | +{ | |
14 | + | |
15 | + // protected $scope = 'friends'; | |
16 | + | |
17 | + protected function fetchAttributes() | |
18 | + { | |
19 | + $tokenData = $this->getAccessTokenData(); | |
20 | + $info = $this->makeSignedRequest('users.get.json', [ | |
21 | + 'query' => [ | |
22 | + 'uids' => $tokenData['params']['user_id'], | |
23 | + 'fields' => '', // uid, first_name and last_name is always available | |
24 | + 'fields' => 'nickname, sex, bdate, city, country, timezone, photo, photo_medium, photo_big, photo_rec', | |
25 | + ], | |
26 | + ]); | |
27 | + | |
28 | + $info = $info['response'][0]; | |
29 | + | |
30 | + $this->attributes = $info; | |
31 | + $this->attributes['id'] = $info['uid']; | |
32 | + $this->attributes['name'] = $info['first_name'] . ' ' . $info['last_name']; | |
33 | + $this->attributes['url'] = 'http://vk.com/id' . $info['uid']; | |
34 | + | |
35 | + if (!empty($info['nickname'])) { | |
36 | + $this->attributes['username'] = $info['nickname']; | |
37 | + } else { | |
38 | + $this->attributes['username'] = 'id' . $info['uid']; | |
39 | + } | |
40 | + | |
41 | + $this->attributes['gender'] = $info['sex'] == 1 ? 'F' : 'M'; | |
42 | + | |
43 | + if (!empty($info['timezone'])) { | |
44 | + $this->attributes['timezone'] = timezone_name_from_abbr('', $info['timezone'] * 3600, date('I')); | |
45 | + } | |
46 | + | |
47 | + return true; | |
48 | + } | |
49 | +} | ... | ... |
common/components/nodge/eauth/src/views/redirect.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +use yii\web\View; | |
4 | + | |
5 | +/** @var $this View */ | |
6 | +/** @var $url string */ | |
7 | +/** @var $redirect bool */ | |
8 | +/** @var $url string */ | |
9 | + | |
10 | +?><!DOCTYPE html> | |
11 | +<html> | |
12 | +<head> | |
13 | + <script type="text/javascript"> | |
14 | + <?php | |
15 | + $code = 'if (window.opener) {'; | |
16 | + $code .= 'window.close();'; | |
17 | + if ($redirect) { | |
18 | + $code .= 'window.opener.location = \''.addslashes($url).'\';'; | |
19 | + } | |
20 | + $code .= '}'; | |
21 | + $code .= 'else {'; | |
22 | + if ($redirect) { | |
23 | + $code .= 'window.location = \''.addslashes($url).'\';'; | |
24 | + } | |
25 | + $code .= '}'; | |
26 | + echo $code; | |
27 | + ?> | |
28 | + </script> | |
29 | +</head> | |
30 | +<body> | |
31 | + | |
32 | +<h2 id="title" style="display:none;"> | |
33 | + <?php echo \Yii::t('eauth', 'Redirecting back to the application...'); ?> | |
34 | +</h2> | |
35 | + | |
36 | +<h3 id="link"> | |
37 | + <a href="<?php echo $url; ?>"> | |
38 | + <?php echo \Yii::t('eauth', 'Click here to return to the application.'); ?> | |
39 | + </a> | |
40 | +</h3> | |
41 | + | |
42 | +<script type="text/javascript"> | |
43 | + document.getElementById('title').style.display = ''; | |
44 | + document.getElementById('link').style.display = 'none'; | |
45 | +</script> | |
46 | + | |
47 | +</body> | |
48 | +</html> | |
0 | 49 | \ No newline at end of file | ... | ... |
1 | +<?php | |
2 | + | |
3 | +use yii\helpers\Html; | |
4 | +use yii\web\View; | |
5 | + | |
6 | +/** @var $this View */ | |
7 | +/** @var $id string */ | |
8 | +/** @var $services stdClass[] See EAuth::getServices() */ | |
9 | +/** @var $action string */ | |
10 | +/** @var $popup bool */ | |
11 | +/** @var $assetBundle string Alias to AssetBundle */ | |
12 | + | |
13 | +Yii::createObject(['class' => $assetBundle])->register($this); | |
14 | + | |
15 | +// Open the authorization dilalog in popup window. | |
16 | +if ($popup) { | |
17 | + $options = []; | |
18 | + foreach ($services as $name => $service) { | |
19 | + $options[$service->id] = $service->jsArguments; | |
20 | + } | |
21 | + $this->registerJs('$("#' . $id . '").eauth(' . json_encode($options) . ');'); | |
22 | +} | |
23 | + | |
24 | +?> | |
25 | +<div class="eauth" id="<?php echo $id; ?>"> | |
26 | + <ul class="eauth-list"> | |
27 | + <?php | |
28 | + foreach ($services as $name => $service) { | |
29 | + echo '<li class="eauth-service eauth-service-id-' . $service->id . '">'; | |
30 | + echo Html::a($service->title, [$action, 'service' => $name], [ | |
31 | + 'class' => 'eauth-service-link', | |
32 | + 'data-eauth-service' => $service->id, | |
33 | + ]); | |
34 | + echo '</li>'; | |
35 | + } | |
36 | + ?> | |
37 | + </ul> | |
38 | +</div> | ... | ... |
1 | +# LightOpenID Change Log | |
2 | + | |
3 | + | |
4 | +## v1.1.2 (January 15, 2013) | |
5 | + | |
6 | +`fix` Fixed a bug in the proxy configuration. | |
7 | + | |
8 | + | |
9 | +## v1.1.1 (December 21, 2012) | |
10 | + | |
11 | +`add` Added support for overriding the initial URL XRDS lookup. | |
12 | + | |
13 | + | |
14 | +## v1.1.0 (December 02, 2012) | |
15 | + | |
16 | +`add` Added support for connecting through a proxy. | |
17 | +`add` Added support for an OpenID+OAuth hybrid protocol. | |
18 | +`add` Added SSL-validation support for HEAD-requests. | |
19 | +`fix` Fixed a bug in the attribute exchange implementation. | |
20 | +`fix` Fixed a bug in stream defaults after a HEAD request. | |
21 | + | |
22 | + | |
23 | +## v1.0.0 (June 08, 2012) | |
24 | +`fix` Fixed a bug causing validation failure when using streams. | ... | ... |
1 | +Copyright (c) 2010, Mewp | |
2 | + | |
3 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
4 | +of this software and associated documentation files (the "Software"), to deal | |
5 | +in the Software without restriction, including without limitation the rights | |
6 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
7 | +copies of the Software, and to permit persons to whom the Software is | |
8 | +furnished to do so, subject to the following conditions: | |
9 | + | |
10 | +The above copyright notice and this permission notice shall be included in | |
11 | +all copies or substantial portions of the Software. | |
12 | + | |
13 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
14 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
15 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
16 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
17 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
18 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
19 | +THE SOFTWARE. | |
0 | 20 | \ No newline at end of file | ... | ... |
1 | +# LightOpenID | |
2 | + | |
3 | +Lightweight PHP5 library for easy OpenID authentication. | |
4 | + | |
5 | +* `Version....:` [**1.1.2** :arrow_double_down:][1] | |
6 | + ( *see [the change log][2] for details* ) | |
7 | +* `Released on:` January 15, 2013 | |
8 | +* `Source code:` [Gitorious :link:][3] | |
9 | + | |
10 | + [GitHub :octocat:][4] | |
11 | +* `Homepage...:` http://code.google.com/p/lightopenid/ | |
12 | +* `Author.....:` Mewp (http://mewp.s4w.pl/) | |
13 | + | |
14 | +[1]: https://github.com/iignatov/LightOpenID/archive/master.zip | |
15 | +[2]: http://github.com/iignatov/LightOpenID/blob/master/CHANGELOG.md | |
16 | +[3]: http://gitorious.org/lightopenid | |
17 | +[4]: http://github.com/iignatov/LightOpenID | |
18 | + | |
19 | + | |
20 | +## Quick start | |
21 | + | |
22 | +### Sign-on with OpenID in just 2 steps: | |
23 | + | |
24 | + 1. Authentication with the provider: | |
25 | + | |
26 | + ```php | |
27 | + $openid = new LightOpenID('my-host.example.org'); | |
28 | + | |
29 | + $openid->identity = 'ID supplied by user'; | |
30 | + | |
31 | + header('Location: ' . $openid->authUrl()); | |
32 | + ``` | |
33 | + 2. Verification: | |
34 | + | |
35 | + ```php | |
36 | + $openid = new LightOpenID('my-host.example.org'); | |
37 | + | |
38 | + if ($openid->mode) { | |
39 | + echo $openid->validate() ? 'Logged in.' : 'Failed!'; | |
40 | + } | |
41 | + ``` | |
42 | + | |
43 | +### Support for AX and SREG extensions: | |
44 | + | |
45 | + To use the AX and SREG extensions, specify `$openid->required` and/or `$openid->optional` | |
46 | + before calling `$openid->authUrl()`. These are arrays, with values being AX schema paths | |
47 | + (the 'path' part of the URL). For example: | |
48 | + | |
49 | + ```php | |
50 | + $openid->required = array('namePerson/friendly', 'contact/email'); | |
51 | + $openid->optional = array('namePerson/first'); | |
52 | + ``` | |
53 | + | |
54 | + Note that if the server supports only SREG or OpenID 1.1, these are automaticaly mapped | |
55 | + to SREG names. To get the values use: | |
56 | + | |
57 | + ```php | |
58 | + $openid->getAttributes(); | |
59 | + ``` | |
60 | + | |
61 | + For more information see [USAGE.md](http://github.com/iignatov/LightOpenID/blob/master/USAGE.md). | |
62 | + | |
63 | + | |
64 | +## Requirements | |
65 | + | |
66 | +This library requires PHP >= 5.1.2 with cURL or HTTP/HTTPS stream wrappers enabled. | |
67 | + | |
68 | + | |
69 | +## Features | |
70 | + | |
71 | +* Easy to use - you can code a functional client in less than ten lines of code. | |
72 | +* Uses cURL if avaiable, PHP-streams otherwise. | |
73 | +* Supports both OpenID 1.1 and 2.0. | |
74 | +* Supports Yadis discovery. | |
75 | +* Supports only stateless/dumb protocol. | |
76 | +* Works with PHP >= 5. | |
77 | +* Generates no errors with `error_reporting(E_ALL | E_STRICT)`. | |
78 | + | |
79 | + | |
80 | +## Links | |
81 | + | |
82 | +* [JavaScript OpenID Selector](http://code.google.com/p/openid-selector/) - | |
83 | + simple user interface that can be used with LightOpenID. | |
84 | +* [HybridAuth](http://hybridauth.sourceforge.net/) - | |
85 | + easy to install and use social sign on PHP library, which uses LightOpenID. | |
86 | +* [OpenID Dev Specifications](http://openid.net/developers/specs/) - | |
87 | + documentation for the OpenID extensions and related topics. | |
88 | + | |
89 | + | |
90 | +## License | |
91 | + | |
92 | +[LightOpenID](http://github.com/iignatov/LightOpenID) | |
93 | +is an open source software available under the | |
94 | +[MIT License](http://opensource.org/licenses/mit-license.php). | ... | ... |
1 | +# LightOpenID Quick Start | |
2 | + | |
3 | + | |
4 | +## Sign-on with OpenID is a two step process: | |
5 | + | |
6 | + 1. Step one is authentication with the provider: | |
7 | + | |
8 | + ```php | |
9 | + $openid = new LightOpenID('my-host.example.org'); | |
10 | + | |
11 | + $openid->identity = 'ID supplied by the user'; | |
12 | + | |
13 | + header('Location: ' . $openid->authUrl()); | |
14 | + ``` | |
15 | + | |
16 | + The provider then sends various parameters via GET, one of which is `openid_mode`. | |
17 | + | |
18 | + 2. Step two is verification: | |
19 | + | |
20 | + ```php | |
21 | + $openid = new LightOpenID('my-host.example.org'); | |
22 | + | |
23 | + if ($openid->mode) { | |
24 | + echo $openid->validate() ? 'Logged in.' : 'Failed!'; | |
25 | + } | |
26 | + ``` | |
27 | + | |
28 | + | |
29 | +### Notes: | |
30 | + | |
31 | + Change 'my-host.example.org' to your domain name. Do NOT use `$_SERVER['HTTP_HOST']` | |
32 | + for that, unless you know what you're doing. | |
33 | + | |
34 | + Optionally, you can set `$returnUrl` and `$realm` (or `$trustRoot`, which is an alias). | |
35 | + The default values for those are: | |
36 | + | |
37 | + ```php | |
38 | + $openid->realm = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; | |
39 | + $openid->returnUrl = $openid->realm . $_SERVER['REQUEST_URI']; | |
40 | + ``` | |
41 | + | |
42 | + If you don't know their meaning, refer to any OpenID tutorial, or specification. | |
43 | + | |
44 | + | |
45 | +## Basic configuration options: | |
46 | + | |
47 | +<table> | |
48 | + <tr> | |
49 | + <th>name</th> | |
50 | + <th>description</th> | |
51 | + </tr> | |
52 | + <tr> | |
53 | + <td>identity</td> | |
54 | + <td> | |
55 | + Sets (or gets) the identity supplied by an user. Set it | |
56 | + before calling authUrl(), and get after validate(). | |
57 | + </td> | |
58 | + </tr> | |
59 | + <tr> | |
60 | + <td>returnUrl</td> | |
61 | + <td> | |
62 | + Users will be redirected to this url after they complete | |
63 | + authentication with their provider. Default: current url. | |
64 | + </td> | |
65 | + </tr> | |
66 | + <tr> | |
67 | + <td>realm</td> | |
68 | + <td> | |
69 | + The realm user is signing into. Providers usually say | |
70 | + "You are sgning into $realm". Must be in the same domain | |
71 | + as returnUrl. Usually, this should be the host part of | |
72 | + your site's url. And that's the default. | |
73 | + </td> | |
74 | + </tr> | |
75 | + <tr> | |
76 | + <td>required and optional</td> | |
77 | + <td> | |
78 | + Attempts to fetch more information about an user. | |
79 | + See <a href="#common-ax-attributes">Common AX attributes</a>. | |
80 | + </td> | |
81 | + </tr> | |
82 | + <tr> | |
83 | + <td>verify_peer</td> | |
84 | + <td> | |
85 | + When using https, attempts to verify peer's certificate. | |
86 | + See <a href="http://php.net/manual/en/function.curl-setopt.php">CURLOPT_SSL_VERIFYPEER</a>. | |
87 | + </td> | |
88 | + </tr> | |
89 | + <tr> | |
90 | + <td>cainfo and capath</td> | |
91 | + <td> | |
92 | + When verify_peer is true, sets the CA info file and directory. | |
93 | + See <a href="http://php.net/manual/en/function.curl-setopt.php">CURLOPT_SSL_CAINFO</a> | |
94 | + and <a href="http://php.net/manual/en/function.curl-setopt.php">CURLOPT_SSL_CAPATH</a>. | |
95 | + </td> | |
96 | + </tr> | |
97 | +</table> | |
98 | + | |
99 | + | |
100 | +## AX and SREG extensions are supported: | |
101 | + | |
102 | + To use them, specify `$openid->required` and/or `$openid->optional` before calling | |
103 | + `$openid->authUrl()`. These are arrays, with values being AX schema paths (the 'path' | |
104 | + part of the URL). For example: | |
105 | + | |
106 | + ```php | |
107 | + $openid->required = array('namePerson/friendly', 'contact/email'); | |
108 | + $openid->optional = array('namePerson/first'); | |
109 | + ``` | |
110 | + | |
111 | + Note that if the server supports only SREG or OpenID 1.1, these are automaticaly mapped | |
112 | + to SREG names, so that user doesn't have to know anything about the server. | |
113 | + To get the values, use `$openid->getAttributes()`. | |
114 | + | |
115 | + | |
116 | +### Common AX attributes | |
117 | + | |
118 | + Here is a list of the more common AX attributes (from [axschema.org](http://www.axschema.org/types/)): | |
119 | + | |
120 | + Name | Meaning | |
121 | + ------------------------|--------------- | |
122 | + namePerson/friendly | Alias/Username | |
123 | + contact/email | Email | |
124 | + namePerson | Full name | |
125 | + birthDate | Birth date | |
126 | + person/gender | Gender | |
127 | + contact/postalCode/home | Postal code | |
128 | + contact/country/home | Country | |
129 | + pref/language | Language | |
130 | + pref/timezone | Time zone | |
131 | + | |
132 | + Note that even if you mark some field as required, there is no guarantee that you'll get any | |
133 | + information from a provider. Not all providers support all of these attributes, and some don't | |
134 | + support these extensions at all. | |
135 | + | |
136 | + Google, for example, completely ignores optional parameters, and for the required ones, it supports, | |
137 | + according to [it's website](http://code.google.com/apis/accounts/docs/OpenID.html): | |
138 | + | |
139 | + * namePerson/first (first name) | |
140 | + * namePerson/last (last name) | |
141 | + * contact/country/home | |
142 | + * contact/email | |
143 | + * pref/language | |
144 | + | ... | ... |
1 | +{ | |
2 | + "name": "nodge/lightopenid", | |
3 | + "description": "Lightweight PHP5 library for easy OpenID authentication.", | |
4 | + "keywords": ["openid", "authentication"], | |
5 | + "homepage": "https://github.com/Nodge/LightOpenID", | |
6 | + "type": "library", | |
7 | + "license": "MIT License", | |
8 | + "authors": [ | |
9 | + { | |
10 | + "name": "Mewp", | |
11 | + "homepage": "http://code.google.com/p/lightopenid/" | |
12 | + }, | |
13 | + { | |
14 | + "name": "Ignat Ignatov", | |
15 | + "homepage": "https://github.com/iignatov/LightOpenID" | |
16 | + } | |
17 | + ], | |
18 | + "require": { | |
19 | + "php": ">=5.2" | |
20 | + }, | |
21 | + "autoload": { | |
22 | + "classmap": ["openid.php", "provider/provider.php"] | |
23 | + } | |
24 | +} | |
0 | 25 | \ No newline at end of file | ... | ... |
common/components/nodge/lightopenid/example-google.php
0 → 100644
1 | +<?php | |
2 | +# Logging in with Google accounts requires setting special identity, | |
3 | +# so this example shows how to do it. | |
4 | +require 'openid.php'; | |
5 | + | |
6 | +try { | |
7 | + # Change 'example.org' to your domain name. | |
8 | + $domain = 'example.org'; | |
9 | + $openid = new LightOpenID($domain); | |
10 | + | |
11 | + if (!$openid->mode) { | |
12 | + if (isset($_GET['login'])) { | |
13 | + $openid->identity = 'https://www.google.com/accounts/o8/id'; | |
14 | + header('Location: ' . $openid->authUrl()); | |
15 | + } | |
16 | +?> | |
17 | +<form action="?login" method="post"> | |
18 | + <button>Login with Google</button> | |
19 | +</form> | |
20 | +<?php | |
21 | + } elseif($openid->mode == 'cancel') { | |
22 | + echo 'User has canceled authentication!'; | |
23 | + } else { | |
24 | + echo 'User ' . ($openid->validate() ? $openid->identity . ' has ' : 'has not ') . 'logged in.'; | |
25 | + } | |
26 | +} catch(ErrorException $e) { | |
27 | + echo $e->getMessage(); | |
28 | +} | ... | ... |
common/components/nodge/lightopenid/example-google_apps.php
0 → 100644
1 | +<?php | |
2 | +# Logging in with Google Apps accounts requires setting special identity | |
3 | +# and XRDS override, so this example shows how to do it. | |
4 | +require 'openid.php'; | |
5 | + | |
6 | +try { | |
7 | + # Change 'example.org' to your domain name. | |
8 | + $domain = 'example.org'; | |
9 | + $openid = new LightOpenID($domain); | |
10 | + $openid->xrdsOverride = array( | |
11 | + '#^http://' . $domain . '/openid\?id=\d+$#', | |
12 | + 'https://www.google.com/accounts/o8/site-xrds?hd=' . $domain | |
13 | + ); | |
14 | + | |
15 | + if (!$openid->mode) { | |
16 | + if (isset($_GET['login'])) { | |
17 | + $openid->identity = 'https://www.google.com/accounts/o8/site-xrds?hd=' . $domain; | |
18 | + header('Location: ' . $openid->authUrl()); | |
19 | + } | |
20 | +?> | |
21 | +<form action="?login" method="post"> | |
22 | + <button>Login with Google</button> | |
23 | +</form> | |
24 | +<?php | |
25 | + } elseif($openid->mode == 'cancel') { | |
26 | + echo 'User has canceled authentication!'; | |
27 | + } else { | |
28 | + echo 'User ' . ($openid->validate() ? $openid->identity . ' has ' : 'has not ') . 'logged in.'; | |
29 | + } | |
30 | +} catch(ErrorException $e) { | |
31 | + echo $e->getMessage(); | |
32 | +} | ... | ... |
1 | +<?php | |
2 | +require 'openid.php'; | |
3 | +try { | |
4 | + # Change 'localhost' to your domain name. | |
5 | + $openid = new LightOpenID('localhost'); | |
6 | + if(!$openid->mode) { | |
7 | + if(isset($_POST['openid_identifier'])) { | |
8 | + $openid->identity = $_POST['openid_identifier']; | |
9 | + # The following two lines request email, full name, and a nickname | |
10 | + # from the provider. Remove them if you don't need that data. | |
11 | + $openid->required = array('contact/email'); | |
12 | + $openid->optional = array('namePerson', 'namePerson/friendly'); | |
13 | + header('Location: ' . $openid->authUrl()); | |
14 | + } | |
15 | +?> | |
16 | +<form action="" method="post"> | |
17 | + OpenID: <input type="text" name="openid_identifier" /> <button>Submit</button> | |
18 | +</form> | |
19 | +<?php | |
20 | + } elseif($openid->mode == 'cancel') { | |
21 | + echo 'User has canceled authentication!'; | |
22 | + } else { | |
23 | + echo 'User ' . ($openid->validate() ? $openid->identity . ' has ' : 'has not ') . 'logged in.'; | |
24 | + print_r($openid->getAttributes()); | |
25 | + } | |
26 | +} catch(ErrorException $e) { | |
27 | + echo $e->getMessage(); | |
28 | +} | ... | ... |
1 | +<?php | |
2 | +/** | |
3 | + * This class provides a simple interface for OpenID 1.1/2.0 authentication. | |
4 | + * | |
5 | + * It requires PHP >= 5.1.2 with cURL or HTTP/HTTPS stream wrappers enabled. | |
6 | + * | |
7 | + * @version v1.1.2 2013-01-15 | |
8 | + * @link http://gitorious.org/lightopenid Official Repo | |
9 | + * @link http://github.com/iignatov/LightOpenID GitHub Clone | |
10 | + * @author Mewp | |
11 | + * @copyright Copyright (c) 2010, Mewp | |
12 | + * @license http://www.opensource.org/licenses/mit-license.php MIT License | |
13 | + */ | |
14 | +class LightOpenID | |
15 | +{ | |
16 | + public $returnUrl | |
17 | + , $required = array() | |
18 | + , $optional = array() | |
19 | + , $verify_peer = null | |
20 | + , $capath = null | |
21 | + , $cainfo = null | |
22 | + , $data | |
23 | + , $oauth = array(); | |
24 | + private $identity, $claimed_id; | |
25 | + protected $server, $version, $trustRoot, $aliases, $identifier_select = false | |
26 | + , $ax = false, $sreg = false, $setup_url = null, $headers = array(), $proxy = null | |
27 | + , $xrds_override_pattern = null, $xrds_override_replacement = null; | |
28 | + static protected $ax_to_sreg = array( | |
29 | + 'namePerson/friendly' => 'nickname', | |
30 | + 'contact/email' => 'email', | |
31 | + 'namePerson' => 'fullname', | |
32 | + 'birthDate' => 'dob', | |
33 | + 'person/gender' => 'gender', | |
34 | + 'contact/postalCode/home' => 'postcode', | |
35 | + 'contact/country/home' => 'country', | |
36 | + 'pref/language' => 'language', | |
37 | + 'pref/timezone' => 'timezone', | |
38 | + ); | |
39 | + | |
40 | + function __construct($host, $proxy = null) | |
41 | + { | |
42 | + $this->trustRoot = (strpos($host, '://') ? $host : 'http://' . $host); | |
43 | + if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') | |
44 | + || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) | |
45 | + && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') | |
46 | + ) { | |
47 | + $this->trustRoot = (strpos($host, '://') ? $host : 'https://' . $host); | |
48 | + } | |
49 | + | |
50 | + if(($host_end = strpos($this->trustRoot, '/', 8)) !== false) { | |
51 | + $this->trustRoot = substr($this->trustRoot, 0, $host_end); | |
52 | + } | |
53 | + | |
54 | + $this->set_proxy($proxy); | |
55 | + | |
56 | + $uri = rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#', '', $_SERVER['REQUEST_URI']), '?'); | |
57 | + $this->returnUrl = $this->trustRoot . $uri; | |
58 | + | |
59 | + $this->data = ($_SERVER['REQUEST_METHOD'] === 'POST') ? $_POST : $_GET; | |
60 | + | |
61 | + if(!function_exists('curl_init') && !in_array('https', stream_get_wrappers())) { | |
62 | + throw new ErrorException('You must have either https wrappers or curl enabled.'); | |
63 | + } | |
64 | + } | |
65 | + | |
66 | + function __set($name, $value) | |
67 | + { | |
68 | + switch ($name) { | |
69 | + case 'identity': | |
70 | + if (strlen($value = trim((String) $value))) { | |
71 | + if (preg_match('#^xri:/*#i', $value, $m)) { | |
72 | + $value = substr($value, strlen($m[0])); | |
73 | + } elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) { | |
74 | + $value = "http://$value"; | |
75 | + } | |
76 | + if (preg_match('#^https?://[^/]+$#i', $value, $m)) { | |
77 | + $value .= '/'; | |
78 | + } | |
79 | + } | |
80 | + $this->$name = $this->claimed_id = $value; | |
81 | + break; | |
82 | + case 'trustRoot': | |
83 | + case 'realm': | |
84 | + $this->trustRoot = trim($value); | |
85 | + break; | |
86 | + case 'xrdsOverride': | |
87 | + if (is_array($value)) { | |
88 | + list($pattern, $replacement) = $value; | |
89 | + $this->xrds_override_pattern = $pattern; | |
90 | + $this->xrds_override_replacement = $replacement; | |
91 | + } else { | |
92 | + trigger_error('Invalid value specified for "xrdsOverride".', E_USER_ERROR); | |
93 | + } | |
94 | + break; | |
95 | + } | |
96 | + } | |
97 | + | |
98 | + function __get($name) | |
99 | + { | |
100 | + switch ($name) { | |
101 | + case 'identity': | |
102 | + # We return claimed_id instead of identity, | |
103 | + # because the developer should see the claimed identifier, | |
104 | + # i.e. what he set as identity, not the op-local identifier (which is what we verify) | |
105 | + return $this->claimed_id; | |
106 | + case 'trustRoot': | |
107 | + case 'realm': | |
108 | + return $this->trustRoot; | |
109 | + case 'mode': | |
110 | + return empty($this->data['openid_mode']) ? null : $this->data['openid_mode']; | |
111 | + } | |
112 | + } | |
113 | + | |
114 | + function set_proxy($proxy) | |
115 | + { | |
116 | + if (!empty($proxy)) { | |
117 | + // When the proxy is a string - try to parse it. | |
118 | + if (!is_array($proxy)) { | |
119 | + $proxy = parse_url($proxy); | |
120 | + } | |
121 | + | |
122 | + // Check if $proxy is valid after the parsing. | |
123 | + if ($proxy && !empty($proxy['host'])) { | |
124 | + // Make sure that a valid port number is specified. | |
125 | + if (array_key_exists('port', $proxy)) { | |
126 | + if (!is_int($proxy['port'])) { | |
127 | + $proxy['port'] = is_numeric($proxy['port']) ? intval($proxy['port']) : 0; | |
128 | + } | |
129 | + | |
130 | + if ($proxy['port'] <= 0) { | |
131 | + throw new ErrorException('The specified proxy port number is invalid.'); | |
132 | + } | |
133 | + } | |
134 | + | |
135 | + $this->proxy = $proxy; | |
136 | + } | |
137 | + } | |
138 | + } | |
139 | + | |
140 | + /** | |
141 | + * Checks if the server specified in the url exists. | |
142 | + * | |
143 | + * @param $url url to check | |
144 | + * @return true, if the server exists; false otherwise | |
145 | + */ | |
146 | + function hostExists($url) | |
147 | + { | |
148 | + if (strpos($url, '/') === false) { | |
149 | + $server = $url; | |
150 | + } else { | |
151 | + $server = @parse_url($url, PHP_URL_HOST); | |
152 | + } | |
153 | + | |
154 | + if (!$server) { | |
155 | + return false; | |
156 | + } | |
157 | + | |
158 | + return !!gethostbynamel($server); | |
159 | + } | |
160 | + | |
161 | + protected function request_curl($url, $method='GET', $params=array(), $update_claimed_id) | |
162 | + { | |
163 | + $params = http_build_query($params, '', '&'); | |
164 | + $curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : '')); | |
165 | + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); | |
166 | + curl_setopt($curl, CURLOPT_HEADER, false); | |
167 | + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); | |
168 | + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
169 | + curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*')); | |
170 | + | |
171 | + if (!empty($this->proxy)) { | |
172 | + curl_setopt($curl, CURLOPT_PROXY, $this->proxy['host']); | |
173 | + | |
174 | + if (!empty($this->proxy['port'])) { | |
175 | + curl_setopt($curl, CURLOPT_PROXYPORT, $this->proxy['port']); | |
176 | + } | |
177 | + | |
178 | + if (!empty($this->proxy['user'])) { | |
179 | + curl_setopt($curl, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']); | |
180 | + } | |
181 | + } | |
182 | + | |
183 | + if($this->verify_peer !== null) { | |
184 | + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); | |
185 | + if($this->capath) { | |
186 | + curl_setopt($curl, CURLOPT_CAPATH, $this->capath); | |
187 | + } | |
188 | + | |
189 | + if($this->cainfo) { | |
190 | + curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo); | |
191 | + } | |
192 | + } | |
193 | + | |
194 | + if ($method == 'POST') { | |
195 | + curl_setopt($curl, CURLOPT_POST, true); | |
196 | + curl_setopt($curl, CURLOPT_POSTFIELDS, $params); | |
197 | + } elseif ($method == 'HEAD') { | |
198 | + curl_setopt($curl, CURLOPT_HEADER, true); | |
199 | + curl_setopt($curl, CURLOPT_NOBODY, true); | |
200 | + } else { | |
201 | + curl_setopt($curl, CURLOPT_HEADER, true); | |
202 | + curl_setopt($curl, CURLOPT_HTTPGET, true); | |
203 | + } | |
204 | + $response = curl_exec($curl); | |
205 | + | |
206 | + if($method == 'HEAD' && curl_getinfo($curl, CURLINFO_HTTP_CODE) == 405) { | |
207 | + curl_setopt($curl, CURLOPT_HTTPGET, true); | |
208 | + $response = curl_exec($curl); | |
209 | + $response = substr($response, 0, strpos($response, "\r\n\r\n")); | |
210 | + } | |
211 | + | |
212 | + if($method == 'HEAD' || $method == 'GET') { | |
213 | + $header_response = $response; | |
214 | + | |
215 | + # If it's a GET request, we want to only parse the header part. | |
216 | + if($method == 'GET') { | |
217 | + $header_response = substr($response, 0, strpos($response, "\r\n\r\n")); | |
218 | + } | |
219 | + | |
220 | + $headers = array(); | |
221 | + foreach(explode("\n", $header_response) as $header) { | |
222 | + $pos = strpos($header,':'); | |
223 | + if ($pos !== false) { | |
224 | + $name = strtolower(trim(substr($header, 0, $pos))); | |
225 | + $headers[$name] = trim(substr($header, $pos+1)); | |
226 | + } | |
227 | + } | |
228 | + | |
229 | + if($update_claimed_id) { | |
230 | + # Updating claimed_id in case of redirections. | |
231 | + $effective_url = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL); | |
232 | + if($effective_url != $url) { | |
233 | + $this->identity = $this->claimed_id = $effective_url; | |
234 | + } | |
235 | + } | |
236 | + | |
237 | + if($method == 'HEAD') { | |
238 | + return $headers; | |
239 | + } else { | |
240 | + $this->headers = $headers; | |
241 | + } | |
242 | + } | |
243 | + | |
244 | + if (curl_errno($curl)) { | |
245 | + throw new ErrorException(curl_error($curl), curl_errno($curl)); | |
246 | + } | |
247 | + | |
248 | + return $response; | |
249 | + } | |
250 | + | |
251 | + protected function parse_header_array($array, $update_claimed_id) | |
252 | + { | |
253 | + $headers = array(); | |
254 | + foreach($array as $header) { | |
255 | + $pos = strpos($header,':'); | |
256 | + if ($pos !== false) { | |
257 | + $name = strtolower(trim(substr($header, 0, $pos))); | |
258 | + $headers[$name] = trim(substr($header, $pos+1)); | |
259 | + | |
260 | + # Following possible redirections. The point is just to have | |
261 | + # claimed_id change with them, because the redirections | |
262 | + # are followed automatically. | |
263 | + # We ignore redirections with relative paths. | |
264 | + # If any known provider uses them, file a bug report. | |
265 | + if($name == 'location' && $update_claimed_id) { | |
266 | + if(strpos($headers[$name], 'http') === 0) { | |
267 | + $this->identity = $this->claimed_id = $headers[$name]; | |
268 | + } elseif($headers[$name][0] == '/') { | |
269 | + $parsed_url = parse_url($this->claimed_id); | |
270 | + $this->identity = | |
271 | + $this->claimed_id = $parsed_url['scheme'] . '://' | |
272 | + . $parsed_url['host'] | |
273 | + . $headers[$name]; | |
274 | + } | |
275 | + } | |
276 | + } | |
277 | + } | |
278 | + return $headers; | |
279 | + } | |
280 | + | |
281 | + protected function request_streams($url, $method='GET', $params=array(), $update_claimed_id) | |
282 | + { | |
283 | + if(!$this->hostExists($url)) { | |
284 | + throw new ErrorException("Could not connect to $url.", 404); | |
285 | + } | |
286 | + | |
287 | + $params = http_build_query($params, '', '&'); | |
288 | + switch($method) { | |
289 | + case 'GET': | |
290 | + $opts = array( | |
291 | + 'http' => array( | |
292 | + 'method' => 'GET', | |
293 | + 'header' => 'Accept: application/xrds+xml, */*', | |
294 | + 'ignore_errors' => true, | |
295 | + ), 'ssl' => array( | |
296 | + 'CN_match' => parse_url($url, PHP_URL_HOST), | |
297 | + ), | |
298 | + ); | |
299 | + $url = $url . ($params ? '?' . $params : ''); | |
300 | + if (!empty($this->proxy)) { | |
301 | + $opts['http']['proxy'] = $this->proxy_url(); | |
302 | + } | |
303 | + break; | |
304 | + case 'POST': | |
305 | + $opts = array( | |
306 | + 'http' => array( | |
307 | + 'method' => 'POST', | |
308 | + 'header' => 'Content-type: application/x-www-form-urlencoded', | |
309 | + 'content' => $params, | |
310 | + 'ignore_errors' => true, | |
311 | + ), 'ssl' => array( | |
312 | + 'CN_match' => parse_url($url, PHP_URL_HOST), | |
313 | + ), | |
314 | + ); | |
315 | + if (!empty($this->proxy)) { | |
316 | + $opts['http']['proxy'] = $this->proxy_url(); | |
317 | + } | |
318 | + break; | |
319 | + case 'HEAD': | |
320 | + // We want to send a HEAD request, but since get_headers() doesn't | |
321 | + // accept $context parameter, we have to change the defaults. | |
322 | + $default = stream_context_get_options(stream_context_get_default()); | |
323 | + | |
324 | + // PHP does not reset all options. Instead, it just sets the options | |
325 | + // available in the passed array, therefore set the defaults manually. | |
326 | + $default += array( | |
327 | + 'http' => array(), | |
328 | + 'ssl' => array() | |
329 | + ); | |
330 | + $default['http'] += array( | |
331 | + 'method' => 'GET', | |
332 | + 'header' => '', | |
333 | + 'ignore_errors' => false | |
334 | + ); | |
335 | + $default['ssl'] += array( | |
336 | + 'CN_match' => '' | |
337 | + ); | |
338 | + | |
339 | + $opts = array( | |
340 | + 'http' => array( | |
341 | + 'method' => 'HEAD', | |
342 | + 'header' => 'Accept: application/xrds+xml, */*', | |
343 | + 'ignore_errors' => true, | |
344 | + ), | |
345 | + 'ssl' => array( | |
346 | + 'CN_match' => parse_url($url, PHP_URL_HOST) | |
347 | + ) | |
348 | + ); | |
349 | + | |
350 | + // Enable validation of the SSL certificates. | |
351 | + if ($this->verify_peer) { | |
352 | + $default['ssl'] += array( | |
353 | + 'verify_peer' => false, | |
354 | + 'capath' => '', | |
355 | + 'cafile' => '' | |
356 | + ); | |
357 | + $opts['ssl'] += array( | |
358 | + 'verify_peer' => true, | |
359 | + 'capath' => $this->capath, | |
360 | + 'cafile' => $this->cainfo | |
361 | + ); | |
362 | + } | |
363 | + | |
364 | + // Change the stream context options. | |
365 | + stream_context_get_default($opts); | |
366 | + | |
367 | + $headers = get_headers($url . ($params ? '?' . $params : '')); | |
368 | + | |
369 | + // Restore the stream context options. | |
370 | + stream_context_get_default($default); | |
371 | + | |
372 | + if (!empty($headers)) { | |
373 | + if (intval(substr($headers[0], strlen('HTTP/1.1 '))) == 405) { | |
374 | + // The server doesn't support HEAD - emulate it with a GET. | |
375 | + $args = func_get_args(); | |
376 | + $args[1] = 'GET'; | |
377 | + call_user_func_array(array($this, 'request_streams'), $args); | |
378 | + $headers = $this->headers; | |
379 | + } else { | |
380 | + $headers = $this->parse_header_array($headers, $update_claimed_id); | |
381 | + } | |
382 | + } else { | |
383 | + $headers = array(); | |
384 | + } | |
385 | + | |
386 | + return $headers; | |
387 | + } | |
388 | + | |
389 | + if ($this->verify_peer) { | |
390 | + $opts['ssl'] += array( | |
391 | + 'verify_peer' => true, | |
392 | + 'capath' => $this->capath, | |
393 | + 'cafile' => $this->cainfo | |
394 | + ); | |
395 | + } | |
396 | + | |
397 | + $context = stream_context_create ($opts); | |
398 | + $data = file_get_contents($url, false, $context); | |
399 | + # This is a hack for providers who don't support HEAD requests. | |
400 | + # It just creates the headers array for the last request in $this->headers. | |
401 | + if(isset($http_response_header)) { | |
402 | + $this->headers = $this->parse_header_array($http_response_header, $update_claimed_id); | |
403 | + } | |
404 | + | |
405 | + return $data; | |
406 | + } | |
407 | + | |
408 | + protected function request($url, $method='GET', $params=array(), $update_claimed_id=false) | |
409 | + { | |
410 | + if (function_exists('curl_init') | |
411 | + && (!in_array('https', stream_get_wrappers()) || !ini_get('safe_mode') && !ini_get('open_basedir')) | |
412 | + ) { | |
413 | + return $this->request_curl($url, $method, $params, $update_claimed_id); | |
414 | + } | |
415 | + return $this->request_streams($url, $method, $params, $update_claimed_id); | |
416 | + } | |
417 | + | |
418 | + protected function proxy_url() | |
419 | + { | |
420 | + $result = ''; | |
421 | + | |
422 | + if (!empty($this->proxy)) { | |
423 | + $result = $this->proxy['host']; | |
424 | + | |
425 | + if (!empty($this->proxy['port'])) { | |
426 | + $result = $result . ':' . $this->proxy['port']; | |
427 | + } | |
428 | + | |
429 | + if (!empty($this->proxy['user'])) { | |
430 | + $result = $this->proxy['user'] . ':' . $this->proxy['pass'] . '@' . $result; | |
431 | + } | |
432 | + | |
433 | + $result = 'http://' . $result; | |
434 | + } | |
435 | + | |
436 | + return $result; | |
437 | + } | |
438 | + | |
439 | + protected function build_url($url, $parts) | |
440 | + { | |
441 | + if (isset($url['query'], $parts['query'])) { | |
442 | + $parts['query'] = $url['query'] . '&' . $parts['query']; | |
443 | + } | |
444 | + | |
445 | + $url = $parts + $url; | |
446 | + $url = $url['scheme'] . '://' | |
447 | + . (empty($url['username'])?'' | |
448 | + :(empty($url['password'])? "{$url['username']}@" | |
449 | + :"{$url['username']}:{$url['password']}@")) | |
450 | + . $url['host'] | |
451 | + . (empty($url['port'])?'':":{$url['port']}") | |
452 | + . (empty($url['path'])?'':$url['path']) | |
453 | + . (empty($url['query'])?'':"?{$url['query']}") | |
454 | + . (empty($url['fragment'])?'':"#{$url['fragment']}"); | |
455 | + return $url; | |
456 | + } | |
457 | + | |
458 | + /** | |
459 | + * Helper function used to scan for <meta>/<link> tags and extract information | |
460 | + * from them | |
461 | + */ | |
462 | + protected function htmlTag($content, $tag, $attrName, $attrValue, $valueName) | |
463 | + { | |
464 | + preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1); | |
465 | + preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i", $content, $matches2); | |
466 | + | |
467 | + $result = array_merge($matches1[1], $matches2[1]); | |
468 | + return empty($result)?false:$result[0]; | |
469 | + } | |
470 | + | |
471 | + /** | |
472 | + * Performs Yadis and HTML discovery. Normally not used. | |
473 | + * @param $url Identity URL. | |
474 | + * @return String OP Endpoint (i.e. OpenID provider address). | |
475 | + * @throws ErrorException | |
476 | + */ | |
477 | + function discover($url) | |
478 | + { | |
479 | + if (!$url) throw new ErrorException('No identity supplied.'); | |
480 | + # Use xri.net proxy to resolve i-name identities | |
481 | + if (!preg_match('#^https?:#', $url)) { | |
482 | + $url = "https://xri.net/$url"; | |
483 | + } | |
484 | + | |
485 | + # We save the original url in case of Yadis discovery failure. | |
486 | + # It can happen when we'll be lead to an XRDS document | |
487 | + # which does not have any OpenID2 services. | |
488 | + $originalUrl = $url; | |
489 | + | |
490 | + # A flag to disable yadis discovery in case of failure in headers. | |
491 | + $yadis = true; | |
492 | + | |
493 | + # Allows optional regex replacement of the URL, e.g. to use Google Apps | |
494 | + # as an OpenID provider without setting up XRDS on the domain hosting. | |
495 | + if (!is_null($this->xrds_override_pattern) && !is_null($this->xrds_override_replacement)) { | |
496 | + $url = preg_replace($this->xrds_override_pattern, $this->xrds_override_replacement, $url); | |
497 | + } | |
498 | + | |
499 | + # We'll jump a maximum of 5 times, to avoid endless redirections. | |
500 | + for ($i = 0; $i < 5; $i ++) { | |
501 | + if ($yadis) { | |
502 | + $headers = $this->request($url, 'HEAD', array(), true); | |
503 | + | |
504 | + $next = false; | |
505 | + if (isset($headers['x-xrds-location'])) { | |
506 | + $url = $this->build_url(parse_url($url), parse_url(trim($headers['x-xrds-location']))); | |
507 | + $next = true; | |
508 | + } | |
509 | + | |
510 | + if (isset($headers['content-type']) | |
511 | + && (strpos($headers['content-type'], 'application/xrds+xml') !== false | |
512 | + || strpos($headers['content-type'], 'text/xml') !== false) | |
513 | + ) { | |
514 | + # Apparently, some providers return XRDS documents as text/html. | |
515 | + # While it is against the spec, allowing this here shouldn't break | |
516 | + # compatibility with anything. | |
517 | + # --- | |
518 | + # Found an XRDS document, now let's find the server, and optionally delegate. | |
519 | + $content = $this->request($url, 'GET'); | |
520 | + | |
521 | + preg_match_all('#<Service.*?>(.*?)</Service>#s', $content, $m); | |
522 | + foreach($m[1] as $content) { | |
523 | + $content = ' ' . $content; # The space is added, so that strpos doesn't return 0. | |
524 | + | |
525 | + # OpenID 2 | |
526 | + $ns = preg_quote('http://specs.openid.net/auth/2.0/', '#'); | |
527 | + if(preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s', $content, $type)) { | |
528 | + if ($type[1] == 'server') $this->identifier_select = true; | |
529 | + | |
530 | + preg_match('#<URI.*?>(.*)</URI>#', $content, $server); | |
531 | + preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate); | |
532 | + if (empty($server)) { | |
533 | + return false; | |
534 | + } | |
535 | + # Does the server advertise support for either AX or SREG? | |
536 | + $this->ax = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>'); | |
537 | + $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') | |
538 | + || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); | |
539 | + | |
540 | + $server = $server[1]; | |
541 | + if (isset($delegate[2])) $this->identity = trim($delegate[2]); | |
542 | + $this->version = 2; | |
543 | + | |
544 | + $this->server = $server; | |
545 | + return $server; | |
546 | + } | |
547 | + | |
548 | + # OpenID 1.1 | |
549 | + $ns = preg_quote('http://openid.net/signon/1.1', '#'); | |
550 | + if (preg_match('#<Type>\s*'.$ns.'\s*</Type>#s', $content)) { | |
551 | + | |
552 | + preg_match('#<URI.*?>(.*)</URI>#', $content, $server); | |
553 | + preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate); | |
554 | + if (empty($server)) { | |
555 | + return false; | |
556 | + } | |
557 | + # AX can be used only with OpenID 2.0, so checking only SREG | |
558 | + $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') | |
559 | + || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); | |
560 | + | |
561 | + $server = $server[1]; | |
562 | + if (isset($delegate[1])) $this->identity = $delegate[1]; | |
563 | + $this->version = 1; | |
564 | + | |
565 | + $this->server = $server; | |
566 | + return $server; | |
567 | + } | |
568 | + } | |
569 | + | |
570 | + $next = true; | |
571 | + $yadis = false; | |
572 | + $url = $originalUrl; | |
573 | + $content = null; | |
574 | + break; | |
575 | + } | |
576 | + if ($next) continue; | |
577 | + | |
578 | + # There are no relevant information in headers, so we search the body. | |
579 | + $content = $this->request($url, 'GET', array(), true); | |
580 | + | |
581 | + if (isset($this->headers['x-xrds-location'])) { | |
582 | + $url = $this->build_url(parse_url($url), parse_url(trim($this->headers['x-xrds-location']))); | |
583 | + continue; | |
584 | + } | |
585 | + | |
586 | + $location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content'); | |
587 | + if ($location) { | |
588 | + $url = $this->build_url(parse_url($url), parse_url($location)); | |
589 | + continue; | |
590 | + } | |
591 | + } | |
592 | + | |
593 | + if (!$content) $content = $this->request($url, 'GET'); | |
594 | + | |
595 | + # At this point, the YADIS Discovery has failed, so we'll switch | |
596 | + # to openid2 HTML discovery, then fallback to openid 1.1 discovery. | |
597 | + $server = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href'); | |
598 | + $delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href'); | |
599 | + $this->version = 2; | |
600 | + | |
601 | + if (!$server) { | |
602 | + # The same with openid 1.1 | |
603 | + $server = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href'); | |
604 | + $delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href'); | |
605 | + $this->version = 1; | |
606 | + } | |
607 | + | |
608 | + if ($server) { | |
609 | + # We found an OpenID2 OP Endpoint | |
610 | + if ($delegate) { | |
611 | + # We have also found an OP-Local ID. | |
612 | + $this->identity = $delegate; | |
613 | + } | |
614 | + $this->server = $server; | |
615 | + return $server; | |
616 | + } | |
617 | + | |
618 | + throw new ErrorException("No OpenID Server found at $url", 404); | |
619 | + } | |
620 | + throw new ErrorException('Endless redirection!', 500); | |
621 | + } | |
622 | + | |
623 | + protected function sregParams() | |
624 | + { | |
625 | + $params = array(); | |
626 | + # We always use SREG 1.1, even if the server is advertising only support for 1.0. | |
627 | + # That's because it's fully backwards compatibile with 1.0, and some providers | |
628 | + # advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com | |
629 | + $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1'; | |
630 | + if ($this->required) { | |
631 | + $params['openid.sreg.required'] = array(); | |
632 | + foreach ($this->required as $required) { | |
633 | + if (!isset(self::$ax_to_sreg[$required])) continue; | |
634 | + $params['openid.sreg.required'][] = self::$ax_to_sreg[$required]; | |
635 | + } | |
636 | + $params['openid.sreg.required'] = implode(',', $params['openid.sreg.required']); | |
637 | + } | |
638 | + | |
639 | + if ($this->optional) { | |
640 | + $params['openid.sreg.optional'] = array(); | |
641 | + foreach ($this->optional as $optional) { | |
642 | + if (!isset(self::$ax_to_sreg[$optional])) continue; | |
643 | + $params['openid.sreg.optional'][] = self::$ax_to_sreg[$optional]; | |
644 | + } | |
645 | + $params['openid.sreg.optional'] = implode(',', $params['openid.sreg.optional']); | |
646 | + } | |
647 | + return $params; | |
648 | + } | |
649 | + | |
650 | + protected function axParams() | |
651 | + { | |
652 | + $params = array(); | |
653 | + if ($this->required || $this->optional) { | |
654 | + $params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0'; | |
655 | + $params['openid.ax.mode'] = 'fetch_request'; | |
656 | + $this->aliases = array(); | |
657 | + $counts = array(); | |
658 | + $required = array(); | |
659 | + $optional = array(); | |
660 | + foreach (array('required','optional') as $type) { | |
661 | + foreach ($this->$type as $alias => $field) { | |
662 | + if (is_int($alias)) $alias = strtr($field, '/', '_'); | |
663 | + $this->aliases[$alias] = 'http://axschema.org/' . $field; | |
664 | + if (empty($counts[$alias])) $counts[$alias] = 0; | |
665 | + $counts[$alias] += 1; | |
666 | + ${$type}[] = $alias; | |
667 | + } | |
668 | + } | |
669 | + foreach ($this->aliases as $alias => $ns) { | |
670 | + $params['openid.ax.type.' . $alias] = $ns; | |
671 | + } | |
672 | + foreach ($counts as $alias => $count) { | |
673 | + if ($count == 1) continue; | |
674 | + $params['openid.ax.count.' . $alias] = $count; | |
675 | + } | |
676 | + | |
677 | + # Don't send empty ax.requied and ax.if_available. | |
678 | + # Google and possibly other providers refuse to support ax when one of these is empty. | |
679 | + if($required) { | |
680 | + $params['openid.ax.required'] = implode(',', $required); | |
681 | + } | |
682 | + if($optional) { | |
683 | + $params['openid.ax.if_available'] = implode(',', $optional); | |
684 | + } | |
685 | + } | |
686 | + return $params; | |
687 | + } | |
688 | + | |
689 | + protected function authUrl_v1($immediate) | |
690 | + { | |
691 | + $returnUrl = $this->returnUrl; | |
692 | + # If we have an openid.delegate that is different from our claimed id, | |
693 | + # we need to somehow preserve the claimed id between requests. | |
694 | + # The simplest way is to just send it along with the return_to url. | |
695 | + if($this->identity != $this->claimed_id) { | |
696 | + $returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->claimed_id; | |
697 | + } | |
698 | + | |
699 | + $params = array( | |
700 | + 'openid.return_to' => $returnUrl, | |
701 | + 'openid.mode' => $immediate ? 'checkid_immediate' : 'checkid_setup', | |
702 | + 'openid.identity' => $this->identity, | |
703 | + 'openid.trust_root' => $this->trustRoot, | |
704 | + ) + $this->sregParams(); | |
705 | + | |
706 | + return $this->build_url(parse_url($this->server) | |
707 | + , array('query' => http_build_query($params, '', '&'))); | |
708 | + } | |
709 | + | |
710 | + protected function authUrl_v2($immediate) | |
711 | + { | |
712 | + $params = array( | |
713 | + 'openid.ns' => 'http://specs.openid.net/auth/2.0', | |
714 | + 'openid.mode' => $immediate ? 'checkid_immediate' : 'checkid_setup', | |
715 | + 'openid.return_to' => $this->returnUrl, | |
716 | + 'openid.realm' => $this->trustRoot, | |
717 | + ); | |
718 | + | |
719 | + if ($this->ax) { | |
720 | + $params += $this->axParams(); | |
721 | + } | |
722 | + | |
723 | + if ($this->sreg) { | |
724 | + $params += $this->sregParams(); | |
725 | + } | |
726 | + | |
727 | + if (!$this->ax && !$this->sreg) { | |
728 | + # If OP doesn't advertise either SREG, nor AX, let's send them both | |
729 | + # in worst case we don't get anything in return. | |
730 | + $params += $this->axParams() + $this->sregParams(); | |
731 | + } | |
732 | + | |
733 | + if (!empty($this->oauth) && is_array($this->oauth)) { | |
734 | + $params['openid.ns.oauth'] = 'http://specs.openid.net/extensions/oauth/1.0'; | |
735 | + $params['openid.oauth.consumer'] = str_replace(array('http://', 'https://'), '', $this->trustRoot); | |
736 | + $params['openid.oauth.scope'] = implode(' ', $this->oauth); | |
737 | + } | |
738 | + | |
739 | + if ($this->identifier_select) { | |
740 | + $params['openid.identity'] = $params['openid.claimed_id'] | |
741 | + = 'http://specs.openid.net/auth/2.0/identifier_select'; | |
742 | + } else { | |
743 | + $params['openid.identity'] = $this->identity; | |
744 | + $params['openid.claimed_id'] = $this->claimed_id; | |
745 | + } | |
746 | + | |
747 | + return $this->build_url(parse_url($this->server) | |
748 | + , array('query' => http_build_query($params, '', '&'))); | |
749 | + } | |
750 | + | |
751 | + /** | |
752 | + * Returns authentication url. Usually, you want to redirect your user to it. | |
753 | + * @return String The authentication url. | |
754 | + * @param String $select_identifier Whether to request OP to select identity for an user in OpenID 2. Does not affect OpenID 1. | |
755 | + * @throws ErrorException | |
756 | + */ | |
757 | + function authUrl($immediate = false) | |
758 | + { | |
759 | + if ($this->setup_url && !$immediate) return $this->setup_url; | |
760 | + if (!$this->server) $this->discover($this->identity); | |
761 | + | |
762 | + if ($this->version == 2) { | |
763 | + return $this->authUrl_v2($immediate); | |
764 | + } | |
765 | + return $this->authUrl_v1($immediate); | |
766 | + } | |
767 | + | |
768 | + /** | |
769 | + * Performs OpenID verification with the OP. | |
770 | + * @return Bool Whether the verification was successful. | |
771 | + * @throws ErrorException | |
772 | + */ | |
773 | + function validate() | |
774 | + { | |
775 | + # If the request was using immediate mode, a failure may be reported | |
776 | + # by presenting user_setup_url (for 1.1) or reporting | |
777 | + # mode 'setup_needed' (for 2.0). Also catching all modes other than | |
778 | + # id_res, in order to avoid throwing errors. | |
779 | + if(isset($this->data['openid_user_setup_url'])) { | |
780 | + $this->setup_url = $this->data['openid_user_setup_url']; | |
781 | + return false; | |
782 | + } | |
783 | + if($this->mode != 'id_res') { | |
784 | + return false; | |
785 | + } | |
786 | + | |
787 | + $this->claimed_id = isset($this->data['openid_claimed_id'])?$this->data['openid_claimed_id']:$this->data['openid_identity']; | |
788 | + $params = array( | |
789 | + 'openid.assoc_handle' => $this->data['openid_assoc_handle'], | |
790 | + 'openid.signed' => $this->data['openid_signed'], | |
791 | + 'openid.sig' => $this->data['openid_sig'], | |
792 | + ); | |
793 | + | |
794 | + if (isset($this->data['openid_ns'])) { | |
795 | + # We're dealing with an OpenID 2.0 server, so let's set an ns | |
796 | + # Even though we should know location of the endpoint, | |
797 | + # we still need to verify it by discovery, so $server is not set here | |
798 | + $params['openid.ns'] = 'http://specs.openid.net/auth/2.0'; | |
799 | + } elseif (isset($this->data['openid_claimed_id']) | |
800 | + && $this->data['openid_claimed_id'] != $this->data['openid_identity'] | |
801 | + ) { | |
802 | + # If it's an OpenID 1 provider, and we've got claimed_id, | |
803 | + # we have to append it to the returnUrl, like authUrl_v1 does. | |
804 | + $this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?') | |
805 | + . 'openid.claimed_id=' . $this->claimed_id; | |
806 | + } | |
807 | + | |
808 | + if ($this->data['openid_return_to'] != $this->returnUrl) { | |
809 | + # The return_to url must match the url of current request. | |
810 | + # I'm assuing that noone will set the returnUrl to something that doesn't make sense. | |
811 | + return false; | |
812 | + } | |
813 | + | |
814 | + $server = $this->discover($this->claimed_id); | |
815 | + | |
816 | + foreach (explode(',', $this->data['openid_signed']) as $item) { | |
817 | + # Checking whether magic_quotes_gpc is turned on, because | |
818 | + # the function may fail if it is. For example, when fetching | |
819 | + # AX namePerson, it might containg an apostrophe, which will be escaped. | |
820 | + # In such case, validation would fail, since we'd send different data than OP | |
821 | + # wants to verify. stripslashes() should solve that problem, but we can't | |
822 | + # use it when magic_quotes is off. | |
823 | + $value = $this->data['openid_' . str_replace('.','_',$item)]; | |
824 | + $params['openid.' . $item] = function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() ? stripslashes($value) : $value; | |
825 | + | |
826 | + } | |
827 | + | |
828 | + $params['openid.mode'] = 'check_authentication'; | |
829 | + | |
830 | + $response = $this->request($server, 'POST', $params); | |
831 | + | |
832 | + return preg_match('/is_valid\s*:\s*true/i', $response); | |
833 | + } | |
834 | + | |
835 | + protected function getAxAttributes() | |
836 | + { | |
837 | + $result = array(); | |
838 | + | |
839 | + if ($alias = $this->getNamespaceAlias('http://openid.net/srv/ax/1.0', 'ax')) { | |
840 | + $prefix = 'openid_' . $alias; | |
841 | + $length = strlen('http://axschema.org/'); | |
842 | + | |
843 | + foreach (explode(',', $this->data['openid_signed']) as $key) { | |
844 | + $keyMatch = $alias . '.type.'; | |
845 | + | |
846 | + if (strncmp($key, $keyMatch, strlen($keyMatch)) !== 0) { | |
847 | + continue; | |
848 | + } | |
849 | + | |
850 | + $key = substr($key, strlen($keyMatch)); | |
851 | + $idv = $prefix . '_value_' . $key; | |
852 | + $idc = $prefix . '_count_' . $key; | |
853 | + $key = substr($this->getItem($prefix . '_type_' . $key), $length); | |
854 | + | |
855 | + if (!empty($key)) { | |
856 | + if (($count = intval($this->getItem($idc))) > 0) { | |
857 | + $value = array(); | |
858 | + | |
859 | + for ($i = 1; $i <= $count; $i++) { | |
860 | + $value[] = $this->getItem($idv . '_' . $i); | |
861 | + } | |
862 | + | |
863 | + $value = ($count == 1) ? reset($value) : $value; | |
864 | + } else { | |
865 | + $value = $this->getItem($idv); | |
866 | + } | |
867 | + | |
868 | + if (!is_null($value)) { | |
869 | + $result[$key] = $value; | |
870 | + } | |
871 | + } | |
872 | + } | |
873 | + } else { | |
874 | + // No alias for the AX schema has been found, | |
875 | + // so there is no AX data in the OP's response. | |
876 | + } | |
877 | + | |
878 | + return $result; | |
879 | + } | |
880 | + | |
881 | + protected function getSregAttributes() | |
882 | + { | |
883 | + $attributes = array(); | |
884 | + $sreg_to_ax = array_flip(self::$ax_to_sreg); | |
885 | + foreach (explode(',', $this->data['openid_signed']) as $key) { | |
886 | + $keyMatch = 'sreg.'; | |
887 | + if (strncmp($key, $keyMatch, strlen($keyMatch)) !== 0) { | |
888 | + continue; | |
889 | + } | |
890 | + $key = substr($key, strlen($keyMatch)); | |
891 | + if (!isset($sreg_to_ax[$key])) { | |
892 | + # The field name isn't part of the SREG spec, so we ignore it. | |
893 | + continue; | |
894 | + } | |
895 | + $attributes[$sreg_to_ax[$key]] = $this->data['openid_sreg_' . $key]; | |
896 | + } | |
897 | + return $attributes; | |
898 | + } | |
899 | + | |
900 | + /** | |
901 | + * Gets AX/SREG attributes provided by OP. should be used only after successful validaton. | |
902 | + * Note that it does not guarantee that any of the required/optional parameters will be present, | |
903 | + * or that there will be no other attributes besides those specified. | |
904 | + * In other words. OP may provide whatever information it wants to. | |
905 | + * * SREG names will be mapped to AX names. | |
906 | + * * @return Array Array of attributes with keys being the AX schema names, e.g. 'contact/email' | |
907 | + * @see http://www.axschema.org/types/ | |
908 | + */ | |
909 | + function getAttributes() | |
910 | + { | |
911 | + if (isset($this->data['openid_ns']) | |
912 | + && $this->data['openid_ns'] == 'http://specs.openid.net/auth/2.0' | |
913 | + ) { # OpenID 2.0 | |
914 | + # We search for both AX and SREG attributes, with AX taking precedence. | |
915 | + return $this->getAxAttributes() + $this->getSregAttributes(); | |
916 | + } | |
917 | + return $this->getSregAttributes(); | |
918 | + } | |
919 | + | |
920 | + /** | |
921 | + * Gets an OAuth request token if the OpenID+OAuth hybrid protocol has been used. | |
922 | + * | |
923 | + * In order to use the OpenID+OAuth hybrid protocol, you need to add at least one | |
924 | + * scope to the $openid->oauth array before you get the call to getAuthUrl(), e.g.: | |
925 | + * $openid->oauth[] = 'https://www.googleapis.com/auth/plus.me'; | |
926 | + * | |
927 | + * Furthermore the registered consumer name must fit the OpenID realm. | |
928 | + * To register an OpenID consumer at Google use: https://www.google.com/accounts/ManageDomains | |
929 | + * | |
930 | + * @return string|bool OAuth request token on success, FALSE if no token was provided. | |
931 | + */ | |
932 | + function getOAuthRequestToken() | |
933 | + { | |
934 | + $alias = $this->getNamespaceAlias('http://specs.openid.net/extensions/oauth/1.0'); | |
935 | + | |
936 | + return !empty($alias) ? $this->data['openid_' . $alias . '_request_token'] : false; | |
937 | + } | |
938 | + | |
939 | + /** | |
940 | + * Gets the alias for the specified namespace, if it's present. | |
941 | + * | |
942 | + * @param string $namespace The namespace for which an alias is needed. | |
943 | + * @param string $hint Common alias of this namespace, used for optimization. | |
944 | + * @return string|null The namespace alias if found, otherwise - NULL. | |
945 | + */ | |
946 | + private function getNamespaceAlias($namespace, $hint = null) | |
947 | + { | |
948 | + $result = null; | |
949 | + | |
950 | + if (empty($hint) || $this->getItem('openid_ns_' . $hint) != $namespace) { | |
951 | + // The common alias is either undefined or points to | |
952 | + // some other extension - search for another alias.. | |
953 | + $prefix = 'openid_ns_'; | |
954 | + $length = strlen($prefix); | |
955 | + | |
956 | + foreach ($this->data as $key => $val) { | |
957 | + if (strncmp($key, $prefix, $length) === 0 && $val === $namespace) { | |
958 | + $result = trim(substr($key, $length)); | |
959 | + break; | |
960 | + } | |
961 | + } | |
962 | + } else { | |
963 | + $result = $hint; | |
964 | + } | |
965 | + | |
966 | + return $result; | |
967 | + } | |
968 | + | |
969 | + /** | |
970 | + * Gets an item from the $data array by the specified id. | |
971 | + * | |
972 | + * @param string $id The id of the desired item. | |
973 | + * @return string|null The item if found, otherwise - NULL. | |
974 | + */ | |
975 | + private function getItem($id) | |
976 | + { | |
977 | + return isset($this->data[$id]) ? $this->data[$id] : null; | |
978 | + } | |
979 | +} | |
0 | 980 | \ No newline at end of file | ... | ... |
common/components/nodge/lightopenid/provider/example-mysql.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * This example shows several things: | |
4 | + * - How a setup interface should look like. | |
5 | + * - How to use a mysql table for authentication | |
6 | + * - How to store associations in mysql table, instead of php sessions. | |
7 | + * - How to store realm authorizations. | |
8 | + * - How to send AX/SREG parameters. | |
9 | + * For the example to work, you need to create the necessary tables: | |
10 | +CREATE TABLE Users ( | |
11 | + id INT NOT NULL auto_increment PRIMARY KEY, | |
12 | + login VARCHAR(32) NOT NULL, | |
13 | + password CHAR(40) NOT NULL, | |
14 | + firstName VARCHAR(32) NOT NULL, | |
15 | + lastName VARCHAR(32) NOT NULL | |
16 | +); | |
17 | + | |
18 | +CREATE TABLE AllowedSites ( | |
19 | + user INT NOT NULL, | |
20 | + realm TEXT NOT NULL, | |
21 | + attributes TEXT NOT NULL, | |
22 | + INDEX(user) | |
23 | +); | |
24 | + | |
25 | +CREATE TABLE Associations ( | |
26 | + id INT NOT NULL PRIMARY KEY, | |
27 | + data TEXT NOT NULL | |
28 | +); | |
29 | + * | |
30 | + * This is only an example. Don't use it in your code as-is. | |
31 | + * It has several security flaws, which you shouldn't copy (like storing plaintext login and password in forms). | |
32 | + * | |
33 | + * This setup could be very easily flooded with many associations, | |
34 | + * since non-private ones aren't automatically deleted. | |
35 | + * You could prevent this by storing a date of association and removing old ones, | |
36 | + * or by setting $this->dh = false; | |
37 | + * However, the latter one would disable stateful mode, unless connecting via HTTPS. | |
38 | + */ | |
39 | +require 'provider.php'; | |
40 | + | |
41 | +mysql_connect(); | |
42 | +mysql_select_db('test'); | |
43 | + | |
44 | +function getUserData($handle=null) | |
45 | +{ | |
46 | + if(isset($_POST['login'],$_POST['password'])) { | |
47 | + $login = mysql_real_escape_string($_POST['login']); | |
48 | + $password = sha1($_POST['password']); | |
49 | + $q = mysql_query("SELECT * FROM Users WHERE login = '$login' AND password = '$password'"); | |
50 | + if($data = mysql_fetch_assoc($q)) { | |
51 | + return $data; | |
52 | + } | |
53 | + if($handle) { | |
54 | + echo 'Wrong login/password.'; | |
55 | + } | |
56 | + } | |
57 | + if($handle) { | |
58 | + ?> | |
59 | + <form action="" method="post"> | |
60 | + <input type="hidden" name="openid.assoc_handle" value="<?php echo $handle?>"> | |
61 | + Login: <input type="text" name="login"><br> | |
62 | + Password: <input type="password" name="password"><br> | |
63 | + <button>Submit</button> | |
64 | + </form> | |
65 | + <?php | |
66 | + die(); | |
67 | + } | |
68 | +} | |
69 | + | |
70 | +class MysqlProvider extends LightOpenIDProvider | |
71 | +{ | |
72 | + private $attrMap = array( | |
73 | + 'namePerson/first' => 'First name', | |
74 | + 'namePerson/last' => 'Last name', | |
75 | + 'namePerson/friendly' => 'Nickname (login)' | |
76 | + ); | |
77 | + | |
78 | + private $attrFieldMap = array( | |
79 | + 'namePerson/first' => 'firstName', | |
80 | + 'namePerson/last' => 'lastName', | |
81 | + 'namePerson/friendly' => 'login' | |
82 | + ); | |
83 | + | |
84 | + function setup($identity, $realm, $assoc_handle, $attributes) | |
85 | + { | |
86 | + $data = getUserData($assoc_handle); | |
87 | + echo '<form action="" method="post">' | |
88 | + . '<input type="hidden" name="openid.assoc_handle" value="' . $assoc_handle . '">' | |
89 | + . '<input type="hidden" name="login" value="' . $_POST['login'] .'">' | |
90 | + . '<input type="hidden" name="password" value="' . $_POST['password'] .'">' | |
91 | + . "<b>$realm</b> wishes to authenticate you."; | |
92 | + if($attributes['required'] || $attributes['optional']) { | |
93 | + echo " It also requests following information (required fields marked with *):" | |
94 | + . '<ul>'; | |
95 | + | |
96 | + foreach($attributes['required'] as $attr) { | |
97 | + if(isset($this->attrMap[$attr])) { | |
98 | + echo '<li>' | |
99 | + . '<input type="checkbox" name="attributes[' . $attr . ']"> ' | |
100 | + . $this->attrMap[$attr] . '(*)</li>'; | |
101 | + } | |
102 | + } | |
103 | + | |
104 | + foreach($attributes['optional'] as $attr) { | |
105 | + if(isset($this->attrMap[$attr])) { | |
106 | + echo '<li>' | |
107 | + . '<input type="checkbox" name="attributes[' . $attr . ']"> ' | |
108 | + . $this->attrMap[$attr] . '</li>'; | |
109 | + } | |
110 | + } | |
111 | + echo '</ul>'; | |
112 | + } | |
113 | + echo '<br>' | |
114 | + . '<button name="once">Allow once</button> ' | |
115 | + . '<button name="always">Always allow</button> ' | |
116 | + . '<button name="cancel">cancel</button> ' | |
117 | + . '</form>'; | |
118 | + } | |
119 | + | |
120 | + function checkid($realm, &$attributes) | |
121 | + { | |
122 | + if(isset($_POST['cancel'])) { | |
123 | + $this->cancel(); | |
124 | + } | |
125 | + | |
126 | + $data = getUserData(); | |
127 | + if(!$data) { | |
128 | + return false; | |
129 | + } | |
130 | + $realm = mysql_real_escape_string($realm); | |
131 | + $q = mysql_query("SELECT attributes FROM AllowedSites WHERE user = '{$data['id']}' AND realm = '$realm'"); | |
132 | + | |
133 | + $attrs = array(); | |
134 | + if($attrs = mysql_fetch_row($q)) { | |
135 | + $attrs = explode(',', $attributes[0]); | |
136 | + } elseif(isset($_POST['attributes'])) { | |
137 | + $attrs = array_keys($_POST['attributes']); | |
138 | + } elseif(!isset($_POST['once']) && !isset($_POST['always'])) { | |
139 | + return false; | |
140 | + } | |
141 | + | |
142 | + $attributes = array(); | |
143 | + foreach($attrs as $attr) { | |
144 | + if(isset($this->attrFieldMap[$attr])) { | |
145 | + $attributes[$attr] = $data[$this->attrFieldMap[$attr]]; | |
146 | + } | |
147 | + } | |
148 | + | |
149 | + if(isset($_POST['always'])) { | |
150 | + $attrs = mysql_real_escape_string(implode(',', array_keys($attributes))); | |
151 | + mysql_query("REPLACE INTO AllowedSites VALUES('{$data['id']}', '$realm', '$attrs')"); | |
152 | + } | |
153 | + | |
154 | + return $this->serverLocation . '?' . $data['login']; | |
155 | + } | |
156 | + | |
157 | + function assoc_handle() | |
158 | + { | |
159 | + # We generate an integer assoc handle, because it's just faster to look up an integer later. | |
160 | + $q = mysql_query("SELECT MAX(id) FROM Associations"); | |
161 | + $result = mysql_fetch_row($q); | |
162 | + return $q[0]+1; | |
163 | + } | |
164 | + | |
165 | + function setAssoc($handle, $data) | |
166 | + { | |
167 | + $data = mysql_real_escape_string(serialize($data)); | |
168 | + mysql_query("REPLACE INTO Associations VALUES('$handle', '$data')"); | |
169 | + } | |
170 | + | |
171 | + function getAssoc($handle) | |
172 | + { | |
173 | + if(!is_numeric($handle)) { | |
174 | + return false; | |
175 | + } | |
176 | + $q = mysql_query("SELECT data FROM Associations WHERE id = '$handle'"); | |
177 | + $data = mysql_fetch_row($q); | |
178 | + if(!$data) { | |
179 | + return false; | |
180 | + } | |
181 | + return unserialize($data[0]); | |
182 | + } | |
183 | + | |
184 | + function delAssoc($handle) | |
185 | + { | |
186 | + if(!is_numeric($handle)) { | |
187 | + return false; | |
188 | + } | |
189 | + mysql_query("DELETE FROM Associations WHERE id = '$handle'"); | |
190 | + } | |
191 | + | |
192 | +} | |
193 | +$op = new MysqlProvider; | |
194 | +$op->server(); | ... | ... |
common/components/nodge/lightopenid/provider/example.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * This example shows how to create a basic provider usin HTTP Authentication. | |
4 | + * This is only an example. You shouldn't use it as-is in your code. | |
5 | + */ | |
6 | +require 'provider.php'; | |
7 | + | |
8 | +class BasicProvider extends LightOpenIDProvider | |
9 | +{ | |
10 | + public $select_id = true; | |
11 | + public $login = ''; | |
12 | + public $password = ''; | |
13 | + | |
14 | + function __construct() | |
15 | + { | |
16 | + parent::__construct(); | |
17 | + | |
18 | + # If we use select_id, we must disable it for identity pages, | |
19 | + # so that an RP can discover it and get proper data (i.e. without select_id) | |
20 | + if(isset($_GET['id'])) { | |
21 | + $this->select_id = false; | |
22 | + } | |
23 | + } | |
24 | + | |
25 | + function setup($identity, $realm, $assoc_handle, $attributes) | |
26 | + { | |
27 | + header('WWW-Authenticate: Basic realm="' . $this->data['openid_realm'] . '"'); | |
28 | + header('HTTP/1.0 401 Unauthorized'); | |
29 | + } | |
30 | + | |
31 | + function checkid($realm, &$attributes) | |
32 | + { | |
33 | + if(!isset($_SERVER['PHP_AUTH_USER'])) { | |
34 | + return false; | |
35 | + } | |
36 | + | |
37 | + if ($_SERVER['PHP_AUTH_USER'] == $this->login | |
38 | + && $_SERVER['PHP_AUTH_PW'] == $this->password | |
39 | + ) { | |
40 | + # Returning identity | |
41 | + # It can be any url that leads here, or to any other place that hosts | |
42 | + # an XRDS document pointing here. | |
43 | + return $this->serverLocation . '?id=' . $this->login; | |
44 | + } | |
45 | + | |
46 | + return false; | |
47 | + } | |
48 | + | |
49 | +} | |
50 | +$op = new BasicProvider; | |
51 | +$op->login = 'test'; | |
52 | +$op->password = 'test'; | |
53 | +$op->server(); | ... | ... |
common/components/nodge/lightopenid/provider/provider.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * Using this class, you can easily set up an OpenID Provider. | |
4 | + * It's independent of LightOpenID class. | |
5 | + * It requires either GMP or BCMath for session encryption, | |
6 | + * but will work without them (although either via SSL, or in stateless mode only). | |
7 | + * Also, it requires PHP >= 5.1.2 | |
8 | + * | |
9 | + * This is an alpha version, using it in production code is not recommended, | |
10 | + * until you are *sure* that it works and is secure. | |
11 | + * | |
12 | + * Please send me messages about your testing results | |
13 | + * (even if successful, so I know that it has been tested). | |
14 | + * Also, if you think there's a way to make it easier to use, tell me -- it's an alpha for a reason. | |
15 | + * Same thing applies to bugs in code, suggestions, | |
16 | + * and everything else you'd like to say about the library. | |
17 | + * | |
18 | + * There's no usage documentation here, see the examples. | |
19 | + * | |
20 | + * @author Mewp | |
21 | + * @copyright Copyright (c) 2010, Mewp | |
22 | + * @license http://www.opensource.org/licenses/mit-license.php MIT | |
23 | + */ | |
24 | +ini_set('error_log','log'); | |
25 | +abstract class LightOpenIDProvider | |
26 | +{ | |
27 | + # URL-s to XRDS and server location. | |
28 | + public $xrdsLocation, $serverLocation; | |
29 | + | |
30 | + # Should we operate in server, or signon mode? | |
31 | + public $select_id = false; | |
32 | + | |
33 | + # Lifetime of an association. | |
34 | + protected $assoc_lifetime = 600; | |
35 | + | |
36 | + # Variables below are either set automatically, or are constant. | |
37 | + # ----- | |
38 | + # Can we support DH? | |
39 | + protected $dh = true; | |
40 | + protected $ns = 'http://specs.openid.net/auth/2.0'; | |
41 | + protected $data, $assoc; | |
42 | + | |
43 | + # Default DH parameters as defined in the specification. | |
44 | + protected $default_modulus; | |
45 | + protected $default_gen = 'Ag=='; | |
46 | + | |
47 | + # AX <-> SREG transform | |
48 | + protected $ax_to_sreg = array( | |
49 | + 'namePerson/friendly' => 'nickname', | |
50 | + 'contact/email' => 'email', | |
51 | + 'namePerson' => 'fullname', | |
52 | + 'birthDate' => 'dob', | |
53 | + 'person/gender' => 'gender', | |
54 | + 'contact/postalCode/home' => 'postcode', | |
55 | + 'contact/country/home' => 'country', | |
56 | + 'pref/language' => 'language', | |
57 | + 'pref/timezone' => 'timezone', | |
58 | + ); | |
59 | + | |
60 | + # Math | |
61 | + private $add, $mul, $pow, $mod, $div, $powmod; | |
62 | + # ----- | |
63 | + | |
64 | + # ------------------------------------------------------------------------ # | |
65 | + # Functions you probably want to implement when extending the class. | |
66 | + | |
67 | + /** | |
68 | + * Checks whether an user is authenticated. | |
69 | + * The function should determine what fields it wants to send to the RP, | |
70 | + * and put them in the $attributes array. | |
71 | + * @param Array $attributes | |
72 | + * @param String $realm Realm used for authentication. | |
73 | + * @return String OP-local identifier of an authenticated user, or an empty value. | |
74 | + */ | |
75 | + abstract function checkid($realm, &$attributes); | |
76 | + | |
77 | + /** | |
78 | + * Displays an user interface for inputting user's login and password. | |
79 | + * Attributes are always AX field namespaces, with stripped host part. | |
80 | + * For example, the $attributes array may be: | |
81 | + * array( 'required' => array('namePerson/friendly', 'contact/email'), | |
82 | + * 'optional' => array('pref/timezone', 'pref/language') | |
83 | + * @param String $identity Discovered identity string. May be used to extract login, unless using $this->select_id | |
84 | + * @param String $realm Realm used for authentication. | |
85 | + * @param String Association handle. must be sent as openid.assoc_handle in $_GET or $_POST in subsequent requests. | |
86 | + * @param Array User attributes requested by the RP. | |
87 | + */ | |
88 | + abstract function setup($identity, $realm, $assoc_handle, $attributes); | |
89 | + | |
90 | + /** | |
91 | + * Stores an association. | |
92 | + * If you want to use php sessions in your provider code, you have to replace it. | |
93 | + * @param String $handle Association handle -- should be used as a key. | |
94 | + * @param Array $assoc Association data. | |
95 | + */ | |
96 | + protected function setAssoc($handle, $assoc) | |
97 | + { | |
98 | + $oldSession = session_id(); | |
99 | + session_commit(); | |
100 | + session_id($assoc['handle']); | |
101 | + session_start(); | |
102 | + $_SESSION['assoc'] = $assoc; | |
103 | + session_commit(); | |
104 | + if($oldSession) { | |
105 | + session_id($oldSession); | |
106 | + session_start(); | |
107 | + } | |
108 | + } | |
109 | + | |
110 | + /** | |
111 | + * Retreives association data. | |
112 | + * If you want to use php sessions in your provider code, you have to replace it. | |
113 | + * @param String $handle Association handle. | |
114 | + * @return Array Association data. | |
115 | + */ | |
116 | + protected function getAssoc($handle) | |
117 | + { | |
118 | + $oldSession = session_id(); | |
119 | + session_commit(); | |
120 | + session_id($handle); | |
121 | + session_start(); | |
122 | + $assoc = null; | |
123 | + if(!empty($_SESSION['assoc'])) { | |
124 | + $assoc = $_SESSION['assoc']; | |
125 | + } | |
126 | + session_commit(); | |
127 | + if($oldSession) { | |
128 | + session_id($oldSession); | |
129 | + session_start(); | |
130 | + } | |
131 | + return $assoc; | |
132 | + } | |
133 | + | |
134 | + /** | |
135 | + * Deletes an association. | |
136 | + * If you want to use php sessions in your provider code, you have to replace it. | |
137 | + * @param String $handle Association handle. | |
138 | + */ | |
139 | + protected function delAssoc($handle) | |
140 | + { | |
141 | + $oldSession = session_id(); | |
142 | + session_commit(); | |
143 | + session_id($handle); | |
144 | + session_start(); | |
145 | + session_destroy(); | |
146 | + if($oldSession) { | |
147 | + session_id($oldSession); | |
148 | + session_start(); | |
149 | + } | |
150 | + } | |
151 | + | |
152 | + # ------------------------------------------------------------------------ # | |
153 | + # Functions that you might want to implement. | |
154 | + | |
155 | + /** | |
156 | + * Redirects the user to an url. | |
157 | + * @param String $location The url that the user will be redirected to. | |
158 | + */ | |
159 | + protected function redirect($location) | |
160 | + { | |
161 | + header('Location: ' . $location); | |
162 | + die(); | |
163 | + } | |
164 | + | |
165 | + /** | |
166 | + * Generates a new association handle. | |
167 | + * @return string | |
168 | + */ | |
169 | + protected function assoc_handle() | |
170 | + { | |
171 | + return sha1(microtime()); | |
172 | + } | |
173 | + | |
174 | + /** | |
175 | + * Generates a random shared secret. | |
176 | + * @return string | |
177 | + */ | |
178 | + protected function shared_secret($hash) | |
179 | + { | |
180 | + $length = 20; | |
181 | + if($hash == 'sha256') { | |
182 | + $length = 256; | |
183 | + } | |
184 | + | |
185 | + $secret = ''; | |
186 | + for($i = 0; $i < $length; $i++) { | |
187 | + $secret .= mt_rand(0,255); | |
188 | + } | |
189 | + | |
190 | + return $secret; | |
191 | + } | |
192 | + | |
193 | + /** | |
194 | + * Generates a private key. | |
195 | + * @param int $length Length of the key. | |
196 | + */ | |
197 | + protected function keygen($length) | |
198 | + { | |
199 | + $key = ''; | |
200 | + for($i = 1; $i < $length; $i++) { | |
201 | + $key .= mt_rand(0,9); | |
202 | + } | |
203 | + $key .= mt_rand(1,9); | |
204 | + | |
205 | + return $key; | |
206 | + } | |
207 | + | |
208 | + # ------------------------------------------------------------------------ # | |
209 | + # Functions that you probably shouldn't touch. | |
210 | + | |
211 | + function __construct() | |
212 | + { | |
213 | + $this->default_modulus = | |
214 | + 'ANz5OguIOXLsDhmYmsWizjEOHTdxfo2Vcbt2I3MYZuYe91ouJ4mLBX+YkcLiemOcPy' | |
215 | + . 'm2CBRYHNOyyjmG0mg3BVd9RcLn5S3IHHoXGHblzqdLFEi/368Ygo79JRnxTkXjgmY0' | |
216 | + . 'rxlJ5bU1zIKaSDuKdiI+XUkKJX8Fvf8W8vsixYOr'; | |
217 | + | |
218 | + $location = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' | |
219 | + . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; | |
220 | + $location = preg_replace('/\?.*/','',$location); | |
221 | + $this->serverLocation = $location; | |
222 | + $location .= (strpos($location, '?') ? '&' : '?') . 'xrds'; | |
223 | + $this->xrdsLocation = $location; | |
224 | + | |
225 | + $this->data = $_GET + $_POST; | |
226 | + | |
227 | + # We choose GMP if avaiable, and bcmath otherwise | |
228 | + if(function_exists('gmp_add')) { | |
229 | + $this->add = 'gmp_add'; | |
230 | + $this->mul = 'gmp_mul'; | |
231 | + $this->pow = 'gmp_pow'; | |
232 | + $this->mod = 'gmp_mod'; | |
233 | + $this->div = 'gmp_div'; | |
234 | + $this->powmod = 'gmp_powm'; | |
235 | + } elseif(function_exists('bcadd')) { | |
236 | + $this->add = 'bcadd'; | |
237 | + $this->mul = 'bcmul'; | |
238 | + $this->pow = 'bcpow'; | |
239 | + $this->mod = 'bcmod'; | |
240 | + $this->div = 'bcdiv'; | |
241 | + $this->powmod = 'bcpowmod'; | |
242 | + } else { | |
243 | + # If neither are avaiable, we can't use DH | |
244 | + $this->dh = false; | |
245 | + } | |
246 | + | |
247 | + # However, we do require the hash functions. | |
248 | + # They should be built-in anyway. | |
249 | + if(!function_exists('hash_algos')) { | |
250 | + $this->dh = false; | |
251 | + } | |
252 | + } | |
253 | + | |
254 | + /** | |
255 | + * Displays an XRDS document, or redirects to it. | |
256 | + * By default, it detects whether it should display or redirect automatically. | |
257 | + * @param bool|null $force When true, always display the document, when false always redirect. | |
258 | + */ | |
259 | + function xrds($force=null) | |
260 | + { | |
261 | + if($force) { | |
262 | + echo $this->xrdsContent(); | |
263 | + die(); | |
264 | + } elseif($force === false) { | |
265 | + header('X-XRDS-Location: '. $this->xrdsLocation); | |
266 | + return; | |
267 | + } | |
268 | + | |
269 | + if (isset($_GET['xrds']) | |
270 | + || (isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'application/xrds+xml') !== false) | |
271 | + ) { | |
272 | + header('Content-Type: application/xrds+xml'); | |
273 | + echo $this->xrdsContent(); | |
274 | + die(); | |
275 | + } | |
276 | + | |
277 | + header('X-XRDS-Location: ' . $this->xrdsLocation); | |
278 | + } | |
279 | + | |
280 | + /** | |
281 | + * Returns the content of the XRDS document | |
282 | + * @return String The XRDS document. | |
283 | + */ | |
284 | + protected function xrdsContent() | |
285 | + { | |
286 | + $lines = array( | |
287 | + '<?xml version="1.0" encoding="UTF-8"?>', | |
288 | + '<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">', | |
289 | + '<XRD>', | |
290 | + ' <Service>', | |
291 | + ' <Type>' . $this->ns . '/' . ($this->select_id ? 'server' : 'signon') .'</Type>', | |
292 | + ' <URI>' . $this->serverLocation . '</URI>', | |
293 | + ' </Service>', | |
294 | + '</XRD>', | |
295 | + '</xrds:XRDS>' | |
296 | + ); | |
297 | + return implode("\n", $lines); | |
298 | + } | |
299 | + | |
300 | + /** | |
301 | + * Does everything that a provider has to -- in one function. | |
302 | + */ | |
303 | + function server() | |
304 | + { | |
305 | + if(isset($this->data['openid_assoc_handle'])) { | |
306 | + $this->assoc = $this->getAssoc($this->data['openid_assoc_handle']); | |
307 | + if(isset($this->assoc['data'])) { | |
308 | + # We have additional data stored for setup. | |
309 | + $this->data += $this->assoc['data']; | |
310 | + unset($this->assoc['data']); | |
311 | + } | |
312 | + } | |
313 | + | |
314 | + if (isset($this->data['openid_ns']) | |
315 | + && $this->data['openid_ns'] == $this->ns | |
316 | + ) { | |
317 | + if(!isset($this->data['openid_mode'])) $this->errorResponse(); | |
318 | + | |
319 | + switch($this->data['openid_mode']) | |
320 | + { | |
321 | + case 'checkid_immediate': | |
322 | + case 'checkid_setup': | |
323 | + $this->checkRealm(); | |
324 | + # We support AX xor SREG. | |
325 | + $attributes = $this->ax(); | |
326 | + if(!$attributes) { | |
327 | + $attributes = $this->sreg(); | |
328 | + } | |
329 | + | |
330 | + # Even if some user is authenticated, we need to know if it's | |
331 | + # the same one that want's to authenticate. | |
332 | + # Of course, if we use select_id, we accept any user. | |
333 | + if (($identity = $this->checkid($this->data['openid_realm'], $attrValues)) | |
334 | + && ($this->select_id || $identity == $this->data['openid_identity']) | |
335 | + ) { | |
336 | + $this->positiveResponse($identity, $attrValues); | |
337 | + } elseif($this->data['openid_mode'] == 'checkid_immediate') { | |
338 | + $this->redirect($this->response(array('openid.mode' => 'setup_needed'))); | |
339 | + } else { | |
340 | + if(!$this->assoc) { | |
341 | + $this->generateAssociation(); | |
342 | + $this->assoc['private'] = true; | |
343 | + } | |
344 | + $this->assoc['data'] = $this->data; | |
345 | + $this->setAssoc($this->assoc['handle'], $this->assoc); | |
346 | + $this->setup($this->data['openid_identity'], | |
347 | + $this->data['openid_realm'], | |
348 | + $this->assoc['handle'], | |
349 | + $attributes); | |
350 | + } | |
351 | + break; | |
352 | + case 'associate': | |
353 | + $this->associate(); | |
354 | + break; | |
355 | + case 'check_authentication': | |
356 | + $this->checkRealm(); | |
357 | + if($this->verify()) { | |
358 | + echo "ns:$this->ns\nis_valid:true"; | |
359 | + if(strpos($this->data['openid_signed'],'invalidate_handle') !== false) { | |
360 | + echo "\ninvalidate_handle:" . $this->data['openid_invalidate_handle']; | |
361 | + } | |
362 | + } else { | |
363 | + echo "ns:$this->ns\nis_valid:false"; | |
364 | + } | |
365 | + die(); | |
366 | + break; | |
367 | + default: | |
368 | + $this->errorResponse(); | |
369 | + } | |
370 | + } else { | |
371 | + $this->xrds(); | |
372 | + } | |
373 | + } | |
374 | + | |
375 | + protected function checkRealm() | |
376 | + { | |
377 | + if (!isset($this->data['openid_return_to'], $this->data['openid_realm'])) { | |
378 | + $this->errorResponse(); | |
379 | + } | |
380 | + | |
381 | + $realm = str_replace('\*', '[^/]', preg_quote($this->data['openid_realm'])); | |
382 | + if(!preg_match("#^$realm#", $this->data['openid_return_to'])) { | |
383 | + $this->errorResponse(); | |
384 | + } | |
385 | + } | |
386 | + | |
387 | + protected function ax() | |
388 | + { | |
389 | + # Namespace prefix that the fields must have. | |
390 | + $ns = 'http://axschema.org/'; | |
391 | + | |
392 | + # First, we must find out what alias is used for AX. | |
393 | + # Let's check the most likely one | |
394 | + $alias = null; | |
395 | + if (isset($this->data['openid_ns_ax']) | |
396 | + && $this->data['openid_ns_ax'] == 'http://openid.net/srv/ax/1.0' | |
397 | + ) { | |
398 | + $alias = 'ax'; | |
399 | + } else { | |
400 | + foreach($this->data as $name => $value) { | |
401 | + if ($value == 'http://openid.net/srv/ax/1.0' | |
402 | + && preg_match('/openid_ns_(.+)/', $name, $m) | |
403 | + ) { | |
404 | + $alias = $m[1]; | |
405 | + break; | |
406 | + } | |
407 | + } | |
408 | + } | |
409 | + | |
410 | + if(!$alias) { | |
411 | + return null; | |
412 | + } | |
413 | + | |
414 | + $fields = array(); | |
415 | + # Now, we must search again, this time for field aliases | |
416 | + foreach($this->data as $name => $value) { | |
417 | + if (strpos($name, 'openid_' . $alias . '_type') === false | |
418 | + || strpos($value, $ns) === false) { | |
419 | + continue; | |
420 | + } | |
421 | + | |
422 | + $name = substr($name, strlen('openid_' . $alias . '_type_')); | |
423 | + $value = substr($value, strlen($ns)); | |
424 | + | |
425 | + $fields[$name] = $value; | |
426 | + } | |
427 | + | |
428 | + # Then, we find out what fields are required and optional | |
429 | + $required = array(); | |
430 | + $if_available = array(); | |
431 | + foreach(array('required','if_available') as $type) { | |
432 | + if(empty($this->data["openid_{$alias}_{$type}"])) { | |
433 | + continue; | |
434 | + } | |
435 | + $attributes = explode(',', $this->data["openid_{$alias}_{$type}"]); | |
436 | + foreach($attributes as $attr) { | |
437 | + if(empty($fields[$attr])) { | |
438 | + # There is an undefined field here, so we ignore it. | |
439 | + continue; | |
440 | + } | |
441 | + | |
442 | + ${$type}[] = $fields[$attr]; | |
443 | + } | |
444 | + } | |
445 | + | |
446 | + $this->data['ax'] = true; | |
447 | + return array('required' => $required, 'optional' => $if_available); | |
448 | + } | |
449 | + | |
450 | + protected function sreg() | |
451 | + { | |
452 | + $sreg_to_ax = array_flip($this->ax_to_sreg); | |
453 | + | |
454 | + $attributes = array('required' => array(), 'optional' => array()); | |
455 | + | |
456 | + if (empty($this->data['openid_sreg_required']) | |
457 | + && empty($this->data['openid_sreg_optional']) | |
458 | + ) { | |
459 | + return $attributes; | |
460 | + } | |
461 | + | |
462 | + foreach(array('required', 'optional') as $type) { | |
463 | + foreach(explode(',',$this->data['openid_sreg_' . $type]) as $attr) { | |
464 | + if(empty($sreg_to_ax[$attr])) { | |
465 | + # Undefined attribute in SREG request. | |
466 | + # Shouldn't happen, but we check anyway. | |
467 | + continue; | |
468 | + } | |
469 | + | |
470 | + $attributes[$type][] = $sreg_to_ax[$attr]; | |
471 | + } | |
472 | + } | |
473 | + | |
474 | + return $attributes; | |
475 | + } | |
476 | + | |
477 | + /** | |
478 | + * Aids an RP in assertion verification. | |
479 | + * @return bool Information whether the verification suceeded. | |
480 | + */ | |
481 | + protected function verify() | |
482 | + { | |
483 | + # Firstly, we need to make sure that there's an association. | |
484 | + # Otherwise the verification will fail, | |
485 | + # because we've signed assoc_handle in the assertion | |
486 | + if(empty($this->assoc)) { | |
487 | + return false; | |
488 | + } | |
489 | + | |
490 | + # Next, we check that it's a private association, | |
491 | + # i.e. one made without RP input. | |
492 | + # Otherwise, the RP shouldn't ask us to verify. | |
493 | + if(empty($this->assoc['private'])) { | |
494 | + return false; | |
495 | + } | |
496 | + | |
497 | + # Now we have to check if the nonce is correct, to prevent replay attacks. | |
498 | + if($this->data['openid_response_nonce'] != $this->assoc['nonce']) { | |
499 | + return false; | |
500 | + } | |
501 | + | |
502 | + # Getting the signed fields for signature. | |
503 | + $sig = array(); | |
504 | + $signed = explode(',', $this->data['openid_signed']); | |
505 | + foreach($signed as $field) { | |
506 | + $name = strtr($field, '.', '_'); | |
507 | + if(!isset($this->data['openid_' . $name])) { | |
508 | + return false; | |
509 | + } | |
510 | + | |
511 | + $sig[$field] = $this->data['openid_' . $name]; | |
512 | + } | |
513 | + | |
514 | + # Computing the signature and checking if it matches. | |
515 | + $sig = $this->keyValueForm($sig); | |
516 | + if ($this->data['openid_sig'] != | |
517 | + base64_encode(hash_hmac($this->assoc['hash'], $sig, $this->assoc['mac'], true)) | |
518 | + ) { | |
519 | + return false; | |
520 | + } | |
521 | + | |
522 | + # Clearing the nonce, so that it won't be used again. | |
523 | + $this->assoc['nonce'] = null; | |
524 | + | |
525 | + if(empty($this->assoc['private'])) { | |
526 | + # Commiting changes to the association. | |
527 | + $this->setAssoc($this->assoc['handle'], $this->assoc); | |
528 | + } else { | |
529 | + # Private associations shouldn't be used again, se we can as well delete them. | |
530 | + $this->delAssoc($this->assoc['handle']); | |
531 | + } | |
532 | + | |
533 | + # Nothing has failed, so the verification was a success. | |
534 | + return true; | |
535 | + } | |
536 | + | |
537 | + /** | |
538 | + * Performs association with an RP. | |
539 | + */ | |
540 | + protected function associate() | |
541 | + { | |
542 | + # Rejecting no-encryption without TLS. | |
543 | + if(empty($_SERVER['HTTPS']) && $this->data['openid_session_type'] == 'no-encryption') { | |
544 | + $this->directErrorResponse(); | |
545 | + } | |
546 | + | |
547 | + # Checking whether we support DH at all. | |
548 | + if (!$this->dh && substr($this->data['openid_session_type'], 0, 2) == 'DH') { | |
549 | + $this->redirect($this->response(array( | |
550 | + 'openid.error' => 'DH not supported', | |
551 | + 'openid.error_code' => 'unsupported-type', | |
552 | + 'openid.session_type' => 'no-encryption' | |
553 | + ))); | |
554 | + } | |
555 | + | |
556 | + # Creating the association | |
557 | + $this->assoc = array(); | |
558 | + $this->assoc['hash'] = $this->data['openid_assoc_type'] == 'HMAC-SHA256' ? 'sha256' : 'sha1'; | |
559 | + $this->assoc['handle'] = $this->assoc_handle(); | |
560 | + | |
561 | + # Getting the shared secret | |
562 | + if($this->data['openid_session_type'] == 'no-encryption') { | |
563 | + $this->assoc['mac'] = base64_encode($this->shared_secret($this->assoc['hash'])); | |
564 | + } else { | |
565 | + $this->dh(); | |
566 | + } | |
567 | + | |
568 | + # Preparing the direct response... | |
569 | + $response = array( | |
570 | + 'ns' => $this->ns, | |
571 | + 'assoc_handle' => $this->assoc['handle'], | |
572 | + 'assoc_type' => $this->data['openid_assoc_type'], | |
573 | + 'session_type' => $this->data['openid_session_type'], | |
574 | + 'expires_in' => $this->assoc_lifetime | |
575 | + ); | |
576 | + | |
577 | + if(isset($this->assoc['dh_server_public'])) { | |
578 | + $response['dh_server_public'] = $this->assoc['dh_server_public']; | |
579 | + $response['enc_mac_key'] = $this->assoc['mac']; | |
580 | + } else { | |
581 | + $response['mac_key'] = $this->assoc['mac']; | |
582 | + } | |
583 | + | |
584 | + # ...and sending it. | |
585 | + echo $this->keyValueForm($response); | |
586 | + die(); | |
587 | + } | |
588 | + | |
589 | + /** | |
590 | + * Creates a private association. | |
591 | + */ | |
592 | + protected function generateAssociation() | |
593 | + { | |
594 | + $this->assoc = array(); | |
595 | + # We use sha1 by default. | |
596 | + $this->assoc['hash'] = 'sha1'; | |
597 | + $this->assoc['mac'] = $this->shared_secret('sha1'); | |
598 | + $this->assoc['handle'] = $this->assoc_handle(); | |
599 | + } | |
600 | + | |
601 | + /** | |
602 | + * Encrypts the MAC key using DH key exchange. | |
603 | + */ | |
604 | + protected function dh() | |
605 | + { | |
606 | + if(empty($this->data['openid_dh_modulus'])) { | |
607 | + $this->data['openid_dh_modulus'] = $this->default_modulus; | |
608 | + } | |
609 | + | |
610 | + if(empty($this->data['openid_dh_gen'])) { | |
611 | + $this->data['openid_dh_gen'] = $this->default_gen; | |
612 | + } | |
613 | + | |
614 | + if(empty($this->data['openid_dh_consumer_public'])) { | |
615 | + $this->directErrorResponse(); | |
616 | + } | |
617 | + | |
618 | + $modulus = $this->b64dec($this->data['openid_dh_modulus']); | |
619 | + $gen = $this->b64dec($this->data['openid_dh_gen']); | |
620 | + $consumerKey = $this->b64dec($this->data['openid_dh_consumer_public']); | |
621 | + | |
622 | + $privateKey = $this->keygen(strlen($modulus)); | |
623 | + $publicKey = $this->powmod($gen, $privateKey, $modulus); | |
624 | + $ss = $this->powmod($consumerKey, $privateKey, $modulus); | |
625 | + | |
626 | + $mac = $this->x_or(hash($this->assoc['hash'], $ss, true), $this->shared_secret($this->assoc['hash'])); | |
627 | + $this->assoc['dh_server_public'] = $this->decb64($publicKey); | |
628 | + $this->assoc['mac'] = base64_encode($mac); | |
629 | + } | |
630 | + | |
631 | + /** | |
632 | + * XORs two strings. | |
633 | + * @param String $a | |
634 | + * @param String $b | |
635 | + * @return String $a ^ $b | |
636 | + */ | |
637 | + protected function x_or($a, $b) | |
638 | + { | |
639 | + $length = strlen($a); | |
640 | + for($i = 0; $i < $length; $i++) { | |
641 | + $a[$i] = $a[$i] ^ $b[$i]; | |
642 | + } | |
643 | + | |
644 | + return $a; | |
645 | + } | |
646 | + | |
647 | + /** | |
648 | + * Prepares an indirect response url. | |
649 | + * @param array $params Parameters to be sent. | |
650 | + */ | |
651 | + protected function response($params) | |
652 | + { | |
653 | + $params += array('openid.ns' => $this->ns); | |
654 | + return $this->data['openid_return_to'] | |
655 | + . (strpos($this->data['openid_return_to'],'?') ? '&' : '?') | |
656 | + . http_build_query($params, '', '&'); | |
657 | + } | |
658 | + | |
659 | + /** | |
660 | + * Outputs a direct error. | |
661 | + */ | |
662 | + protected function errorResponse() | |
663 | + { | |
664 | + if(!empty($this->data['openid_return_to'])) { | |
665 | + $response = array( | |
666 | + 'openid.mode' => 'error', | |
667 | + 'openid.error' => 'Invalid request' | |
668 | + ); | |
669 | + $this->redirect($this->response($response)); | |
670 | + } else { | |
671 | + header('HTTP/1.1 400 Bad Request'); | |
672 | + $response = array( | |
673 | + 'ns' => $this->ns, | |
674 | + 'error' => 'Invalid request' | |
675 | + ); | |
676 | + echo $this->keyValueForm($response); | |
677 | + } | |
678 | + die(); | |
679 | + } | |
680 | + | |
681 | + /** | |
682 | + * Sends an positive assertion. | |
683 | + * @param String $identity the OP-Local Identifier that is being authenticated. | |
684 | + * @param Array $attributes User attributes to be sent. | |
685 | + */ | |
686 | + protected function positiveResponse($identity, $attributes) | |
687 | + { | |
688 | + # We generate a private association if there is none established. | |
689 | + if(!$this->assoc) { | |
690 | + $this->generateAssociation(); | |
691 | + $this->assoc['private'] = true; | |
692 | + } | |
693 | + | |
694 | + # We set openid.identity (and openid.claimed_id if necessary) to our $identity | |
695 | + if($this->data['openid_identity'] == $this->data['openid_claimed_id'] || $this->select_id) { | |
696 | + $this->data['openid_claimed_id'] = $identity; | |
697 | + } | |
698 | + $this->data['openid_identity'] = $identity; | |
699 | + | |
700 | + # Preparing fields to be signed | |
701 | + $params = array( | |
702 | + 'op_endpoint' => $this->serverLocation, | |
703 | + 'claimed_id' => $this->data['openid_claimed_id'], | |
704 | + 'identity' => $this->data['openid_identity'], | |
705 | + 'return_to' => $this->data['openid_return_to'], | |
706 | + 'realm' => $this->data['openid_realm'], | |
707 | + 'response_nonce' => gmdate("Y-m-d\TH:i:s\Z"), | |
708 | + 'assoc_handle' => $this->assoc['handle'], | |
709 | + ); | |
710 | + | |
711 | + $params += $this->responseAttributes($attributes); | |
712 | + | |
713 | + # Has the RP used an invalid association handle? | |
714 | + if (isset($this->data['openid_assoc_handle']) | |
715 | + && $this->data['openid_assoc_handle'] != $this->assoc['handle'] | |
716 | + ) { | |
717 | + $params['invalidate_handle'] = $this->data['openid_assoc_handle']; | |
718 | + } | |
719 | + | |
720 | + # Signing the $params | |
721 | + $sig = hash_hmac($this->assoc['hash'], $this->keyValueForm($params), $this->assoc['mac'], true); | |
722 | + $req = array( | |
723 | + 'openid.mode' => 'id_res', | |
724 | + 'openid.signed' => implode(',', array_keys($params)), | |
725 | + 'openid.sig' => base64_encode($sig), | |
726 | + ); | |
727 | + | |
728 | + # Saving the nonce and commiting the association. | |
729 | + $this->assoc['nonce'] = $params['response_nonce']; | |
730 | + $this->setAssoc($this->assoc['handle'], $this->assoc); | |
731 | + | |
732 | + # Preparing and sending the response itself | |
733 | + foreach($params as $name => $value) { | |
734 | + $req['openid.' . $name] = $value; | |
735 | + } | |
736 | + | |
737 | + $this->redirect($this->response($req)); | |
738 | + } | |
739 | + | |
740 | + /** | |
741 | + * Prepares an array of attributes to send | |
742 | + */ | |
743 | + protected function responseAttributes($attributes) | |
744 | + { | |
745 | + if(!$attributes) return array(); | |
746 | + | |
747 | + $ns = 'http://axschema.org/'; | |
748 | + | |
749 | + $response = array(); | |
750 | + if(isset($this->data['ax'])) { | |
751 | + $response['ns.ax'] = 'http://openid.net/srv/ax/1.0'; | |
752 | + foreach($attributes as $name => $value) { | |
753 | + $alias = strtr($name, '/', '_'); | |
754 | + $response['ax.type.' . $alias] = $ns . $name; | |
755 | + $response['ax.value.' . $alias] = $value; | |
756 | + } | |
757 | + return $response; | |
758 | + } | |
759 | + | |
760 | + foreach($attributes as $name => $value) { | |
761 | + if(!isset($this->ax_to_sreg[$name])) { | |
762 | + continue; | |
763 | + } | |
764 | + | |
765 | + $response['sreg.' . $this->ax_to_sreg[$name]] = $value; | |
766 | + } | |
767 | + return $response; | |
768 | + } | |
769 | + | |
770 | + /** | |
771 | + * Encodes fields in key-value form. | |
772 | + * @param Array $params Fields to be encoded. | |
773 | + * @return String $params in key-value form. | |
774 | + */ | |
775 | + protected function keyValueForm($params) | |
776 | + { | |
777 | + $str = ''; | |
778 | + foreach($params as $name => $value) { | |
779 | + $str .= "$name:$value\n"; | |
780 | + } | |
781 | + | |
782 | + return $str; | |
783 | + } | |
784 | + | |
785 | + /** | |
786 | + * Responds with an information that the user has canceled authentication. | |
787 | + */ | |
788 | + protected function cancel() | |
789 | + { | |
790 | + $this->redirect($this->response(array('openid.mode' => 'cancel'))); | |
791 | + } | |
792 | + | |
793 | + /** | |
794 | + * Converts base64 encoded number to it's decimal representation. | |
795 | + * @param String $str base64 encoded number. | |
796 | + * @return String Decimal representation of that number. | |
797 | + */ | |
798 | + protected function b64dec($str) | |
799 | + { | |
800 | + $bytes = unpack('C*', base64_decode($str)); | |
801 | + $n = 0; | |
802 | + foreach($bytes as $byte) { | |
803 | + $n = $this->add($this->mul($n, 256), $byte); | |
804 | + } | |
805 | + | |
806 | + return $n; | |
807 | + } | |
808 | + | |
809 | + /** | |
810 | + * Complements b64dec. | |
811 | + */ | |
812 | + protected function decb64($num) | |
813 | + { | |
814 | + $bytes = array(); | |
815 | + while($num) { | |
816 | + array_unshift($bytes, $this->mod($num, 256)); | |
817 | + $num = $this->div($num, 256); | |
818 | + } | |
819 | + | |
820 | + if($bytes && $bytes[0] > 127) { | |
821 | + array_unshift($bytes,0); | |
822 | + } | |
823 | + | |
824 | + array_unshift($bytes, 'C*'); | |
825 | + | |
826 | + return base64_encode(call_user_func_array('pack', $bytes)); | |
827 | + } | |
828 | + | |
829 | + function __call($name, $args) | |
830 | + { | |
831 | + switch($name) { | |
832 | + case 'add': | |
833 | + case 'mul': | |
834 | + case 'pow': | |
835 | + case 'mod': | |
836 | + case 'div': | |
837 | + case 'powmod': | |
838 | + if(function_exists('gmp_strval')) { | |
839 | + return gmp_strval(call_user_func_array($this->$name, $args)); | |
840 | + } | |
841 | + return call_user_func_array($this->$name, $args); | |
842 | + default: | |
843 | + throw new BadMethodCallException(); | |
844 | + } | |
845 | + } | |
846 | +} | ... | ... |
common/config/main-local.php
... | ... | @@ -3,7 +3,7 @@ return [ |
3 | 3 | 'components' => [ |
4 | 4 | 'db' => [ |
5 | 5 | 'class' => 'yii\db\Connection', |
6 | - 'dsn' => 'pgsql:host=localhost;port=5432;dbname=artbox_db', | |
6 | + 'dsn' => 'pgsql:host=localhost;port=5432;dbname=artbox_test', | |
7 | 7 | 'username' => 'postgres', |
8 | 8 | 'password' => '', |
9 | 9 | 'schemaMap' => [ | ... | ... |
common/config/main.php
... | ... | @@ -55,7 +55,7 @@ return [ |
55 | 55 | //подключаем конфигурации API соц сетей для авторизации |
56 | 56 | |
57 | 57 | 'eauth' => [ |
58 | - 'class' => 'nodge\eauth\EAuth', | |
58 | + 'class' => 'common\components\nodge\eauth\src\EAuth', | |
59 | 59 | 'popup' => true, // Use the popup window instead of redirecting. |
60 | 60 | 'cache' => false, // Cache component name or false to disable cache. Defaults to 'cache' on production environments. |
61 | 61 | 'cacheExpire' => 0, // Cache lifetime. Defaults to 0 - means unlimited. |
... | ... | @@ -66,86 +66,86 @@ return [ |
66 | 66 | 'services' => [ // You can change the providers and their classes. |
67 | 67 | 'google' => [ |
68 | 68 | // register your app here: https://code.google.com/apis/console/ |
69 | - 'class' => 'nodge\eauth\services\GoogleOAuth2Service', | |
69 | + 'class' => 'common\components\nodge\eauth\src\services\GoogleOAuth2Service', | |
70 | 70 | 'clientId' => 'artbox-1138', |
71 | 71 | 'clientSecret' => '', |
72 | 72 | 'title' => 'Google', |
73 | 73 | ], |
74 | 74 | 'twitter' => [ |
75 | 75 | // register your app here: https://dev.twitter.com/apps/new |
76 | - 'class' => 'nodge\eauth\services\TwitterOAuth1Service', | |
76 | + 'class' => 'common\components\nodge\eauth\src\services\TwitterOAuth1Service', | |
77 | 77 | 'key' => '8vReLxI63vTs98MBMqhvrszwy', |
78 | 78 | 'secret' => 'jOqNbHIkQw4cVKKJkgrMtaEeCcfbeT1GTik4pF6O9D7AmqcwOG', |
79 | 79 | ], |
80 | 80 | 'yandex' => [ |
81 | 81 | // register your app here: https://oauth.yandex.ru/client/my |
82 | - 'class' => 'nodge\eauth\services\YandexOAuth2Service', | |
82 | + 'class' => 'common\components\nodge\eauth\src\services\YandexOAuth2Service', | |
83 | 83 | 'clientId' => 'ea13195ac0424ff8a190838bec41bb71', |
84 | 84 | 'clientSecret' => '911f2c9afcbf4f5f9319b3134c096c86', |
85 | 85 | 'title' => 'Yandex', |
86 | 86 | ], |
87 | 87 | 'facebook' => [ |
88 | 88 | // register your app here: https://developers.facebook.com/apps/ |
89 | - 'class' => 'nodge\eauth\services\FacebookOAuth2Service', | |
89 | + 'class' => 'common\components\nodge\eauth\src\services\FacebookOAuth2Service', | |
90 | 90 | 'clientId' => '1642047622727997', |
91 | 91 | 'clientSecret' => 'f5b7ba4f062a568678b764fc74cc416e', |
92 | 92 | ], |
93 | 93 | 'yahoo' => [ |
94 | - 'class' => 'nodge\eauth\services\YahooOpenIDService', | |
94 | + 'class' => 'common\components\nodge\eauth\src\services\YahooOpenIDService', | |
95 | 95 | //'realm' => '*.example.org', // your domain, can be with wildcard to authenticate on subdomains. |
96 | 96 | ], |
97 | 97 | 'linkedin' => [ |
98 | 98 | // register your app here: https://www.linkedin.com/secure/developer |
99 | - 'class' => 'nodge\eauth\services\LinkedinOAuth1Service', | |
99 | + 'class' => 'common\components\nodge\eauth\src\services\LinkedinOAuth1Service', | |
100 | 100 | 'key' => '77s41eixn3dyvo', |
101 | 101 | 'secret' => '1xLZQ7RRK6RNjo4U', |
102 | 102 | 'title' => 'LinkedIn (OAuth1)', |
103 | 103 | ], |
104 | 104 | 'linkedin_oauth2' => [ |
105 | 105 | // register your app here: https://www.linkedin.com/secure/developer |
106 | - 'class' => 'nodge\eauth\services\LinkedinOAuth2Service', | |
106 | + 'class' => 'common\components\nodge\eauth\src\services\LinkedinOAuth2Service', | |
107 | 107 | 'clientId' => '77s41eixn3dyvo', |
108 | 108 | 'clientSecret' => '1xLZQ7RRK6RNjo4U', |
109 | 109 | 'title' => 'LinkedIn (OAuth2)', |
110 | 110 | ], |
111 | 111 | 'github' => [ |
112 | 112 | // register your app here: https://github.com/settings/applications |
113 | - 'class' => 'nodge\eauth\services\GitHubOAuth2Service', | |
113 | + 'class' => 'common\components\nodge\eauth\src\services\GitHubOAuth2Service', | |
114 | 114 | 'clientId' => 'd00283b5cfb225cd1600', |
115 | 115 | 'clientSecret' => 'f482361fad7184819d452f421c8b09db60830b42', |
116 | 116 | ], |
117 | 117 | 'live' => [ |
118 | 118 | // register your app here: https://account.live.com/developers/applications/index |
119 | - 'class' => 'nodge\eauth\services\LiveOAuth2Service', | |
119 | + 'class' => 'common\components\nodge\eauth\src\services\LiveOAuth2Service', | |
120 | 120 | 'clientId' => '00000000481796AE', |
121 | 121 | 'clientSecret' => 'rt9GiJrlKz3sE6CvdOeuwWyYbl1tQT03', |
122 | 122 | ], |
123 | 123 | 'steam' => [ |
124 | - 'class' => 'nodge\eauth\services\SteamOpenIDService', | |
124 | + 'class' => 'common\components\nodge\eauth\src\services\SteamOpenIDService', | |
125 | 125 | //'realm' => '*.example.org', // your domain, can be with wildcard to authenticate on subdomains. |
126 | 126 | ], |
127 | 127 | 'instagram' => [ |
128 | 128 | // register your app here: https://instagram.com/developer/register/ |
129 | - 'class' => 'nodge\eauth\services\InstagramOAuth2Service', | |
129 | + 'class' => 'common\components\nodge\eauth\src\services\InstagramOAuth2Service', | |
130 | 130 | 'clientId' => '...', |
131 | 131 | 'clientSecret' => '...', |
132 | 132 | ], |
133 | 133 | 'vkontakte' => [ |
134 | 134 | // register your app here: https://vk.com/editapp?act=create&site=1 |
135 | - 'class' => 'nodge\eauth\services\VKontakteOAuth2Service', | |
135 | + 'class' => 'common\components\nodge\eauth\src\services\VKontakteOAuth2Service', | |
136 | 136 | 'clientId' => '5155388', |
137 | 137 | 'clientSecret' => 'jxgmdGVQw7huGKRpnX3a', |
138 | 138 | ], |
139 | 139 | 'mailru' => [ |
140 | 140 | // register your app here: http://api.mail.ru/sites/my/add |
141 | - 'class' => 'nodge\eauth\services\MailruOAuth2Service', | |
141 | + 'class' => 'common\components\nodge\eauth\src\services\MailruOAuth2Service', | |
142 | 142 | 'clientId' => '739322', |
143 | 143 | 'clientSecret' => 'd6ce7be6ff791375adff58fe0e4460b2', |
144 | 144 | ], |
145 | 145 | 'odnoklassniki' => [ |
146 | 146 | // register your app here: http://dev.odnoklassniki.ru/wiki/pages/viewpage.action?pageId=13992188 |
147 | 147 | // ... or here: http://www.odnoklassniki.ru/dk?st.cmd=appsInfoMyDevList&st._aid=Apps_Info_MyDev |
148 | - 'class' => 'nodge\eauth\services\OdnoklassnikiOAuth2Service', | |
148 | + 'class' => 'common\components\nodge\eauth\src\services\OdnoklassnikiOAuth2Service', | |
149 | 149 | 'clientId' => '...', |
150 | 150 | 'clientSecret' => '...', |
151 | 151 | 'clientPublic' => '...', |
... | ... | @@ -160,7 +160,7 @@ return [ |
160 | 160 | [ |
161 | 161 | 'class' => 'yii\log\FileTarget', |
162 | 162 | 'logFile' => '@app/runtime/logs/eauth.log', |
163 | - 'categories' => ['nodge\eauth\*'], | |
163 | + 'categories' => ['common\components\nodge\eauth\nodge\eauth\*'], | |
164 | 164 | 'logVars' => [], |
165 | 165 | ], |
166 | 166 | ], | ... | ... |
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
db-migration/social.backup renamed to db-migration/dmitryi/social.backup
No preview for this file type
db-migration/user.backup renamed to db-migration/dmitryi/user.backup
No preview for this file type
frontend/controllers/SiteController.php
... | ... | @@ -190,7 +190,7 @@ class SiteController extends Controller |
190 | 190 | */ |
191 | 191 | public function actionContact() |
192 | 192 | { |
193 | - //Yii::$app->user->logout(); | |
193 | + Yii::$app->user->logout(); | |
194 | 194 | $identity = Yii::$app->getUser()->getIdentity(); |
195 | 195 | var_dump($identity[profile]); |
196 | 196 | die(); | ... | ... |