init
This commit is contained in:
@@ -0,0 +1 @@
|
||||
see https://github.com/hybridauth/hybridauth/releases
|
||||
@@ -0,0 +1,46 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hybridauth@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
@@ -0,0 +1,49 @@
|
||||
Contributing
|
||||
============
|
||||
|
||||
Hybridauth is a community driven project, and it needs your help to keep the project going.
|
||||
|
||||
|
||||
### Report Problems
|
||||
|
||||
A great way to help is to find and submit [bug reports](https://github.com/hybridauth/hybridauth/issues) or to fix the
|
||||
existing ones.
|
||||
|
||||
When reporting new issues, please provide as much detail and context as possible, otherwise we will be left in the dark
|
||||
about the problem you having.
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
You can help improve Hybridauth user documentation (this website) by making it more consistent and readable, and by adding
|
||||
missing information, correcting errors and typos.
|
||||
|
||||
Hybridauth documentation is maintained as plain text markdown files at https://github.com/hybridauth/hybridauth.github.io
|
||||
|
||||
|
||||
### Develop
|
||||
|
||||
If you have fixed a bug or implemented a new feature that you would like to share with the community, send a pull request
|
||||
against the [dev branch](https://github.com/hybridauth/hybridauth/).
|
||||
|
||||
Before contributing code, please consider these guide lines:
|
||||
|
||||
**Coding Style**
|
||||
|
||||
Hybridauth follows [PSR-1](http://www.php-fig.org/psr/psr-1/) and [PSR-2](http://www.php-fig.org/psr/psr-2/).
|
||||
|
||||
Please prevent your IDE for reformatting huge chunks of code/files as it make it nearly impossible to see what changes were
|
||||
actually made to a file on your Pull Request.
|
||||
|
||||
**Compatibility**
|
||||
|
||||
Additional providers, minor enhancements, bugs and typos fixes are most welcome. Large and "breaking" changes should be
|
||||
discussed ahead of time. **Please ask first**.
|
||||
|
||||
Hybridauth 3 is compatible with **PHP 5.4** and therefore all code supplied must stick to this requirement.
|
||||
|
||||
**License**
|
||||
|
||||
Hybridauth PHP Library is released under the terms of MIT License: By contributing your code to the project, you agree to
|
||||
license your contribution under the MIT License. (which means, once you donate your code to the community, it become freely
|
||||
available to everyone to use, or mis-use).
|
||||
@@ -0,0 +1,75 @@
|
||||
Except where otherwise noted in the source code (i.e., LightOpenID and OAuth
|
||||
Library, which are covered by similar licences but with different Copyright
|
||||
notices) all the files are:
|
||||
|
||||
Copyright (C) 2009-2019, Hybridauth authors. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
-----------------------
|
||||
|
||||
|
||||
Hybridauth includes a copy of LightOpenID, licensed as follows:
|
||||
|
||||
Copyright (c) 2013-2016 Mewp (mewp151 at gmail dot com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
-----------------------
|
||||
|
||||
|
||||
Hybridauth includes a modified copy of OAuth PHP Library, licensed as follows:
|
||||
|
||||
Copyright (c) 2007-2011 Andy Smith
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,13 @@
|
||||
## Bug, feature or question?
|
||||
|
||||
Is this a bug, a feature request or a question?
|
||||
Give us a short description.
|
||||
|
||||
### Version and provider
|
||||
|
||||
What version of Hybrid Auth does this relates to?
|
||||
Is this an issue with a provider? If yes, which one?
|
||||
|
||||
### Reproduction
|
||||
|
||||
How can we replicate this issue?
|
||||
@@ -0,0 +1,9 @@
|
||||
| Q | A
|
||||
| ------------------------ | ---
|
||||
| Fixed Issues? | `Fixes #1, Fixes #2` <!-- remove the (`) quotes to link the issues -->
|
||||
| Patch: Bug Fix? |
|
||||
| Major: Breaking Change? |
|
||||
| Minor: New Feature? |
|
||||
|
||||
<!-- Describe your changes below in as much detail as possible -->
|
||||
<!-- For documentation fixes, pls create a PR in https://github.com/hybridauth/hybridauth.github.io -->
|
||||
@@ -0,0 +1,67 @@
|
||||
## [Hybridauth](https://hybridauth.github.io/) 3.7.1
|
||||
|
||||
[](https://travis-ci.org/hybridauth/hybridauth) [](https://scrutinizer-ci.com/g/hybridauth/hybridauth/?branch=master) [](https://packagist.org/packages/hybridauth/hybridauth) [](https://gitter.im/hybridauth/hybridauth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
Hybridauth enables developers to easily build social applications and tools to engage websites visitors and customers on a social level that starts off with social sign-in and extends to social sharing, users profiles, friends lists, activities streams, status updates and more.
|
||||
|
||||
The main goal of Hybridauth is to act as an abstract API between your application and the various social networks APIs and identities providers such as Facebook, Twitter and Google.
|
||||
|
||||
#### Usage
|
||||
|
||||
Hybridauth provides a number of basic [examples](https://github.com/hybridauth/hybridauth/tree/master/examples). You can also find complete Hybridauth documentation at https://hybridauth.github.io
|
||||
|
||||
```php
|
||||
$config = [
|
||||
'callback' => 'https://example.com/path/to/script.php',
|
||||
'keys' => [
|
||||
'key' => 'your-twitter-consumer-key',
|
||||
'secret' => 'your-twitter-consumer-secret',
|
||||
],
|
||||
];
|
||||
|
||||
try {
|
||||
$twitter = new Hybridauth\Provider\Twitter($config);
|
||||
|
||||
$twitter->authenticate();
|
||||
|
||||
$accessToken = $twitter->getAccessToken();
|
||||
$userProfile = $twitter->getUserProfile();
|
||||
$apiResponse = $twitter->apiRequest('statuses/home_timeline.json');
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
echo 'Oops, we ran into an issue! ' . $e->getMessage();
|
||||
}
|
||||
```
|
||||
|
||||
#### Requirements
|
||||
|
||||
* PHP 5.4+
|
||||
* PHP Session
|
||||
* PHP cURL
|
||||
|
||||
#### Installation
|
||||
|
||||
To install Hybridauth we recommend [Composer](https://getcomposer.org/), the now defacto dependency manager for PHP. Alternatively, you can download and use the latest release available at [Github](https://github.com/hybridauth/hybridauth/releases).
|
||||
|
||||
#### Versions Status
|
||||
|
||||
| Version | Status | Repository | Documentation | PHP Version |
|
||||
|---------|-------------|-------------------------|-------------------------|-------------|
|
||||
| 2.x | Maintenance | [v2][hybridauth-2-repo] | [v2][hybridauth-2-docs] | >= 5.3 |
|
||||
| 3.x | Development | [v3][hybridauth-3-repo] | [v3][hybridauth-3-docs] | >= 5.4 |
|
||||
| 4.x | Future | -- | -- | >= 7.3 |
|
||||
|
||||
[hybridauth-2-repo]: https://github.com/hybridauth/hybridauth/tree/v2
|
||||
[hybridauth-3-repo]: https://github.com/hybridauth/hybridauth/
|
||||
[hybridauth-2-docs]: https://hybridauth.github.io/hybridauth/
|
||||
[hybridauth-3-docs]: https://hybridauth.github.io/
|
||||
|
||||
#### Questions, Help and Support?
|
||||
|
||||
For general questions (i.e, "how-to" questions), please consider using [StackOverflow](https://stackoverflow.com/questions/tagged/hybridauth) instead of the Github issues tracker. For convenience, we also have a [low-activity] [Gitter channel](https://gitter.im/hybridauth/hybridauth) if you want to get help directly from the community.
|
||||
|
||||
#### License
|
||||
|
||||
Hybridauth PHP Library is released under the terms of MIT License.
|
||||
|
||||
For the full Copyright Notice and Disclaimer, see [COPYING.md](https://github.com/hybridauth/hybridauth/blob/master/COPYING.md).
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
session_start();
|
||||
include __DIR__."/src/autoload.php";
|
||||
|
||||
use Hybridauth\Hybridauth;
|
||||
use Hybridauth\HttpClient;
|
||||
|
||||
// include __DIR__."/../../dbinfo.php";
|
||||
$db = mysqli_connect(MYSQL_RW_HOST, MYSQL_USER_ID, MYSQL_USER_PW, MYSQL_DB_NAME);
|
||||
$db->query("set session character_set_client=utf8mb4;");
|
||||
$db->query("set session character_set_connection=utf8mb4;");
|
||||
// echo nl2br(print_r($_SESSION,1));
|
||||
$config = [
|
||||
'callback' => "https://{$_SERVER['HTTP_HOST']}{$_SERVER['REDIRECT_URL']}",
|
||||
|
||||
'providers' => [
|
||||
'Kakao' => [
|
||||
'enabled' => true,
|
||||
'name' => '카카오톡',
|
||||
'keys' => ['id' => '500a99d34478a54c7c4fbfc04ff90512', 'secret' => ' '],
|
||||
// 'keys' => ['id' => '2b01f5f8aed3146fb045034489a410ba', 'secret' => ' '], //예쁨주의쁨의원
|
||||
// 'keys' => ['id' => '9934f98df726d20ad728eec94d40e323', 'secret' => ' '], //하늘안과
|
||||
],
|
||||
'Facebook' => [
|
||||
'enabled' => true,
|
||||
'name' => '페이스북',
|
||||
'keys' => ['id' => '1225097934573584', 'secret' => '08f4b7d15f725c2856fef1a8a696607d']
|
||||
],
|
||||
'Naver' => [
|
||||
'enabled' => true,
|
||||
'name' => '네이버',
|
||||
// 'keys' => ['id' => 'PiV62dqtvaoffn0GkK4Y', 'secret' => 'gye6ngjg0_'], //케어랩스
|
||||
'keys' => ['id' => 'EoQUcrKT07bjcBt2rDZ0', 'secret' => '9cIABEwMeG'], //에스앤유안과
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$hybridauth = new Hybridauth($config);
|
||||
$adapter = @$hybridauth->authenticate($provider);
|
||||
$userProfile = @$adapter->getUserProfile();
|
||||
$_SESSION['userProfile'] = (array)$userProfile;
|
||||
if(isset($_SESSION['kakaosync'])) {
|
||||
$landing = $_SESSION['kakaosync'];
|
||||
$url = "https://{$landing}";
|
||||
header("Location: {$url}");
|
||||
exit;
|
||||
}
|
||||
// echo nl2br(print_r($adapter->storage->get('REQUEST_URI'),1)); exit;
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SNS 로그인</title>
|
||||
<script src="//static.hotblood.co.kr/libs/jquery/1.12.4/jquery.min.js"></script>
|
||||
<style>
|
||||
.action{text-align: center;}
|
||||
.btn_close{border: 0 none; text-decoration: underline; background-color: transparent; font-size: 120%; cursor: pointer;}
|
||||
.lds-facebook {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.lds-facebook div {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
width: 16px;
|
||||
background: #fed;
|
||||
animation: lds-facebook 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite;
|
||||
}
|
||||
.lds-facebook div:nth-child(1) {
|
||||
left: 8px;
|
||||
animation-delay: -0.24s;
|
||||
}
|
||||
.lds-facebook div:nth-child(2) {
|
||||
left: 32px;
|
||||
animation-delay: -0.12s;
|
||||
}
|
||||
.lds-facebook div:nth-child(3) {
|
||||
left: 56px;
|
||||
animation-delay: 0;
|
||||
}
|
||||
@keyframes lds-facebook {
|
||||
0% {
|
||||
top: 8px;
|
||||
height: 64px;
|
||||
}
|
||||
50%, 100% {
|
||||
top: 24px;
|
||||
height: 32px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="action">
|
||||
<div class="lds-facebook"><div></div><div></div><div></div></div>
|
||||
<p><?php echo $config['providers'][ucfirst($provider)]['name'];?>에서 정보를 받아오고 있습니다.</p>
|
||||
<p class="done">완료되었습니다. 이 탭을 닫으신 후 신청페이지로 돌아가주세요.</p>
|
||||
</div>
|
||||
<?
|
||||
$adapter->disconnect();
|
||||
// echo '<pre>'.print_r($adapter,1).'</pre>'; exit;
|
||||
if(!$userProfile->displayName) exit;
|
||||
if(!empty($userProfile->gender) && preg_match('/^(여|f)/i', $userProfile->gender)) {
|
||||
$gender = "1";
|
||||
} else if(!empty($userProfile->gender) && preg_match('/^(남|m)/i', $userProfile->gender)) {
|
||||
$gender = "0";
|
||||
}
|
||||
|
||||
$evt_no = $_SESSION['no'];
|
||||
$code = @$_SESSION['code'];
|
||||
$site = @$_SESSION['site'];
|
||||
$today = date('Y-m-d');
|
||||
$imp_sql = "INSERT INTO event_sns_clicks_history(seq, date, code, site, provider, clicks, last_datetime) VALUES('{$evt_no}', '{$today}', '{$code}', '{$site}', '{$provider}', 1, NOW()) ON DUPLICATE KEY UPDATE clicks = clicks + 1, last_datetime = NOW()";
|
||||
if(!preg_match('/bot/i', $_SERVER['HTTP_USER_AGENT']))
|
||||
$db->query($imp_sql, true);
|
||||
?>
|
||||
<script defer>
|
||||
$(document).ready(function() {
|
||||
setTimeout(function() {
|
||||
var o = window.opener;
|
||||
var $doc = $(o.document);
|
||||
$('[name="name"]', $doc).val('<?php echo @$userProfile->displayName;?>');
|
||||
$('[name="name"]', $doc).after('<input name="memo3" type="hidden">').next('[name="memo3"]').val('<?php echo @$provider;?>');
|
||||
$('[name="age"]', $doc).val('<?php echo @$userProfile->age;?>');
|
||||
$('[name="email"]', $doc).val('<?php echo @$userProfile->email;?>');
|
||||
$('[name="phone"]', $doc).val('<?php echo @$userProfile->phone;?>');
|
||||
<?php if(isset($gender)) {?>
|
||||
$('[name="gender"]', $doc).eq(<?php echo @$gender;?>).prop('checked', true);
|
||||
<?php } ?>
|
||||
$('.submit input', $doc).trigger('click');
|
||||
setTimeout(function() {
|
||||
window.self.close();
|
||||
}, 500)
|
||||
},500)
|
||||
$('.btn_close').click(function(e) {
|
||||
e.preventDefault();
|
||||
self.close;
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,12 @@
|
||||
Hybridauth 3 Examples
|
||||
======================
|
||||
|
||||
File | Description
|
||||
-------------- | ------------------------------------------------------------------------------
|
||||
example_01.php | This simple example illustrate how to authenticate users with GitHub. If you're new to Hybridauth, this file is the one you'll likely want to check.
|
||||
example_02.php | Details how to use users in a similar fashion to Hybridauth 2. Note that while Hybridauth 3 provides a similar interface to Hybridauth 2, both versions are not fully compatible with each other.
|
||||
example_03.php | An example on how use Access Tokens to access providers APIs, and how to setup custom API endpoints.
|
||||
example_04.php | A simple example that shows how to connect users to providers using OpenID.
|
||||
example_05.php | A simple example that shows how to use Guzzle as a Http Client for Hybridauth instead of PHP Curl extension.
|
||||
example_06/ | A simple example that shows how to organize multiple providers.
|
||||
example_07/ | A simple example that shows how to organize multiple providers, using a pop-up.
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
/*!
|
||||
* This simple example illustrate how to authenticate users with GitHub.
|
||||
*
|
||||
* Most other providers work pretty much the same.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Step 0: Start PHP session
|
||||
*
|
||||
* Normally this step is not required as Hybridauth will attempt to start the session for you, however
|
||||
* in some cases it might be better to call session_start() at top of script to avoid cookie-based sessions
|
||||
* issues.
|
||||
*
|
||||
* See: http://php.net/manual/en/function.session-start.php#refsect1-function.session-start-notes
|
||||
* http://stackoverflow.com/a/8028987
|
||||
*/
|
||||
|
||||
session_start();
|
||||
|
||||
/**
|
||||
* Step 1: Require the Hybridauth Library
|
||||
*
|
||||
* Should be as simple as including Composer's autoloader.
|
||||
*/
|
||||
|
||||
include '../src/autoload.php';
|
||||
|
||||
/**
|
||||
* Step 2: Configuring Your Application
|
||||
*
|
||||
* If you're already familiar with the process, you can skip the explanation below.
|
||||
*
|
||||
* To get started with GitHub authentication, you need to create a new GitHub application.
|
||||
*
|
||||
* First, navigate to https://github.com/settings/developers then click the Register
|
||||
* new application button at the top right of that page and fill in any required fields
|
||||
* such as the application name, description and website.
|
||||
*
|
||||
* Set the Authorization callback URL to https://path/to/hybridauth/examples/example_01.php.
|
||||
* Understandably, you need to replace 'path/to/hybridauth' with the real path to this script.
|
||||
*
|
||||
* Note that Hybridauth provides an utility function that can generate the current page url for you
|
||||
* and can be used for the callback. Example: 'callback' => Hybridauth\HttpClient\Util::getCurrentUrl()
|
||||
*
|
||||
* After configuring your GitHub application, simple replace 'your-app-id' and 'your-app-secret'
|
||||
* with your application credentials (Client ID and Client Secret).
|
||||
*
|
||||
* Providers who uses OAuth 2.0 protocol (i.g., GitHub, Facebook, Google, etc.) may need
|
||||
* an Authorization scope as additional parameter. Authorization scopes are strings that
|
||||
* enable access to particular resources, such as user data.
|
||||
*
|
||||
* https://developer.github.com/v3/oauth/
|
||||
* https://developer.github.com/v3/oauth/#scopes
|
||||
*/
|
||||
|
||||
$config = [
|
||||
'callback' => 'https://path/to/hybridauth/examples/example_01.php', // or Hybridauth\HttpClient\Util::getCurrentUrl()
|
||||
|
||||
'keys' => ['id' => 'your-app-id', 'secret' => 'your-app-secret'], // Your Github application credentials
|
||||
|
||||
/* optional : set scope
|
||||
'scope' => 'user:email', */
|
||||
|
||||
/* optional : set debug mode
|
||||
'debug_mode' => true,
|
||||
// Path to file writeable by the web server. Required if 'debug_mode' is not false
|
||||
'debug_file' => __FILE__ . '.log', */
|
||||
|
||||
/* optional : customize Curl settings
|
||||
// for more information on curl, refer to: http://www.php.net/manual/fr/function.curl-setopt.php
|
||||
'curl_options' => [
|
||||
// setting custom certificates
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
CURLOPT_CAINFO => '/path/to/your/certificate.crt',
|
||||
|
||||
// set a valid proxy ip address
|
||||
CURLOPT_PROXY => '*.*.*.*:*',
|
||||
|
||||
// set a custom user agent
|
||||
CURLOPT_USERAGENT => ''
|
||||
] */
|
||||
];
|
||||
|
||||
/**
|
||||
* Step 3: Instantiate Github Adapter
|
||||
*
|
||||
* This example instantiates a GitHub adapter using the array $config we just built.
|
||||
*/
|
||||
|
||||
$github = new Hybridauth\Provider\GitHub($config);
|
||||
|
||||
/**
|
||||
* Step 4: Authenticating Users
|
||||
*
|
||||
* When invoked, `authenticate()` will redirect users to GitHub login page where they
|
||||
* will be asked to grant access to your application. If they do, GitHub will redirect
|
||||
* the users back to Authorization callback URL (i.e., this script).
|
||||
*
|
||||
* Note that GitHub and few other providers will ask their users for authorisation
|
||||
* only once.
|
||||
*/
|
||||
|
||||
$github->authenticate();
|
||||
|
||||
/**
|
||||
* Step 5: Retrieve Users Profiles
|
||||
*
|
||||
* Calling getUserProfile returns an instance of class Hybridauth\User\Profile which contain the
|
||||
* connected user's profile in simple and standardized structure across all the social APIs supported
|
||||
* by Hybridauth.
|
||||
*/
|
||||
|
||||
$userProfile = $github->getUserProfile();
|
||||
|
||||
echo 'Hi ' . $userProfile->displayName;
|
||||
|
||||
/**
|
||||
* Bonus: Access GitHub API
|
||||
*
|
||||
* Now that the user is authenticated with Gihub, and depending on the authorization given to your
|
||||
* application, you should be able to query the said API on behalf of the user.
|
||||
*
|
||||
* As an example we list the authenticated user's public gists.
|
||||
*/
|
||||
|
||||
$apiResponse = $github->apiRequest('gists');
|
||||
|
||||
/**
|
||||
* Step 6: Disconnect the adapter
|
||||
*
|
||||
* This will erase the current user authentication data from session, and any further
|
||||
* attempt to communicate with Github API will result on an authorisation exception.
|
||||
*/
|
||||
|
||||
$github->disconnect();
|
||||
|
||||
/**
|
||||
* Final note: Catching Exceptions
|
||||
*
|
||||
* Hybridauth use exceptions extensively and it's important that these exceptions
|
||||
* be properly caught/handled in your code.
|
||||
*
|
||||
* Below is a basic example of how to catch exceptions.
|
||||
*
|
||||
* Note that on the previous step we disconnected from the API; meaning Hybridauth
|
||||
* has erased the oauth access token used to sign http requests from the current
|
||||
* session, thus, any new request we now make will now throw an exception.
|
||||
*
|
||||
* It's important that you don't show Hybridauth exception's messages to the end user as
|
||||
* they may include sensitive data, and that you use your own error messages instead.
|
||||
*/
|
||||
|
||||
try {
|
||||
$github->getUserProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch Curl Errors
|
||||
*
|
||||
* This kind of error may happen in case of:
|
||||
* - Internet or Network issues.
|
||||
* - Your server configuration is not setup correctly.
|
||||
*
|
||||
* The full list of curl errors that may happen can be found at http://curl.haxx.se/libcurl/c/libcurl-errors.html
|
||||
*/
|
||||
catch (Hybridauth\Exception\HttpClientFailureException $e) {
|
||||
echo 'Curl text error message : ' . $github->getHttpClient()->getResponseClientError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch API Requests Errors
|
||||
*
|
||||
* This usually happens when requesting a:
|
||||
* - Wrong URI or a mal-formatted http request.
|
||||
* - Protected resource without providing a valid access token.
|
||||
*/
|
||||
catch (Hybridauth\Exception\HttpRequestFailedException $e) {
|
||||
echo 'Raw API Response: ' . $github->getHttpClient()->getResponseBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Base PHP's exception that catches everything [else]
|
||||
*/
|
||||
catch (\Exception $e) {
|
||||
echo 'Oops! We ran into an unknown issue: ' . $e->getMessage();
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/*!
|
||||
* Details how to use users in a similar fashion to Hybridauth 2. Note that while Hybridauth 3 provides
|
||||
* a similar interface to Hybridauth 2, both versions are not fully compatible with each other.
|
||||
*/
|
||||
|
||||
include '../src/autoload.php';
|
||||
|
||||
use Hybridauth\Hybridauth;
|
||||
use Hybridauth\HttpClient;
|
||||
|
||||
$config = [
|
||||
'callback' => HttpClient\Util::getCurrentUrl(),
|
||||
|
||||
'providers' => [
|
||||
'GitHub' => [
|
||||
'enabled' => true,
|
||||
'keys' => ['id' => '', 'secret' => ''],
|
||||
],
|
||||
|
||||
'Google' => [
|
||||
'enabled' => true,
|
||||
'keys' => ['id' => '', 'secret' => ''],
|
||||
],
|
||||
|
||||
'Facebook' => [
|
||||
'enabled' => true,
|
||||
'keys' => ['id' => '', 'secret' => ''],
|
||||
],
|
||||
|
||||
'Twitter' => [
|
||||
'enabled' => true,
|
||||
'keys' => ['key' => '', 'secret' => ''],
|
||||
]
|
||||
],
|
||||
|
||||
/* optional : set debug mode
|
||||
'debug_mode' => true,
|
||||
// Path to file writeable by the web server. Required if 'debug_mode' is not false
|
||||
'debug_file' => __FILE__ . '.log', */
|
||||
|
||||
/* optional : customize Curl settings
|
||||
// for more information on curl, refer to: http://www.php.net/manual/fr/function.curl-setopt.php
|
||||
'curl_options' => [
|
||||
// setting custom certificates
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
CURLOPT_CAINFO => '/path/to/your/certificate.crt',
|
||||
|
||||
// set a valid proxy ip address
|
||||
CURLOPT_PROXY => '*.*.*.*:*',
|
||||
|
||||
// set a custom user agent
|
||||
CURLOPT_USERAGENT => ''
|
||||
] */
|
||||
];
|
||||
|
||||
try {
|
||||
$hybridauth = new Hybridauth($config);
|
||||
|
||||
$adapter = $hybridauth->authenticate('GitHub');
|
||||
|
||||
// $adapter = $hybridauth->authenticate('Google');
|
||||
// $adapter = $hybridauth->authenticate('Facebook');
|
||||
// $adapter = $hybridauth->authenticate('Twitter');
|
||||
|
||||
$tokens = $adapter->getAccessToken();
|
||||
$userProfile = $adapter->getUserProfile();
|
||||
|
||||
// print_r($tokens);
|
||||
// print_r($userProfile);
|
||||
|
||||
$adapter->disconnect();
|
||||
} catch (\Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/*!
|
||||
* An example on how use Access Tokens to access providers APIs, and how to setup custom API endpoints.
|
||||
*/
|
||||
|
||||
include 'vendor/autoload.php';
|
||||
|
||||
$config = [
|
||||
'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
|
||||
'keys' => ['id' => 'your-facebook-app-id', 'secret' => 'your-facebook-app-secret'],
|
||||
|
||||
'endpoints' => [
|
||||
'api_base_url' => 'https://graph.facebook.com/v2.8/',
|
||||
'authorize_url' => 'https://www.facebook.com/dialog/oauth',
|
||||
'access_token_url' => 'https://graph.facebook.com/oauth/access_token',
|
||||
]
|
||||
];
|
||||
|
||||
try {
|
||||
$adapter = new Hybridauth\Provider\Facebook($config);
|
||||
|
||||
$adapter->setAccessToken(['access_token' => 'user-facebook-access-token']);
|
||||
|
||||
$userProfile = $adapter->getUserProfile();
|
||||
|
||||
// print_r($userProfile);
|
||||
|
||||
$adapter->disconnect();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/*!
|
||||
* A simple example that shows how to connect users to providers using OpenID.
|
||||
*/
|
||||
|
||||
include 'vendor/autoload.php';
|
||||
|
||||
$config = [
|
||||
'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
|
||||
'openid_identifier' => 'https://open.login.yahooapis.com/openid20/www.yahoo.com/xrds',
|
||||
// 'openid_identifier' => 'https://openid.stackexchange.com/',
|
||||
// 'openid_identifier' => 'http://steamcommunity.com/openid',
|
||||
// etc.
|
||||
];
|
||||
|
||||
try {
|
||||
$adapter = new Hybridauth\Provider\OpenID($config);
|
||||
|
||||
$adapter->authenticate();
|
||||
|
||||
$tokens = $adapter->getAccessToken();
|
||||
$userProfile = $adapter->getUserProfile();
|
||||
|
||||
// print_r($tokens);
|
||||
// print_r($userProfile);
|
||||
|
||||
$adapter->disconnect();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/*!
|
||||
* A simple example that shows how to use Guzzle as a Http Client for Hybridauth instead of PHP Curl extention.
|
||||
*/
|
||||
|
||||
include 'vendor/autoload.php';
|
||||
|
||||
$config = [
|
||||
'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
|
||||
'keys' => ['id' => '', 'secret' => ''],
|
||||
];
|
||||
|
||||
$guzzle = new Hybridauth\HttpClient\Guzzle(null, [
|
||||
// 'verify' => true, # Set to false to disable SSL certificate verification
|
||||
]);
|
||||
|
||||
try {
|
||||
$adapter = new Hybridauth\Provider\Github($config, $guzzle);
|
||||
|
||||
$adapter->authenticate();
|
||||
|
||||
$tokens = $adapter->getAccessToken();
|
||||
$userProfile = $adapter->getUserProfile();
|
||||
|
||||
// print_r($tokens);
|
||||
// print_r($userProfile);
|
||||
|
||||
$adapter->disconnect();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* A simple example that shows how to use multiple providers.
|
||||
*/
|
||||
|
||||
include 'vendor/autoload.php';
|
||||
include 'config.php';
|
||||
|
||||
use Hybridauth\Exception\Exception;
|
||||
use Hybridauth\Hybridauth;
|
||||
use Hybridauth\HttpClient;
|
||||
use Hybridauth\Storage\Session;
|
||||
|
||||
try {
|
||||
/**
|
||||
* Feed configuration array to Hybridauth.
|
||||
*/
|
||||
$hybridauth = new Hybridauth($config);
|
||||
|
||||
/**
|
||||
* Initialize session storage.
|
||||
*/
|
||||
$storage = new Session();
|
||||
|
||||
/**
|
||||
* Hold information about provider when user clicks on Sign In.
|
||||
*/
|
||||
if (isset($_GET['provider'])) {
|
||||
$storage->set('provider', $_GET['provider']);
|
||||
}
|
||||
|
||||
/**
|
||||
* When provider exists in the storage, try to authenticate user and clear storage.
|
||||
*
|
||||
* When invoked, `authenticate()` will redirect users to provider login page where they
|
||||
* will be asked to grant access to your application. If they do, provider will redirect
|
||||
* the users back to Authorization callback URL (i.e., this script).
|
||||
*/
|
||||
if ($provider = $storage->get('provider')) {
|
||||
$hybridauth->authenticate($provider);
|
||||
$storage->set('provider', null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will erase the current user authentication data from session, and any further
|
||||
* attempt to communicate with provider.
|
||||
*/
|
||||
if (isset($_GET['logout'])) {
|
||||
$adapter = $hybridauth->getAdapter($_GET['logout']);
|
||||
$adapter->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects user to home page (i.e., index.php in our case)
|
||||
*/
|
||||
HttpClient\Util::redirect('https://path/to/hybridauth/examples/example_06');
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* Build a configuration array to pass to `Hybridauth\Hybridauth`
|
||||
*/
|
||||
|
||||
$config = [
|
||||
/**
|
||||
* Set the Authorization callback URL to https://path/to/hybridauth/examples/example_06/callback.php.
|
||||
* Understandably, you need to replace 'path/to/hybridauth' with the real path to this script.
|
||||
*/
|
||||
'callback' => 'https://path/to/hybridauth/examples/example_06/callback.php',
|
||||
'providers' => [
|
||||
'Twitter' => [
|
||||
'enabled' => true,
|
||||
'keys' => [
|
||||
'key' => '...',
|
||||
'secret' => '...',
|
||||
],
|
||||
],
|
||||
'LinkedIn' => [
|
||||
'enabled' => true,
|
||||
'keys' => [
|
||||
'id' => '...',
|
||||
'secret' => '...',
|
||||
],
|
||||
],
|
||||
'Facebook' => [
|
||||
'enabled' => true,
|
||||
'keys' => [
|
||||
'id' => '...',
|
||||
'secret' => '...',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* Build a simple HTML page with multiple providers.
|
||||
*/
|
||||
|
||||
include 'vendor/autoload.php';
|
||||
include 'config.php';
|
||||
|
||||
use Hybridauth\Hybridauth;
|
||||
|
||||
$hybridauth = new Hybridauth($config);
|
||||
$adapters = $hybridauth->getConnectedAdapters();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Example 06</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Sign in</h1>
|
||||
|
||||
<ul>
|
||||
<?php foreach ($hybridauth->getProviders() as $name) : ?>
|
||||
<?php if (!isset($adapters[$name])) : ?>
|
||||
<li>
|
||||
<a href="<?php print $config['callback'] . "?provider={$name}"; ?>">
|
||||
Sign in with <strong><?php print $name; ?></strong>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<?php if ($adapters) : ?>
|
||||
<h1>You are logged in:</h1>
|
||||
<ul>
|
||||
<?php foreach ($adapters as $name => $adapter) : ?>
|
||||
<li>
|
||||
<strong><?php print $adapter->getUserProfile()->displayName; ?></strong> from
|
||||
<i><?php print $name; ?></i>
|
||||
<span>(<a href="<?php print $config['callback'] . "?logout={$name}"; ?>">Log Out</a>)</span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* A simple example that shows how to use multiple providers, opening provider authentication in a pop-up.
|
||||
*/
|
||||
|
||||
require 'path/to/vendor/autoload.php';
|
||||
require 'config.php';
|
||||
|
||||
use Hybridauth\Exception\Exception;
|
||||
use Hybridauth\Hybridauth;
|
||||
use Hybridauth\HttpClient;
|
||||
use Hybridauth\Storage\Session;
|
||||
|
||||
try {
|
||||
|
||||
$hybridauth = new Hybridauth($config);
|
||||
$storage = new Session();
|
||||
$error = false;
|
||||
|
||||
//
|
||||
// Event 1: User clicked SIGN-IN link
|
||||
//
|
||||
if (isset($_GET['provider'])) {
|
||||
// Validate provider exists in the $config
|
||||
if (in_array($_GET['provider'], $hybridauth->getProviders())) {
|
||||
// Store the provider for the callback event
|
||||
$storage->set('provider', $_GET['provider']);
|
||||
} else {
|
||||
$error = $_GET['provider'];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Event 2: User clicked LOGOUT link
|
||||
//
|
||||
if (isset($_GET['logout'])) {
|
||||
if (in_array($_GET['logout'], $hybridauth->getProviders())) {
|
||||
// Disconnect the adapter
|
||||
$adapter = $hybridauth->getAdapter($_GET['logout']);
|
||||
$adapter->disconnect();
|
||||
} else {
|
||||
$error = $_GET['logout'];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Handle invalid provider errors
|
||||
//
|
||||
if ($error) {
|
||||
error_log('Hybridauth Error: Provider ' . json_encode($error) . ' not found or not enabled in $config');
|
||||
// Close the pop-up window
|
||||
echo "
|
||||
<script>
|
||||
if (window.opener.closeAuthWindow) {
|
||||
window.opener.closeAuthWindow();
|
||||
}
|
||||
</script>";
|
||||
exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Event 3: Provider returns via CALLBACK
|
||||
//
|
||||
if ($provider = $storage->get('provider')) {
|
||||
|
||||
$hybridauth->authenticate($provider);
|
||||
$storage->set('provider', null);
|
||||
|
||||
// Retrieve the provider record
|
||||
$adapter = $hybridauth->getAdapter($provider);
|
||||
$userProfile = $adapter->getUserProfile();
|
||||
$accessToken = $adapter->getAccessToken();
|
||||
|
||||
// add your custom AUTH functions (if any) here
|
||||
// ...
|
||||
$data = [
|
||||
'token' => $accessToken,
|
||||
'identifier' => $userProfile->identifier,
|
||||
'email' => $userProfile->email,
|
||||
'first_name' => $userProfile->firstName,
|
||||
'last_name' => $userProfile->lastName,
|
||||
'photoURL' => strtok($userProfile->photoURL, '?'),
|
||||
];
|
||||
// ...
|
||||
|
||||
// Close pop-up window
|
||||
echo "
|
||||
<script>
|
||||
if (window.opener.closeAuthWindow) {
|
||||
window.opener.closeAuthWindow();
|
||||
}
|
||||
</script>";
|
||||
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log($e->getMessage());
|
||||
echo $e->getMessage();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* Build a configuration array to pass to `Hybridauth\Hybridauth`
|
||||
*
|
||||
* Set the Authorization callback URL to https://path/to/hybridauth/examples/example_07/callback.php
|
||||
* Understandably, you need to replace 'path/to/hybridauth' with the real path to this script.
|
||||
*/
|
||||
$config = [
|
||||
'callback' => 'https://path/to/hybridauth/examples/example_07/callback.php',
|
||||
'providers' => [
|
||||
|
||||
'Google' => [
|
||||
'enabled' => true,
|
||||
'keys' => [
|
||||
'id' => '...',
|
||||
'secret' => '...',
|
||||
],
|
||||
'scope' => 'email',
|
||||
],
|
||||
|
||||
// 'Yahoo' => ['enabled' => true, 'keys' => ['key' => '...', 'secret' => '...']],
|
||||
// 'Facebook' => ['enabled' => true, 'keys' => ['id' => '...', 'secret' => '...']],
|
||||
// 'Twitter' => ['enabled' => true, 'keys' => ['key' => '...', 'secret' => '...']],
|
||||
// 'Instagram' => ['enabled' => true, 'keys' => ['id' => '...', 'secret' => '...']],
|
||||
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* Build a simple HTML page with multiple providers, opening provider authentication in a pop-up.
|
||||
*/
|
||||
|
||||
require 'path/to/vendor/autoload.php';
|
||||
require 'config.php';
|
||||
|
||||
use Hybridauth\Hybridauth;
|
||||
|
||||
$hybridauth = new Hybridauth($config);
|
||||
$adapters = $hybridauth->getConnectedAdapters();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Example 07</title>
|
||||
|
||||
<script>
|
||||
function auth_popup(provider) {
|
||||
// replace 'path/to/hybridauth' with the real path to this script
|
||||
var authWindow = window.open('https://path/to/hybridauth/examples/example_07/callback.php?provider=' + provider, 'authWindow', 'width=600,height=400,scrollbars=yes');
|
||||
window.closeAuthWindow = function () {
|
||||
authWindow.close();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>Sign in</h1>
|
||||
|
||||
<ul>
|
||||
|
||||
<?php foreach ($hybridauth->getProviders() as $name) : ?>
|
||||
<?php if (!isset($adapters[$name])) : ?>
|
||||
<li>
|
||||
<a href="#" onclick="javascript:auth_popup('<?php print $name ?>');">
|
||||
Sign in with <?php print $name ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</ul>
|
||||
|
||||
<?php if ($adapters) : ?>
|
||||
<h1>You are logged in:</h1>
|
||||
<ul>
|
||||
<?php foreach ($adapters as $name => $adapter) : ?>
|
||||
<li>
|
||||
<strong><?php print $adapter->getUserProfile()->displayName; ?></strong> from
|
||||
<i><?php print $name; ?></i>
|
||||
<span>(<a href="<?php print $config['callback'] . "?logout={$name}"; ?>">Log Out</a>)</span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
403.
|
||||
@@ -0,0 +1,372 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Adapter;
|
||||
|
||||
use Hybridauth\Exception\NotImplementedException;
|
||||
use Hybridauth\Exception\InvalidArgumentException;
|
||||
use Hybridauth\Exception\HttpClientFailureException;
|
||||
use Hybridauth\Exception\HttpRequestFailedException;
|
||||
use Hybridauth\Storage\StorageInterface;
|
||||
use Hybridauth\Storage\Session;
|
||||
use Hybridauth\Logger\LoggerInterface;
|
||||
use Hybridauth\Logger\Logger;
|
||||
use Hybridauth\HttpClient\HttpClientInterface;
|
||||
use Hybridauth\HttpClient\Curl as HttpClient;
|
||||
use Hybridauth\Data;
|
||||
|
||||
/**
|
||||
* Class AbstractAdapter
|
||||
*/
|
||||
abstract class AbstractAdapter implements AdapterInterface
|
||||
{
|
||||
use DataStoreTrait;
|
||||
|
||||
/**
|
||||
* Provider ID (unique name).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $providerId = '';
|
||||
|
||||
/**
|
||||
* Specific Provider config.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* Extra Provider parameters.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $params;
|
||||
|
||||
/**
|
||||
* Callback url
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $callback = '';
|
||||
|
||||
/**
|
||||
* Storage.
|
||||
*
|
||||
* @var StorageInterface
|
||||
*/
|
||||
public $storage;
|
||||
|
||||
/**
|
||||
* HttpClient.
|
||||
*
|
||||
* @var HttpClientInterface
|
||||
*/
|
||||
public $httpClient;
|
||||
|
||||
/**
|
||||
* Logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
public $logger;
|
||||
|
||||
/**
|
||||
* Whether to validate API status codes of http responses
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $validateApiResponseHttpCode = true;
|
||||
|
||||
/**
|
||||
* Common adapters constructor.
|
||||
*
|
||||
* @param array $config
|
||||
* @param HttpClientInterface $httpClient
|
||||
* @param StorageInterface $storage
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function __construct(
|
||||
$config = [],
|
||||
HttpClientInterface $httpClient = null,
|
||||
StorageInterface $storage = null,
|
||||
LoggerInterface $logger = null
|
||||
) {
|
||||
$this->providerId = (new \ReflectionClass($this))->getShortName();
|
||||
|
||||
$this->config = new Data\Collection($config);
|
||||
|
||||
$this->setHttpClient($httpClient);
|
||||
|
||||
$this->setStorage($storage);
|
||||
|
||||
$this->setLogger($logger);
|
||||
|
||||
$this->configure();
|
||||
|
||||
$this->logger->debug(sprintf('Initialize %s, config: ', get_class($this)), $config);
|
||||
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load adapter's configuration
|
||||
*/
|
||||
abstract protected function configure();
|
||||
|
||||
/**
|
||||
* Adapter initializer
|
||||
*/
|
||||
abstract protected function initialize();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
abstract public function isConnected();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
|
||||
{
|
||||
throw new NotImplementedException('Provider does not support this feature.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function maintainToken()
|
||||
{
|
||||
// Nothing needed for most providers
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
throw new NotImplementedException('Provider does not support this feature.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserContacts()
|
||||
{
|
||||
throw new NotImplementedException('Provider does not support this feature.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserPages()
|
||||
{
|
||||
throw new NotImplementedException('Provider does not support this feature.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserActivity($stream)
|
||||
{
|
||||
throw new NotImplementedException('Provider does not support this feature.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUserStatus($status)
|
||||
{
|
||||
throw new NotImplementedException('Provider does not support this feature.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setPageStatus($status, $pageId)
|
||||
{
|
||||
throw new NotImplementedException('Provider does not support this feature.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$this->clearStoredData();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
$tokenNames = [
|
||||
'access_token',
|
||||
'access_token_secret',
|
||||
'token_type',
|
||||
'refresh_token',
|
||||
'expires_in',
|
||||
'expires_at',
|
||||
];
|
||||
|
||||
$tokens = [];
|
||||
|
||||
foreach ($tokenNames as $name) {
|
||||
if ($this->getStoredData($name)) {
|
||||
$tokens[$name] = $this->getStoredData($name);
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setAccessToken($tokens = [])
|
||||
{
|
||||
$this->clearStoredData();
|
||||
|
||||
foreach ($tokens as $token => $value) {
|
||||
$this->storeData($token, $value);
|
||||
}
|
||||
|
||||
// Re-initialize token parameters.
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setHttpClient(HttpClientInterface $httpClient = null)
|
||||
{
|
||||
$this->httpClient = $httpClient ?: new HttpClient();
|
||||
|
||||
if ($this->config->exists('curl_options') && method_exists($this->httpClient, 'setCurlOptions')) {
|
||||
$this->httpClient->setCurlOptions($this->config->get('curl_options'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHttpClient()
|
||||
{
|
||||
return $this->httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setStorage(StorageInterface $storage = null)
|
||||
{
|
||||
$this->storage = $storage ?: new Session();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStorage()
|
||||
{
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setLogger(LoggerInterface $logger = null)
|
||||
{
|
||||
$this->logger = $logger ?: new Logger(
|
||||
$this->config->get('debug_mode'),
|
||||
$this->config->get('debug_file')
|
||||
);
|
||||
|
||||
if (method_exists($this->httpClient, 'setLogger')) {
|
||||
$this->httpClient->setLogger($this->logger);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLogger()
|
||||
{
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Adapter's API callback url
|
||||
*
|
||||
* @param string $callback
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function setCallback($callback)
|
||||
{
|
||||
if (!filter_var($callback, FILTER_VALIDATE_URL)) {
|
||||
throw new InvalidArgumentException('A valid callback url is required.');
|
||||
}
|
||||
|
||||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite Adapter's API endpoints
|
||||
*
|
||||
* @param array|Data\Collection $endpoints
|
||||
*/
|
||||
protected function setApiEndpoints($endpoints = null)
|
||||
{
|
||||
if (empty($endpoints)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$collection = is_array($endpoints) ? new Data\Collection($endpoints) : $endpoints;
|
||||
|
||||
$this->apiBaseUrl = $collection->get('api_base_url') ?: $this->apiBaseUrl;
|
||||
$this->authorizeUrl = $collection->get('authorize_url') ?: $this->authorizeUrl;
|
||||
$this->accessTokenUrl = $collection->get('access_token_url') ?: $this->accessTokenUrl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate signed API responses Http status code.
|
||||
*
|
||||
* Since the specifics of error responses is beyond the scope of RFC6749 and OAuth Core specifications,
|
||||
* Hybridauth will consider any HTTP status code that is different than '200 OK' as an ERROR.
|
||||
*
|
||||
* @param string $error String to pre append to message thrown in exception
|
||||
*
|
||||
* @throws HttpClientFailureException
|
||||
* @throws HttpRequestFailedException
|
||||
*/
|
||||
protected function validateApiResponse($error = '')
|
||||
{
|
||||
$error .= !empty($error) ? '. ' : '';
|
||||
|
||||
if ($this->httpClient->getResponseClientError()) {
|
||||
throw new HttpClientFailureException(
|
||||
$error . 'HTTP client error: ' . $this->httpClient->getResponseClientError() . '.'
|
||||
);
|
||||
}
|
||||
|
||||
// if validateApiResponseHttpCode is set to false, we by pass verification of http status code
|
||||
if (!$this->validateApiResponseHttpCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
$status = $this->httpClient->getResponseHttpCode();
|
||||
|
||||
if ($status < 200 || $status > 299) {
|
||||
throw new HttpRequestFailedException(
|
||||
$error . 'HTTP error ' . $this->httpClient->getResponseHttpCode() .
|
||||
'. Raw Provider API response: ' . $this->httpClient->getResponseBody() . '.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Adapter;
|
||||
|
||||
use Hybridauth\HttpClient\HttpClientInterface;
|
||||
use Hybridauth\Storage\StorageInterface;
|
||||
use Hybridauth\Logger\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Interface AdapterInterface
|
||||
*/
|
||||
interface AdapterInterface
|
||||
{
|
||||
/**
|
||||
* Initiate the appropriate protocol and process/automate the authentication or authorization flow.
|
||||
*
|
||||
* @return bool|null
|
||||
*/
|
||||
public function authenticate();
|
||||
|
||||
/**
|
||||
* Returns TRUE if the user is connected
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConnected();
|
||||
|
||||
/**
|
||||
* Clear all access token in storage
|
||||
*/
|
||||
public function disconnect();
|
||||
|
||||
/**
|
||||
* Retrieve the connected user profile
|
||||
*
|
||||
* @return \Hybridauth\User\Profile
|
||||
*/
|
||||
public function getUserProfile();
|
||||
|
||||
/**
|
||||
* Retrieve the connected user contacts list
|
||||
*
|
||||
* @return \Hybridauth\User\Contact[]
|
||||
*/
|
||||
public function getUserContacts();
|
||||
|
||||
/**
|
||||
* Retrieve the connected user pages|companies|groups list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getUserPages();
|
||||
|
||||
/**
|
||||
* Retrieve the user activity stream
|
||||
*
|
||||
* @param string $stream
|
||||
*
|
||||
* @return \Hybridauth\User\Activity[]
|
||||
*/
|
||||
public function getUserActivity($stream);
|
||||
|
||||
/**
|
||||
* Post a status on user wall|timeline|blog|website|etc.
|
||||
*
|
||||
* @param string|array $status
|
||||
*
|
||||
* @return mixed API response
|
||||
*/
|
||||
public function setUserStatus($status);
|
||||
|
||||
/**
|
||||
* Post a status on page|company|group wall.
|
||||
*
|
||||
* @param string|array $status
|
||||
* @param string $pageId
|
||||
*
|
||||
* @return mixed API response
|
||||
*/
|
||||
public function setPageStatus($status, $pageId);
|
||||
|
||||
/**
|
||||
* Send a signed request to provider API
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @param array $headers
|
||||
* @param bool $multipart
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false);
|
||||
|
||||
/**
|
||||
* Do whatever may be necessary to make sure tokens do not expire.
|
||||
* Intended to be be called frequently, e.g. via Cron.
|
||||
*/
|
||||
public function maintainToken();
|
||||
|
||||
/**
|
||||
* Return oauth access tokens.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken();
|
||||
|
||||
/**
|
||||
* Set oauth access tokens.
|
||||
*
|
||||
* @param array $tokens
|
||||
*/
|
||||
public function setAccessToken($tokens = []);
|
||||
|
||||
/**
|
||||
* Set http client instance.
|
||||
*
|
||||
* @param HttpClientInterface $httpClient
|
||||
*/
|
||||
public function setHttpClient(HttpClientInterface $httpClient = null);
|
||||
|
||||
/**
|
||||
* Return http client instance.
|
||||
*/
|
||||
public function getHttpClient();
|
||||
|
||||
/**
|
||||
* Set storage instance.
|
||||
*
|
||||
* @param StorageInterface $storage
|
||||
*/
|
||||
public function setStorage(StorageInterface $storage = null);
|
||||
|
||||
/**
|
||||
* Return storage instance.
|
||||
*/
|
||||
public function getStorage();
|
||||
|
||||
/**
|
||||
* Set Logger instance.
|
||||
*
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function setLogger(LoggerInterface $logger = null);
|
||||
|
||||
/**
|
||||
* Return logger instance.
|
||||
*/
|
||||
public function getLogger();
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Adapter;
|
||||
|
||||
/**
|
||||
* Trait DataStoreTrait
|
||||
*/
|
||||
trait DataStoreTrait
|
||||
{
|
||||
/**
|
||||
* Returns storage instance
|
||||
*
|
||||
* @return \Hybridauth\Storage\StorageInterface
|
||||
*/
|
||||
abstract public function getStorage();
|
||||
|
||||
/**
|
||||
* Store a piece of data in storage.
|
||||
*
|
||||
* This method is mainly used for OAuth tokens (access, secret, refresh, and whatnot), but it
|
||||
* can be also used by providers to store any other useful data (i.g., user_id, auth_nonce, etc.)
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
protected function storeData($name, $value = null)
|
||||
{
|
||||
// if empty, we simply delete the thing as we'd want to only store necessary data
|
||||
if (empty($value)) {
|
||||
$this->deleteStoredData($name);
|
||||
}
|
||||
|
||||
$this->getStorage()->set($this->providerId . '.' . $name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a piece of data from storage.
|
||||
*
|
||||
* This method is mainly used for OAuth tokens (access, secret, refresh, and whatnot), but it
|
||||
* can be also used by providers to retrieve from store any other useful data (i.g., user_id,
|
||||
* auth_nonce, etc.)
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getStoredData($name)
|
||||
{
|
||||
return $this->getStorage()->get($this->providerId . '.' . $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a stored piece of data.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
protected function deleteStoredData($name)
|
||||
{
|
||||
$this->getStorage()->delete($this->providerId . '.' . $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all stored data of the instantiated adapter
|
||||
*/
|
||||
protected function clearStoredData()
|
||||
{
|
||||
$this->getStorage()->deleteMatch($this->providerId . '.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,616 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Adapter;
|
||||
|
||||
use Hybridauth\Exception\Exception;
|
||||
use Hybridauth\Exception\InvalidApplicationCredentialsException;
|
||||
use Hybridauth\Exception\AuthorizationDeniedException;
|
||||
use Hybridauth\Exception\InvalidOauthTokenException;
|
||||
use Hybridauth\Exception\InvalidAccessTokenException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\HttpClient;
|
||||
use Hybridauth\Thirdparty\OAuth\OAuthConsumer;
|
||||
use Hybridauth\Thirdparty\OAuth\OAuthRequest;
|
||||
use Hybridauth\Thirdparty\OAuth\OAuthSignatureMethodHMACSHA1;
|
||||
use Hybridauth\Thirdparty\OAuth\OAuthUtil;
|
||||
|
||||
/**
|
||||
* This class can be used to simplify the authorization flow of OAuth 1 based service providers.
|
||||
*
|
||||
* Subclasses (i.e., providers adapters) can either use the already provided methods or override
|
||||
* them when necessary.
|
||||
*/
|
||||
abstract class OAuth1 extends AbstractAdapter implements AdapterInterface
|
||||
{
|
||||
/**
|
||||
* Base URL to provider API
|
||||
*
|
||||
* This var will be used to build urls when sending signed requests
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $apiBaseUrl = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $authorizeUrl = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $requestTokenUrl = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $accessTokenUrl = '';
|
||||
|
||||
/**
|
||||
* IPD API Documentation
|
||||
*
|
||||
* OPTIONAL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $apiDocumentation = '';
|
||||
|
||||
/**
|
||||
* OAuth Version
|
||||
*
|
||||
* '1.0' OAuth Core 1.0
|
||||
* '1.0a' OAuth Core 1.0 Revision A
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oauth1Version = '1.0a';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $consumerKey = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $consumerSecret = null;
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
protected $OAuthConsumer = null;
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
protected $sha1Method = null;
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
protected $consumerToken = null;
|
||||
|
||||
/**
|
||||
* Authorization Url Parameters
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $AuthorizeUrlParameters = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $requestTokenMethod = 'POST';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $requestTokenParameters = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $requestTokenHeaders = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tokenExchangeMethod = 'POST';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokenExchangeParameters = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokenExchangeHeaders = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $apiRequestParameters = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $apiRequestHeaders = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->consumerKey = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
|
||||
$this->consumerSecret = $this->config->filter('keys')->get('secret');
|
||||
|
||||
if (!$this->consumerKey || !$this->consumerSecret) {
|
||||
throw new InvalidApplicationCredentialsException(
|
||||
'Your application id is required in order to connect to ' . $this->providerId
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->config->exists('tokens')) {
|
||||
$this->setAccessToken($this->config->get('tokens'));
|
||||
}
|
||||
|
||||
$this->setCallback($this->config->get('callback'));
|
||||
$this->setApiEndpoints($this->config->get('endpoints'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
/**
|
||||
* Set up OAuth Signature and Consumer
|
||||
*
|
||||
* OAuth Core: All Token requests and Protected Resources requests MUST be signed
|
||||
* by the Consumer and verified by the Service Provider.
|
||||
*
|
||||
* The protocol defines three signature methods: HMAC-SHA1, RSA-SHA1, and PLAINTEXT..
|
||||
*
|
||||
* The Consumer declares a signature method in the oauth_signature_method parameter..
|
||||
*
|
||||
* http://oauth.net/core/1.0a/#signing_process
|
||||
*/
|
||||
$this->sha1Method = new OAuthSignatureMethodHMACSHA1();
|
||||
|
||||
$this->OAuthConsumer = new OAuthConsumer(
|
||||
$this->consumerKey,
|
||||
$this->consumerSecret
|
||||
);
|
||||
|
||||
if ($this->getStoredData('request_token')) {
|
||||
$this->consumerToken = new OAuthConsumer(
|
||||
$this->getStoredData('request_token'),
|
||||
$this->getStoredData('request_token_secret')
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->getStoredData('access_token')) {
|
||||
$this->consumerToken = new OAuthConsumer(
|
||||
$this->getStoredData('access_token'),
|
||||
$this->getStoredData('access_token_secret')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$this->logger->info(sprintf('%s::authenticate()', get_class($this)));
|
||||
|
||||
if ($this->isConnected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$this->getStoredData('request_token')) {
|
||||
// Start a new flow.
|
||||
$this->authenticateBegin();
|
||||
} elseif (empty($_GET['oauth_token']) && empty($_GET['denied'])) {
|
||||
// A previous authentication was not finished, and this request is not finishing it.
|
||||
$this->authenticateBegin();
|
||||
} else {
|
||||
// Finish a flow.
|
||||
$this->authenticateFinish();
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
$this->clearStoredData();
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
return (bool)$this->getStoredData('access_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the authorization protocol
|
||||
*
|
||||
* 1. Obtaining an Unauthorized Request Token
|
||||
* 2. Build Authorization URL for Authorization Request and redirect the user-agent to the
|
||||
* Authorization Server.
|
||||
*/
|
||||
protected function authenticateBegin()
|
||||
{
|
||||
$response = $this->requestAuthToken();
|
||||
|
||||
$this->validateAuthTokenRequest($response);
|
||||
|
||||
$authUrl = $this->getAuthorizeUrl();
|
||||
|
||||
$this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);
|
||||
|
||||
HttpClient\Util::redirect($authUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the authorization process
|
||||
*
|
||||
* @throws AuthorizationDeniedException
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
* @throws InvalidAccessTokenException
|
||||
* @throws InvalidOauthTokenException
|
||||
*/
|
||||
protected function authenticateFinish()
|
||||
{
|
||||
$this->logger->debug(
|
||||
sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
|
||||
[HttpClient\Util::getCurrentUrl(true)]
|
||||
);
|
||||
|
||||
$denied = filter_input(INPUT_GET, 'denied');
|
||||
$oauth_problem = filter_input(INPUT_GET, 'oauth_problem');
|
||||
$oauth_token = filter_input(INPUT_GET, 'oauth_token');
|
||||
$oauth_verifier = filter_input(INPUT_GET, 'oauth_verifier');
|
||||
|
||||
if ($denied) {
|
||||
throw new AuthorizationDeniedException(
|
||||
'User denied access request. Provider returned a denied token: ' . htmlentities($denied)
|
||||
);
|
||||
}
|
||||
|
||||
if ($oauth_problem) {
|
||||
throw new InvalidOauthTokenException(
|
||||
'Provider returned an error. oauth_problem: ' . htmlentities($oauth_problem)
|
||||
);
|
||||
}
|
||||
|
||||
if (!$oauth_token) {
|
||||
throw new InvalidOauthTokenException(
|
||||
'Expecting a non-null oauth_token to continue the authorization flow.'
|
||||
);
|
||||
}
|
||||
|
||||
$response = $this->exchangeAuthTokenForAccessToken($oauth_token, $oauth_verifier);
|
||||
|
||||
$this->validateAccessTokenExchange($response);
|
||||
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Authorization URL for Authorization Request
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthorizeUrl($parameters = [])
|
||||
{
|
||||
$this->AuthorizeUrlParameters = !empty($parameters)
|
||||
? $parameters
|
||||
: array_replace(
|
||||
(array)$this->AuthorizeUrlParameters,
|
||||
(array)$this->config->get('authorize_url_parameters')
|
||||
);
|
||||
|
||||
$this->AuthorizeUrlParameters['oauth_token'] = $this->getStoredData('request_token');
|
||||
|
||||
return $this->authorizeUrl . '?' . http_build_query($this->AuthorizeUrlParameters, '', '&');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unauthorized Request Token
|
||||
*
|
||||
* OAuth Core: The Consumer obtains an unauthorized Request Token by asking the Service Provider
|
||||
* to issue a Token. The Request Token's sole purpose is to receive User approval and can only
|
||||
* be used to obtain an Access Token.
|
||||
*
|
||||
* http://oauth.net/core/1.0/#auth_step1
|
||||
* 6.1.1. Consumer Obtains a Request Token
|
||||
*
|
||||
* @return string Raw Provider API response
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
*/
|
||||
protected function requestAuthToken()
|
||||
{
|
||||
/**
|
||||
* OAuth Core 1.0 Revision A: oauth_callback: An absolute URL to which the Service Provider will redirect
|
||||
* the User back when the Obtaining User Authorization step is completed.
|
||||
*
|
||||
* http://oauth.net/core/1.0a/#auth_step1
|
||||
*/
|
||||
if ('1.0a' == $this->oauth1Version) {
|
||||
$this->requestTokenParameters['oauth_callback'] = $this->callback;
|
||||
}
|
||||
|
||||
$response = $this->oauthRequest(
|
||||
$this->requestTokenUrl,
|
||||
$this->requestTokenMethod,
|
||||
$this->requestTokenParameters,
|
||||
$this->requestTokenHeaders
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Unauthorized Request Token Response
|
||||
*
|
||||
* OAuth Core: The Service Provider verifies the signature and Consumer Key. If successful,
|
||||
* it generates a Request Token and Token Secret and returns them to the Consumer in the HTTP
|
||||
* response body.
|
||||
*
|
||||
* http://oauth.net/core/1.0/#auth_step1
|
||||
* 6.1.2. Service Provider Issues an Unauthorized Request Token
|
||||
*
|
||||
* @param string $response
|
||||
*
|
||||
* @return \Hybridauth\Data\Collection
|
||||
* @throws InvalidOauthTokenException
|
||||
*/
|
||||
protected function validateAuthTokenRequest($response)
|
||||
{
|
||||
/**
|
||||
* The response contains the following parameters:
|
||||
*
|
||||
* - oauth_token The Request Token.
|
||||
* - oauth_token_secret The Token Secret.
|
||||
* - oauth_callback_confirmed MUST be present and set to true.
|
||||
*
|
||||
* http://oauth.net/core/1.0/#auth_step1
|
||||
* 6.1.2. Service Provider Issues an Unauthorized Request Token
|
||||
*
|
||||
* Example of a successful response:
|
||||
*
|
||||
* HTTP/1.1 200 OK
|
||||
* Content-Type: text/html; charset=utf-8
|
||||
* Cache-Control: no-store
|
||||
* Pragma: no-cache
|
||||
*
|
||||
* oauth_token=80359084-clg1DEtxQF3wstTcyUdHF3wsdHM&oauth_token_secret=OIF07hPmJB:P
|
||||
* 6qiHTi1znz6qiH3tTcyUdHnz6qiH3tTcyUdH3xW3wsDvV08e&example_parameter=example_value
|
||||
*
|
||||
* OAuthUtil::parse_parameters will attempt to decode the raw response into an array.
|
||||
*/
|
||||
$tokens = OAuthUtil::parse_parameters($response);
|
||||
|
||||
$collection = new Data\Collection($tokens);
|
||||
|
||||
if (!$collection->exists('oauth_token')) {
|
||||
throw new InvalidOauthTokenException(
|
||||
'Provider returned no oauth_token: ' . htmlentities($response)
|
||||
);
|
||||
}
|
||||
|
||||
$this->consumerToken = new OAuthConsumer(
|
||||
$tokens['oauth_token'],
|
||||
$tokens['oauth_token_secret']
|
||||
);
|
||||
|
||||
$this->storeData('request_token', $tokens['oauth_token']);
|
||||
$this->storeData('request_token_secret', $tokens['oauth_token_secret']);
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests an Access Token
|
||||
*
|
||||
* OAuth Core: The Request Token and Token Secret MUST be exchanged for an Access Token and Token Secret.
|
||||
*
|
||||
* http://oauth.net/core/1.0a/#auth_step3
|
||||
* 6.3.1. Consumer Requests an Access Token
|
||||
*
|
||||
* @param string $oauth_token
|
||||
* @param string $oauth_verifier
|
||||
*
|
||||
* @return string Raw Provider API response
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
*/
|
||||
protected function exchangeAuthTokenForAccessToken($oauth_token, $oauth_verifier = '')
|
||||
{
|
||||
$this->tokenExchangeParameters['oauth_token'] = $oauth_token;
|
||||
|
||||
/**
|
||||
* OAuth Core 1.0 Revision A: oauth_verifier: The verification code received from the Service Provider
|
||||
* in the "Service Provider Directs the User Back to the Consumer" step.
|
||||
*
|
||||
* http://oauth.net/core/1.0a/#auth_step3
|
||||
*/
|
||||
if ('1.0a' == $this->oauth1Version) {
|
||||
$this->tokenExchangeParameters['oauth_verifier'] = $oauth_verifier;
|
||||
}
|
||||
|
||||
$response = $this->oauthRequest(
|
||||
$this->accessTokenUrl,
|
||||
$this->tokenExchangeMethod,
|
||||
$this->tokenExchangeParameters,
|
||||
$this->tokenExchangeHeaders
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Access Token Response
|
||||
*
|
||||
* OAuth Core: If successful, the Service Provider generates an Access Token and Token Secret and returns
|
||||
* them in the HTTP response body.
|
||||
*
|
||||
* The Access Token and Token Secret are stored by the Consumer and used when signing Protected Resources requests.
|
||||
*
|
||||
* http://oauth.net/core/1.0a/#auth_step3
|
||||
* 6.3.2. Service Provider Grants an Access Token
|
||||
*
|
||||
* @param string $response
|
||||
*
|
||||
* @return \Hybridauth\Data\Collection
|
||||
* @throws InvalidAccessTokenException
|
||||
*/
|
||||
protected function validateAccessTokenExchange($response)
|
||||
{
|
||||
/**
|
||||
* The response contains the following parameters:
|
||||
*
|
||||
* - oauth_token The Access Token.
|
||||
* - oauth_token_secret The Token Secret.
|
||||
*
|
||||
* http://oauth.net/core/1.0/#auth_step3
|
||||
* 6.3.2. Service Provider Grants an Access Token
|
||||
*
|
||||
* Example of a successful response:
|
||||
*
|
||||
* HTTP/1.1 200 OK
|
||||
* Content-Type: text/html; charset=utf-8
|
||||
* Cache-Control: no-store
|
||||
* Pragma: no-cache
|
||||
*
|
||||
* oauth_token=sHeLU7Far428zj8PzlWR75&oauth_token_secret=fXb30rzoG&oauth_callback_confirmed=true
|
||||
*
|
||||
* OAuthUtil::parse_parameters will attempt to decode the raw response into an array.
|
||||
*/
|
||||
$tokens = OAuthUtil::parse_parameters($response);
|
||||
|
||||
$collection = new Data\Collection($tokens);
|
||||
|
||||
if (!$collection->exists('oauth_token')) {
|
||||
throw new InvalidAccessTokenException(
|
||||
'Provider returned no access_token: ' . htmlentities($response)
|
||||
);
|
||||
}
|
||||
|
||||
$this->consumerToken = new OAuthConsumer(
|
||||
$collection->get('oauth_token'),
|
||||
$collection->get('oauth_token_secret')
|
||||
);
|
||||
|
||||
$this->storeData('access_token', $collection->get('oauth_token'));
|
||||
$this->storeData('access_token_secret', $collection->get('oauth_token_secret'));
|
||||
|
||||
$this->deleteStoredData('request_token');
|
||||
$this->deleteStoredData('request_token_secret');
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a signed request to provider API
|
||||
*
|
||||
* Note: Since the specifics of error responses is beyond the scope of RFC6749 and OAuth specifications,
|
||||
* Hybridauth will consider any HTTP status code that is different than '200 OK' as an ERROR.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @param array $headers
|
||||
* @param bool $multipart
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
*/
|
||||
public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
|
||||
{
|
||||
// refresh tokens if needed
|
||||
$this->maintainToken();
|
||||
|
||||
if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
|
||||
$url = rtrim($this->apiBaseUrl, '/') . '/' . ltrim($url, '/');
|
||||
}
|
||||
|
||||
$parameters = array_replace($this->apiRequestParameters, (array)$parameters);
|
||||
|
||||
$headers = array_replace($this->apiRequestHeaders, (array)$headers);
|
||||
|
||||
$response = $this->oauthRequest($url, $method, $parameters, $headers, $multipart);
|
||||
|
||||
$response = (new Data\Parser())->parse($response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup and Send a Signed Oauth Request
|
||||
*
|
||||
* This method uses OAuth Library.
|
||||
*
|
||||
* @param string $uri
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @param array $headers
|
||||
* @param bool $multipart
|
||||
*
|
||||
* @return string Raw Provider API response
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
*/
|
||||
protected function oauthRequest($uri, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
|
||||
{
|
||||
$signing_parameters = $parameters;
|
||||
if ($multipart) {
|
||||
$signing_parameters = [];
|
||||
}
|
||||
|
||||
$request = OAuthRequest::from_consumer_and_token(
|
||||
$this->OAuthConsumer,
|
||||
$this->consumerToken,
|
||||
$method,
|
||||
$uri,
|
||||
$signing_parameters
|
||||
);
|
||||
|
||||
$request->sign_request(
|
||||
$this->sha1Method,
|
||||
$this->OAuthConsumer,
|
||||
$this->consumerToken
|
||||
);
|
||||
|
||||
$uri = $request->get_normalized_http_url();
|
||||
$headers = array_replace($request->to_header(), (array)$headers);
|
||||
|
||||
$response = $this->httpClient->request(
|
||||
$uri,
|
||||
$method,
|
||||
$parameters,
|
||||
$headers,
|
||||
$multipart
|
||||
);
|
||||
|
||||
$this->validateApiResponse('Signed API request to ' . $uri . ' has returned an error');
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,739 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Adapter;
|
||||
|
||||
use Hybridauth\Exception\Exception;
|
||||
use Hybridauth\Exception\InvalidApplicationCredentialsException;
|
||||
use Hybridauth\Exception\InvalidAuthorizationStateException;
|
||||
use Hybridauth\Exception\InvalidAuthorizationCodeException;
|
||||
use Hybridauth\Exception\AuthorizationDeniedException;
|
||||
use Hybridauth\Exception\InvalidAccessTokenException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\HttpClient;
|
||||
|
||||
/**
|
||||
* This class can be used to simplify the authorization flow of OAuth 2 based service providers.
|
||||
*
|
||||
* Subclasses (i.e., providers adapters) can either use the already provided methods or override
|
||||
* them when necessary.
|
||||
*/
|
||||
abstract class OAuth2 extends AbstractAdapter implements AdapterInterface
|
||||
{
|
||||
/**
|
||||
* Client Identifier
|
||||
*
|
||||
* RFC6749: client_id REQUIRED. The client identifier issued to the client during
|
||||
* the registration process described by Section 2.2.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-2.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $clientId = '';
|
||||
|
||||
/**
|
||||
* Client Secret
|
||||
*
|
||||
* RFC6749: client_secret REQUIRED. The client secret. The client MAY omit the
|
||||
* parameter if the client secret is an empty string.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-2.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $clientSecret = '';
|
||||
|
||||
/**
|
||||
* Access Token Scope
|
||||
*
|
||||
* RFC6749: The authorization and token endpoints allow the client to specify the
|
||||
* scope of the access request using the "scope" request parameter.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-3.3
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $scope = '';
|
||||
|
||||
/**
|
||||
* Base URL to provider API
|
||||
*
|
||||
* This var will be used to build urls when sending signed requests
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $apiBaseUrl = '';
|
||||
|
||||
/**
|
||||
* Authorization Endpoint
|
||||
*
|
||||
* RFC6749: The authorization endpoint is used to interact with the resource
|
||||
* owner and obtain an authorization grant.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-3.1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $authorizeUrl = '';
|
||||
|
||||
/**
|
||||
* Access Token Endpoint
|
||||
*
|
||||
* RFC6749: The token endpoint is used by the client to obtain an access token by
|
||||
* presenting its authorization grant or refresh token.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-3.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $accessTokenUrl = '';
|
||||
|
||||
/**
|
||||
* TokenInfo endpoint
|
||||
*
|
||||
* Access token validation. OPTIONAL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $accessTokenInfoUrl = '';
|
||||
|
||||
/**
|
||||
* IPD API Documentation
|
||||
*
|
||||
* OPTIONAL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $apiDocumentation = '';
|
||||
|
||||
/**
|
||||
* Redirection Endpoint or Callback
|
||||
*
|
||||
* RFC6749: After completing its interaction with the resource owner, the
|
||||
* authorization server directs the resource owner's user-agent back to
|
||||
* the client.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-3.1.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $callback = '';
|
||||
|
||||
/**
|
||||
* Authorization Url Parameters
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $AuthorizeUrlParameters = [];
|
||||
|
||||
|
||||
/**
|
||||
* Authorization Url Parameter encoding type
|
||||
* @see https://www.php.net/manual/de/function.http-build-query.php
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $AuthorizeUrlParametersEncType = PHP_QUERY_RFC1738;
|
||||
|
||||
/**
|
||||
* Authorization Request State
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $supportRequestState = true;
|
||||
|
||||
/**
|
||||
* Access Token name
|
||||
*
|
||||
* While most providers will use 'access_token' as name for the Access Token attribute, other do not.
|
||||
* On the latter case, this should be set by sub classes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $accessTokenName = 'access_token';
|
||||
|
||||
/**
|
||||
* Authorization Request HTTP method.
|
||||
*
|
||||
* @see exchangeCodeForAccessToken()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tokenExchangeMethod = 'POST';
|
||||
|
||||
/**
|
||||
* Authorization Request URL parameters.
|
||||
*
|
||||
* Sub classes may change add any additional parameter when necessary.
|
||||
*
|
||||
* @see exchangeCodeForAccessToken()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $tokenExchangeParameters = [];
|
||||
|
||||
/**
|
||||
* Authorization Request HTTP headers.
|
||||
*
|
||||
* Sub classes may add any additional header when necessary.
|
||||
*
|
||||
* @see exchangeCodeForAccessToken()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $tokenExchangeHeaders = [];
|
||||
|
||||
/**
|
||||
* Refresh Token Request HTTP method.
|
||||
*
|
||||
* @see refreshAccessToken()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tokenRefreshMethod = 'POST';
|
||||
|
||||
/**
|
||||
* Refresh Token Request URL parameters.
|
||||
*
|
||||
* Sub classes may change add any additional parameter when necessary.
|
||||
*
|
||||
* @see refreshAccessToken()
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
protected $tokenRefreshParameters = null;
|
||||
|
||||
/**
|
||||
* Refresh Token Request HTTP headers.
|
||||
*
|
||||
* Sub classes may add any additional header when necessary.
|
||||
*
|
||||
* @see refreshAccessToken()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $tokenRefreshHeaders = [];
|
||||
|
||||
/**
|
||||
* Authorization Request URL parameters.
|
||||
*
|
||||
* Sub classes may change add any additional parameter when necessary.
|
||||
*
|
||||
* @see apiRequest()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $apiRequestParameters = [];
|
||||
|
||||
/**
|
||||
* Authorization Request HTTP headers.
|
||||
*
|
||||
* Sub classes may add any additional header when necessary.
|
||||
*
|
||||
* @see apiRequest()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $apiRequestHeaders = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->clientId = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
|
||||
$this->clientSecret = $this->config->filter('keys')->get('secret');
|
||||
|
||||
if (!$this->clientId || !$this->clientSecret) {
|
||||
throw new InvalidApplicationCredentialsException(
|
||||
'Your application id is required in order to connect to ' . $this->providerId
|
||||
);
|
||||
}
|
||||
|
||||
$this->scope = $this->config->exists('scope') ? $this->config->get('scope') : $this->scope;
|
||||
|
||||
if ($this->config->exists('tokens')) {
|
||||
$this->setAccessToken($this->config->get('tokens'));
|
||||
}
|
||||
|
||||
$this->setCallback($this->config->get('callback'));
|
||||
$this->setApiEndpoints($this->config->get('endpoints'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
$this->AuthorizeUrlParameters = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->clientId,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => $this->scope,
|
||||
];
|
||||
|
||||
$this->tokenExchangeParameters = [
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
'grant_type' => 'authorization_code',
|
||||
'redirect_uri' => $this->callback
|
||||
];
|
||||
|
||||
$refreshToken = $this->getStoredData('refresh_token');
|
||||
if (!empty($refreshToken)) {
|
||||
$this->tokenRefreshParameters = [
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken,
|
||||
];
|
||||
}
|
||||
|
||||
$this->apiRequestHeaders = [
|
||||
'Authorization' => 'Bearer ' . $this->getStoredData('access_token')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$this->logger->info(sprintf('%s::authenticate()', get_class($this)));
|
||||
|
||||
if ($this->isConnected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->authenticateCheckError();
|
||||
|
||||
$code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
|
||||
|
||||
if (empty($code)) {
|
||||
$this->authenticateBegin();
|
||||
} else {
|
||||
$this->authenticateFinish();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->clearStoredData();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
if ((bool)$this->getStoredData('access_token')) {
|
||||
return (!$this->hasAccessTokenExpired() || $this->isRefreshTokenAvailable());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we can use a refresh token, then an expired token does not stop us being connected.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRefreshTokenAvailable()
|
||||
{
|
||||
return is_array($this->tokenRefreshParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorization Request Error Response
|
||||
*
|
||||
* RFC6749: If the request fails due to a missing, invalid, or mismatching
|
||||
* redirection URI, or if the client identifier is missing or invalid,
|
||||
* the authorization server SHOULD inform the resource owner of the error.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*
|
||||
* @throws \Hybridauth\Exception\InvalidAuthorizationCodeException
|
||||
* @throws \Hybridauth\Exception\AuthorizationDeniedException
|
||||
*/
|
||||
protected function authenticateCheckError()
|
||||
{
|
||||
$error = filter_input(INPUT_GET, 'error', FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
|
||||
if (!empty($error)) {
|
||||
$error_description = filter_input(INPUT_GET, 'error_description', FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
$error_uri = filter_input(INPUT_GET, 'error_uri', FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
|
||||
$collated_error = sprintf('Provider returned an error: %s %s %s', $error, $error_description, $error_uri);
|
||||
|
||||
if ($error == 'access_denied') {
|
||||
throw new AuthorizationDeniedException($collated_error);
|
||||
}
|
||||
|
||||
throw new InvalidAuthorizationCodeException($collated_error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the authorization protocol
|
||||
*
|
||||
* Build Authorization URL for Authorization Request and redirect the user-agent to the
|
||||
* Authorization Server.
|
||||
*/
|
||||
protected function authenticateBegin()
|
||||
{
|
||||
$authUrl = $this->getAuthorizeUrl();
|
||||
|
||||
$this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);
|
||||
|
||||
HttpClient\Util::redirect($authUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the authorization process
|
||||
*
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
* @throws InvalidAccessTokenException
|
||||
* @throws InvalidAuthorizationStateException
|
||||
*/
|
||||
protected function authenticateFinish()
|
||||
{
|
||||
$this->logger->debug(
|
||||
sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
|
||||
[HttpClient\Util::getCurrentUrl(true)]
|
||||
);
|
||||
|
||||
$state = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'state');
|
||||
$code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
|
||||
|
||||
/**
|
||||
* Authorization Request State
|
||||
*
|
||||
* RFC6749: state : RECOMMENDED. An opaque value used by the client to maintain
|
||||
* state between the request and callback. The authorization server includes
|
||||
* this value when redirecting the user-agent back to the client.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
*/
|
||||
if ($this->supportRequestState
|
||||
&& $this->getStoredData('authorization_state') != $state
|
||||
) {
|
||||
throw new InvalidAuthorizationStateException(
|
||||
'The authorization state [state=' . substr(htmlentities($state), 0, 100) . '] '
|
||||
. 'of this page is either invalid or has already been consumed.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorization Request Code
|
||||
*
|
||||
* RFC6749: If the resource owner grants the access request, the authorization
|
||||
* server issues an authorization code and delivers it to the client:
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-4.1.2
|
||||
*/
|
||||
$response = $this->exchangeCodeForAccessToken($code);
|
||||
|
||||
$this->validateAccessTokenExchange($response);
|
||||
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Authorization URL for Authorization Request
|
||||
*
|
||||
* RFC6749: The client constructs the request URI by adding the following
|
||||
* $parameters to the query component of the authorization endpoint URI:
|
||||
*
|
||||
* - response_type REQUIRED. Value MUST be set to "code".
|
||||
* - client_id REQUIRED.
|
||||
* - redirect_uri OPTIONAL.
|
||||
* - scope OPTIONAL.
|
||||
* - state RECOMMENDED.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
*
|
||||
* Sub classes may redefine this method when necessary.
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return string Authorization URL
|
||||
*/
|
||||
protected function getAuthorizeUrl($parameters = [])
|
||||
{
|
||||
$this->AuthorizeUrlParameters = !empty($parameters)
|
||||
? $parameters
|
||||
: array_replace(
|
||||
(array)$this->AuthorizeUrlParameters,
|
||||
(array)$this->config->get('authorize_url_parameters')
|
||||
);
|
||||
|
||||
if ($this->supportRequestState) {
|
||||
if (!isset($this->AuthorizeUrlParameters['state'])) {
|
||||
$this->AuthorizeUrlParameters['state'] = 'HA-' . str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
|
||||
}
|
||||
|
||||
$this->storeData('authorization_state', $this->AuthorizeUrlParameters['state']);
|
||||
}
|
||||
|
||||
$queryParams = http_build_query($this->AuthorizeUrlParameters, '', '&', $this->AuthorizeUrlParametersEncType);
|
||||
return $this->authorizeUrl . '?' . $queryParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access Token Request
|
||||
*
|
||||
* This method will exchange the received $code in loginFinish() with an Access Token.
|
||||
*
|
||||
* RFC6749: The client makes a request to the token endpoint by sending the
|
||||
* following parameters using the "application/x-www-form-urlencoded"
|
||||
* with a character encoding of UTF-8 in the HTTP request entity-body:
|
||||
*
|
||||
* - grant_type REQUIRED. Value MUST be set to "authorization_code".
|
||||
* - code REQUIRED. The authorization code received from the authorization server.
|
||||
* - redirect_uri REQUIRED.
|
||||
* - client_id REQUIRED.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return string Raw Provider API response
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
*/
|
||||
protected function exchangeCodeForAccessToken($code)
|
||||
{
|
||||
$this->tokenExchangeParameters['code'] = $code;
|
||||
|
||||
$response = $this->httpClient->request(
|
||||
$this->accessTokenUrl,
|
||||
$this->tokenExchangeMethod,
|
||||
$this->tokenExchangeParameters,
|
||||
$this->tokenExchangeHeaders
|
||||
);
|
||||
|
||||
$this->validateApiResponse('Unable to exchange code for API access token');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Access Token Response
|
||||
*
|
||||
* RFC6749: If the access token request is valid and authorized, the
|
||||
* authorization server issues an access token and optional refresh token.
|
||||
* If the request client authentication failed or is invalid, the authorization
|
||||
* server returns an error response as described in Section 5.2.
|
||||
*
|
||||
* Example of a successful response:
|
||||
*
|
||||
* HTTP/1.1 200 OK
|
||||
* Content-Type: application/json;charset=UTF-8
|
||||
* Cache-Control: no-store
|
||||
* Pragma: no-cache
|
||||
*
|
||||
* {
|
||||
* "access_token":"2YotnFZFEjr1zCsicMWpAA",
|
||||
* "token_type":"example",
|
||||
* "expires_in":3600,
|
||||
* "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
|
||||
* "example_parameter":"example_value"
|
||||
* }
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-4.1.4
|
||||
*
|
||||
* This method uses Data_Parser to attempt to decodes the raw $response (usually JSON)
|
||||
* into a data collection.
|
||||
*
|
||||
* @param string $response
|
||||
*
|
||||
* @return \Hybridauth\Data\Collection
|
||||
* @throws InvalidAccessTokenException
|
||||
*/
|
||||
protected function validateAccessTokenExchange($response)
|
||||
{
|
||||
$data = (new Data\Parser())->parse($response);
|
||||
|
||||
$collection = new Data\Collection($data);
|
||||
|
||||
if (!$collection->exists('access_token')) {
|
||||
throw new InvalidAccessTokenException(
|
||||
'Provider returned no access_token: ' . htmlentities($response)
|
||||
);
|
||||
}
|
||||
|
||||
$this->storeData('access_token', $collection->get('access_token'));
|
||||
$this->storeData('token_type', $collection->get('token_type'));
|
||||
|
||||
if ($collection->get('refresh_token')) {
|
||||
$this->storeData('refresh_token', $collection->get('refresh_token'));
|
||||
}
|
||||
|
||||
// calculate when the access token expire
|
||||
if ($collection->exists('expires_in')) {
|
||||
$expires_at = time() + (int)$collection->get('expires_in');
|
||||
|
||||
$this->storeData('expires_in', $collection->get('expires_in'));
|
||||
$this->storeData('expires_at', $expires_at);
|
||||
}
|
||||
|
||||
$this->deleteStoredData('authorization_state');
|
||||
|
||||
$this->initialize();
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshing an Access Token
|
||||
*
|
||||
* RFC6749: If the authorization server issued a refresh token to the
|
||||
* client, the client makes a refresh request to the token endpoint by
|
||||
* adding the following parameters ... in the HTTP request entity-body:
|
||||
*
|
||||
* - grant_type REQUIRED. Value MUST be set to "refresh_token".
|
||||
* - refresh_token REQUIRED. The refresh token issued to the client.
|
||||
* - scope OPTIONAL.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-6
|
||||
*
|
||||
* This method is similar to exchangeCodeForAccessToken(). The only
|
||||
* difference is here we exchange refresh_token for a new access_token.
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return string|null Raw Provider API response, or null if we cannot refresh
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
* @throws InvalidAccessTokenException
|
||||
*/
|
||||
public function refreshAccessToken($parameters = [])
|
||||
{
|
||||
$this->tokenRefreshParameters = !empty($parameters)
|
||||
? $parameters
|
||||
: $this->tokenRefreshParameters;
|
||||
|
||||
if (!$this->isRefreshTokenAvailable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$response = $this->httpClient->request(
|
||||
$this->accessTokenUrl,
|
||||
$this->tokenRefreshMethod,
|
||||
$this->tokenRefreshParameters,
|
||||
$this->tokenRefreshHeaders
|
||||
);
|
||||
|
||||
$this->validateApiResponse('Unable to refresh the access token');
|
||||
|
||||
$this->validateRefreshAccessToken($response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether access token has expired
|
||||
*
|
||||
* @param int|null $time
|
||||
* @return bool|null
|
||||
*/
|
||||
public function hasAccessTokenExpired($time = null)
|
||||
{
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
}
|
||||
|
||||
$expires_at = $this->getStoredData('expires_at');
|
||||
if (!$expires_at) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expires_at <= $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Refresh Access Token Request
|
||||
*
|
||||
* RFC6749: If valid and authorized, the authorization server issues an
|
||||
* access token as described in Section 5.1. If the request failed
|
||||
* verification or is invalid, the authorization server returns an error
|
||||
* response as described in Section 5.2.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-6
|
||||
* http://tools.ietf.org/html/rfc6749#section-5.1
|
||||
* http://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*
|
||||
* This method simply use validateAccessTokenExchange(), however sub
|
||||
* classes may redefine it when necessary.
|
||||
*
|
||||
* @param $response
|
||||
*
|
||||
* @return \Hybridauth\Data\Collection
|
||||
* @throws InvalidAccessTokenException
|
||||
*/
|
||||
protected function validateRefreshAccessToken($response)
|
||||
{
|
||||
return $this->validateAccessTokenExchange($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a signed request to provider API
|
||||
*
|
||||
* RFC6749: Accessing Protected Resources: The client accesses protected
|
||||
* resources by presenting the access token to the resource server. The
|
||||
* resource server MUST validate the access token and ensure that it has
|
||||
* not expired and that its scope covers the requested resource.
|
||||
*
|
||||
* Note: Since the specifics of error responses is beyond the scope of
|
||||
* RFC6749 and OAuth specifications, Hybridauth will consider any HTTP
|
||||
* status code that is different than '200 OK' as an ERROR.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6749#section-7
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @param array $headers
|
||||
* @param bool $multipart
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
* @throws InvalidAccessTokenException
|
||||
*/
|
||||
public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
|
||||
{
|
||||
// refresh tokens if needed
|
||||
$this->maintainToken();
|
||||
if ($this->hasAccessTokenExpired() === true) {
|
||||
$this->refreshAccessToken();
|
||||
}
|
||||
|
||||
if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
|
||||
$url = rtrim($this->apiBaseUrl, '/') . '/' . ltrim($url, '/');
|
||||
}
|
||||
|
||||
$parameters = array_replace($this->apiRequestParameters, (array)$parameters);
|
||||
$headers = array_replace($this->apiRequestHeaders, (array)$headers);
|
||||
|
||||
$response = $this->httpClient->request(
|
||||
$url,
|
||||
$method, // HTTP Request Method. Defaults to GET.
|
||||
$parameters, // Request Parameters
|
||||
$headers, // Request Headers
|
||||
$multipart // Is request multipart
|
||||
);
|
||||
|
||||
$this->validateApiResponse('Signed API request to ' . $url . ' has returned an error');
|
||||
|
||||
$response = (new Data\Parser())->parse($response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Adapter;
|
||||
|
||||
use Hybridauth\Exception\InvalidOpenidIdentifierException;
|
||||
use Hybridauth\Exception\AuthorizationDeniedException;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\HttpClient;
|
||||
use Hybridauth\User;
|
||||
use Hybridauth\Thirdparty\OpenID\LightOpenID;
|
||||
|
||||
/**
|
||||
* This class can be used to simplify the authentication flow of OpenID based service providers.
|
||||
*
|
||||
* Subclasses (i.e., providers adapters) can either use the already provided methods or override
|
||||
* them when necessary.
|
||||
*/
|
||||
abstract class OpenID extends AbstractAdapter implements AdapterInterface
|
||||
{
|
||||
/**
|
||||
* LightOpenID instance
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $openIdClient = null;
|
||||
|
||||
/**
|
||||
* Openid provider identifier
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $openidIdentifier = '';
|
||||
|
||||
/**
|
||||
* IPD API Documentation
|
||||
*
|
||||
* OPTIONAL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $apiDocumentation = '';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
if ($this->config->exists('openid_identifier')) {
|
||||
$this->openidIdentifier = $this->config->get('openid_identifier');
|
||||
}
|
||||
|
||||
if (empty($this->openidIdentifier)) {
|
||||
throw new InvalidOpenidIdentifierException('OpenID adapter requires an openid_identifier.', 4);
|
||||
}
|
||||
|
||||
$this->setCallback($this->config->get('callback'));
|
||||
$this->setApiEndpoints($this->config->get('endpoints'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
$hostPort = parse_url($this->callback, PHP_URL_PORT);
|
||||
$hostUrl = parse_url($this->callback, PHP_URL_HOST);
|
||||
|
||||
if ($hostPort) {
|
||||
$hostUrl .= ':' . $hostPort;
|
||||
}
|
||||
|
||||
// @fixme: add proxy
|
||||
$this->openIdClient = new LightOpenID($hostUrl, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$this->logger->info(sprintf('%s::authenticate()', get_class($this)));
|
||||
|
||||
if ($this->isConnected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (empty($_REQUEST['openid_mode'])) {
|
||||
$this->authenticateBegin();
|
||||
} else {
|
||||
return $this->authenticateFinish();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
return (bool)$this->storage->get($this->providerId . '.user');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$this->storage->delete($this->providerId . '.user');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the authorization protocol
|
||||
*
|
||||
* Include and instantiate LightOpenID
|
||||
*/
|
||||
protected function authenticateBegin()
|
||||
{
|
||||
$this->openIdClient->identity = $this->openidIdentifier;
|
||||
$this->openIdClient->returnUrl = $this->callback;
|
||||
$this->openIdClient->required = [
|
||||
'namePerson/first',
|
||||
'namePerson/last',
|
||||
'namePerson/friendly',
|
||||
'namePerson',
|
||||
'contact/email',
|
||||
'birthDate',
|
||||
'birthDate/birthDay',
|
||||
'birthDate/birthMonth',
|
||||
'birthDate/birthYear',
|
||||
'person/gender',
|
||||
'pref/language',
|
||||
'contact/postalCode/home',
|
||||
'contact/city/home',
|
||||
'contact/country/home',
|
||||
|
||||
'media/image/default',
|
||||
];
|
||||
|
||||
$authUrl = $this->openIdClient->authUrl();
|
||||
|
||||
$this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);
|
||||
|
||||
HttpClient\Util::redirect($authUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the authorization process.
|
||||
*
|
||||
* @throws AuthorizationDeniedException
|
||||
* @throws UnexpectedApiResponseException
|
||||
*/
|
||||
protected function authenticateFinish()
|
||||
{
|
||||
$this->logger->debug(
|
||||
sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
|
||||
[HttpClient\Util::getCurrentUrl(true)]
|
||||
);
|
||||
|
||||
if ($this->openIdClient->mode == 'cancel') {
|
||||
throw new AuthorizationDeniedException('User has cancelled the authentication.');
|
||||
}
|
||||
|
||||
if (!$this->openIdClient->validate()) {
|
||||
throw new UnexpectedApiResponseException('Invalid response received.');
|
||||
}
|
||||
|
||||
$openidAttributes = $this->openIdClient->getAttributes();
|
||||
|
||||
if (!$this->openIdClient->identity) {
|
||||
throw new UnexpectedApiResponseException('Provider returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = $this->fetchUserProfile($openidAttributes);
|
||||
|
||||
/* with openid providers we only get user profiles once, so we store it */
|
||||
$this->storage->set($this->providerId . '.user', $userProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch user profile from received openid attributes
|
||||
*
|
||||
* @param array $openidAttributes
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function fetchUserProfile($openidAttributes)
|
||||
{
|
||||
$data = new Data\Collection($openidAttributes);
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $this->openIdClient->identity;
|
||||
|
||||
$userProfile->firstName = $data->get('namePerson/first');
|
||||
$userProfile->lastName = $data->get('namePerson/last');
|
||||
$userProfile->email = $data->get('contact/email');
|
||||
$userProfile->language = $data->get('pref/language');
|
||||
$userProfile->country = $data->get('contact/country/home');
|
||||
$userProfile->zip = $data->get('contact/postalCode/home');
|
||||
$userProfile->gender = $data->get('person/gender');
|
||||
$userProfile->photoURL = $data->get('media/image/default');
|
||||
$userProfile->birthDay = $data->get('birthDate/birthDay');
|
||||
$userProfile->birthMonth = $data->get('birthDate/birthMonth');
|
||||
$userProfile->birthYear = $data->get('birthDate/birthDate');
|
||||
|
||||
$userProfile = $this->fetchUserGender($userProfile, $data->get('person/gender'));
|
||||
|
||||
$userProfile = $this->fetchUserDisplayName($userProfile, $data);
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract users display names
|
||||
*
|
||||
* @param User\Profile $userProfile
|
||||
* @param Data\Collection $data
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function fetchUserDisplayName(User\Profile $userProfile, Data\Collection $data)
|
||||
{
|
||||
$userProfile->displayName = $data->get('namePerson');
|
||||
|
||||
$userProfile->displayName = $userProfile->displayName
|
||||
? $userProfile->displayName
|
||||
: $data->get('namePerson/friendly');
|
||||
|
||||
$userProfile->displayName = $userProfile->displayName
|
||||
? $userProfile->displayName
|
||||
: trim($userProfile->firstName . ' ' . $userProfile->lastName);
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract users gender
|
||||
*
|
||||
* @param User\Profile $userProfile
|
||||
* @param string $gender
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function fetchUserGender(User\Profile $userProfile, $gender)
|
||||
{
|
||||
$gender = strtolower($gender);
|
||||
|
||||
if ('f' == $gender) {
|
||||
$gender = 'female';
|
||||
}
|
||||
|
||||
if ('m' == $gender) {
|
||||
$gender = 'male';
|
||||
}
|
||||
|
||||
$userProfile->gender = $gender;
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenID only provide the user profile one. This method will attempt to retrieve the profile from storage.
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$userProfile = $this->storage->get($this->providerId . '.user');
|
||||
|
||||
if (!is_object($userProfile)) {
|
||||
throw new UnexpectedApiResponseException('Provider returned an unexpected response.');
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Data;
|
||||
|
||||
/**
|
||||
* A very basic Data collection.
|
||||
*/
|
||||
final class Collection
|
||||
{
|
||||
/**
|
||||
* Data collection
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $collection = null;
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
*/
|
||||
public function __construct($data = null)
|
||||
{
|
||||
$this->collection = new \stdClass();
|
||||
|
||||
if (is_object($data)) {
|
||||
$this->collection = $data;
|
||||
}
|
||||
|
||||
$this->collection = (object)$data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the whole collection as array
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return (array)$this->collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an item
|
||||
*
|
||||
* @param $property
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($property)
|
||||
{
|
||||
if ($this->exists($property)) {
|
||||
return $this->collection->$property;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or update an item
|
||||
*
|
||||
* @param $property
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set($property, $value)
|
||||
{
|
||||
if ($property) {
|
||||
$this->collection->$property = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* .. until I come with a better name..
|
||||
*
|
||||
* @param $property
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter($property)
|
||||
{
|
||||
if ($this->exists($property)) {
|
||||
$data = $this->get($property);
|
||||
|
||||
if (!is_a($data, 'Collection')) {
|
||||
$data = new Collection($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return new Collection([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an item within the collection
|
||||
*
|
||||
* @param $property
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($property)
|
||||
{
|
||||
return property_exists($this->collection, $property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds whether the collection is empty
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return !(bool)$this->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Count all items in collection
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all items properties names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function properties()
|
||||
{
|
||||
$properties = [];
|
||||
|
||||
foreach ($this->collection as $key => $value) {
|
||||
$properties[] = $key;
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all items values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function values()
|
||||
{
|
||||
$values = [];
|
||||
|
||||
foreach ($this->collection as $value) {
|
||||
$values[] = $value;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Data;
|
||||
|
||||
/**
|
||||
* Parser
|
||||
*
|
||||
* This class is used to parse plain text into objects. It's used by hybriauth adapters to converts
|
||||
* providers api responses to a more 'manageable' format.
|
||||
*/
|
||||
final class Parser
|
||||
{
|
||||
/**
|
||||
* Decodes a string into an object.
|
||||
*
|
||||
* This method will first attempt to parse data as a JSON string (since most providers use this format)
|
||||
* then XML and parse_str.
|
||||
*
|
||||
* @param string $raw
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function parse($raw = null)
|
||||
{
|
||||
$data = $this->parseJson($raw);
|
||||
|
||||
if (!$data) {
|
||||
$data = $this->parseXml($raw);
|
||||
|
||||
if (!$data) {
|
||||
$data = $this->parseQueryString($raw);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a JSON string
|
||||
*
|
||||
* @param $result
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function parseJson($result)
|
||||
{
|
||||
return json_decode($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a XML string
|
||||
*
|
||||
* @param $result
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function parseXml($result)
|
||||
{
|
||||
libxml_use_internal_errors(true);
|
||||
|
||||
$result = preg_replace('/([<\/])([a-z0-9-]+):/i', '$1', $result);
|
||||
$xml = simplexml_load_string($result);
|
||||
|
||||
libxml_use_internal_errors(false);
|
||||
|
||||
if (!$xml) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$arr = json_decode(json_encode((array)$xml), true);
|
||||
$arr = array($xml->getName() => $arr);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string into variables
|
||||
*
|
||||
* @param $result
|
||||
*
|
||||
* @return \StdClass
|
||||
*/
|
||||
public function parseQueryString($result)
|
||||
{
|
||||
parse_str($result, $output);
|
||||
|
||||
if (!is_array($output)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result = new \StdClass();
|
||||
|
||||
foreach ($output as $k => $v) {
|
||||
$result->$k = $v;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* needs to be improved
|
||||
*
|
||||
* @param $birthday
|
||||
* @param $seperator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parseBirthday($birthday, $seperator)
|
||||
{
|
||||
$birthday = date_parse($birthday);
|
||||
|
||||
return [$birthday['year'], $birthday['month'], $birthday['day']];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class AuthorizationDeniedException extends UnexpectedValueException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
* BadMethodCallException
|
||||
*
|
||||
* Exception thrown if a callback refers to an undefined method or if some arguments are missing.
|
||||
*/
|
||||
class BadMethodCallException extends RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
* Hybridauth Base Exception
|
||||
*/
|
||||
class Exception extends \Exception implements ExceptionInterface
|
||||
{
|
||||
/**
|
||||
* Shamelessly Borrowed from Slimframework
|
||||
*
|
||||
* @param $object
|
||||
*/
|
||||
public function debug($object)
|
||||
{
|
||||
$title = 'Hybridauth Exception';
|
||||
$code = $this->getCode();
|
||||
$message = $this->getMessage();
|
||||
$file = $this->getFile();
|
||||
$line = $this->getLine();
|
||||
$trace = $this->getTraceAsString();
|
||||
|
||||
$html = sprintf('<h1>%s</h1>', $title);
|
||||
$html .= '<p>Hybridauth has encountered the following error:</p>';
|
||||
$html .= '<h2>Details</h2>';
|
||||
|
||||
$html .= sprintf('<div><strong>Exception:</strong> %s</div>', get_class($this));
|
||||
|
||||
$html .= sprintf('<div><strong>Message:</strong> <font color="#cc0000">%s</font></div>', $message);
|
||||
|
||||
$html .= sprintf('<div><strong>File:</strong> %s</div>', $file);
|
||||
|
||||
$html .= sprintf('<div><strong>Line:</strong> %s</div>', $line);
|
||||
|
||||
$html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
|
||||
|
||||
$html .= '<h2>Trace</h2>';
|
||||
$html .= sprintf('<pre>%s</pre>', $trace);
|
||||
|
||||
if ($object) {
|
||||
$html .= '<h2>Debug</h2>';
|
||||
|
||||
$obj_dump = print_r($object, true);
|
||||
|
||||
// phpcs:ignore
|
||||
$html .= sprintf('<b>' . get_class($object) . '</b> extends <b>' . get_parent_class($object) . '</b><pre>%s</pre>', $obj_dump);
|
||||
}
|
||||
|
||||
$html .= '<h2>Session</h2>';
|
||||
|
||||
$session_dump = print_r($_SESSION, true);
|
||||
|
||||
$html .= sprintf('<pre>%s</pre>', $session_dump);
|
||||
|
||||
// phpcs:ignore
|
||||
echo sprintf("<html><head><title>%s</title><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{display:inline-block;width:75px;}</style></head><body>%s</body></html>", $title, $html);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
* Hybridauth Exceptions Interface
|
||||
*/
|
||||
interface ExceptionInterface
|
||||
{
|
||||
/*
|
||||
ExceptionInterface
|
||||
Exception extends \Exception implements ExceptionInterface
|
||||
| RuntimeException extends Exception
|
||||
| | UnexpectedValueException extends RuntimeException
|
||||
| | | AuthorizationDeniedException extends UnexpectedValueException
|
||||
| | | HttpClientFailureException extends UnexpectedValueException
|
||||
| | | HttpRequestFailedException extends UnexpectedValueException
|
||||
| | | InvalidAuthorizationCodeException extends UnexpectedValueException
|
||||
| | | InvalidAuthorizationStateException extends UnexpectedValueException
|
||||
| | | InvalidOauthTokenException extends UnexpectedValueException
|
||||
| | | InvalidAccessTokenException extends UnexpectedValueException
|
||||
| | | UnexpectedApiResponseException extends UnexpectedValueException
|
||||
| |
|
||||
| | BadMethodCallException extends RuntimeException
|
||||
| | | NotImplementedException extends BadMethodCallException
|
||||
| |
|
||||
| | InvalidArgumentException extends RuntimeException
|
||||
| | | InvalidApplicationCredentialsException extends InvalidArgumentException
|
||||
| | | InvalidOpenidIdentifierException extends InvalidArgumentException
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class HttpClientFailureException extends UnexpectedValueException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class HttpRequestFailedException extends UnexpectedValueException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class InvalidAccessTokenException extends InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class InvalidApplicationCredentialsException extends InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
* InvalidArgumentException
|
||||
*
|
||||
* Exception thrown if an argument is not of the expected type.
|
||||
*/
|
||||
class InvalidArgumentException extends RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class InvalidAuthorizationCodeException extends InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class InvalidAuthorizationStateException extends InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class InvalidOauthTokenException extends InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class InvalidOpenidIdentifierException extends InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class NotImplementedException extends BadMethodCallException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
* RuntimeException
|
||||
*
|
||||
* Exception thrown if an error which can only be found on runtime occurs.
|
||||
*/
|
||||
class RuntimeException extends Exception implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class UnexpectedApiResponseException extends UnexpectedValueException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Exception;
|
||||
|
||||
/**
|
||||
* UnexpectedValueException
|
||||
*
|
||||
* Exception thrown if a value does not match with a set of values. Typically this happens when a function calls
|
||||
* another function and expects the return value to be of a certain type or value not including arithmetic or
|
||||
* buffer related errors.
|
||||
*/
|
||||
class UnexpectedValueException extends RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\HttpClient;
|
||||
|
||||
/**
|
||||
* Hybridauth default Http client
|
||||
*/
|
||||
class Curl implements HttpClientInterface
|
||||
{
|
||||
/**
|
||||
* Default curl options
|
||||
*
|
||||
* These defaults options can be overwritten when sending requests.
|
||||
*
|
||||
* See setCurlOptions()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $curlOptions = [
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_CONNECTTIMEOUT => 30,
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_SSL_VERIFYHOST => false,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_MAXREDIRS => 5,
|
||||
CURLINFO_HEADER_OUT => true,
|
||||
CURLOPT_ENCODING => 'identity',
|
||||
// phpcs:ignore
|
||||
CURLOPT_USERAGENT => 'Hybridauth, PHP Social Authentication Library (https://github.com/hybridauth/hybridauth)',
|
||||
];
|
||||
|
||||
/**
|
||||
* Method request() arguments
|
||||
*
|
||||
* This is used for debugging.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $requestArguments = [];
|
||||
|
||||
/**
|
||||
* Default request headers
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $requestHeader = [
|
||||
'Accept' => '*/*',
|
||||
'Cache-Control' => 'max-age=0',
|
||||
'Connection' => 'keep-alive',
|
||||
'Expect' => '',
|
||||
'Pragma' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* Raw response returned by server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $responseBody = '';
|
||||
|
||||
/**
|
||||
* Headers returned in the response
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $responseHeader = [];
|
||||
|
||||
/**
|
||||
* Response HTTP status code
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $responseHttpCode = 0;
|
||||
|
||||
/**
|
||||
* Last curl error number
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $responseClientError = null;
|
||||
|
||||
/**
|
||||
* Information about the last transfer
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $responseClientInfo = [];
|
||||
|
||||
/**
|
||||
* Hybridauth logger instance
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function request($uri, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
|
||||
{
|
||||
$this->requestHeader = array_replace($this->requestHeader, (array)$headers);
|
||||
|
||||
$this->requestArguments = [
|
||||
'uri' => $uri,
|
||||
'method' => $method,
|
||||
'parameters' => $parameters,
|
||||
'headers' => $this->requestHeader,
|
||||
];
|
||||
|
||||
$curl = curl_init();
|
||||
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
case 'DELETE':
|
||||
unset($this->curlOptions[CURLOPT_POST]);
|
||||
unset($this->curlOptions[CURLOPT_POSTFIELDS]);
|
||||
|
||||
$uri = $uri . (strpos($uri, '?') ? '&' : '?') . http_build_query($parameters);
|
||||
if ($method === 'DELETE') {
|
||||
$this->curlOptions[CURLOPT_CUSTOMREQUEST] = 'DELETE';
|
||||
}
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'POST':
|
||||
case 'PATCH':
|
||||
$body_content = $multipart ? $parameters : http_build_query($parameters);
|
||||
if (isset($this->requestHeader['Content-Type'])
|
||||
&& $this->requestHeader['Content-Type'] == 'application/json'
|
||||
) {
|
||||
$body_content = json_encode($parameters);
|
||||
}
|
||||
|
||||
if ($method === 'POST') {
|
||||
$this->curlOptions[CURLOPT_POST] = true;
|
||||
} else {
|
||||
$this->curlOptions[CURLOPT_CUSTOMREQUEST] = $method;
|
||||
}
|
||||
$this->curlOptions[CURLOPT_POSTFIELDS] = $body_content;
|
||||
break;
|
||||
}
|
||||
|
||||
$this->curlOptions[CURLOPT_URL] = $uri;
|
||||
$this->curlOptions[CURLOPT_HTTPHEADER] = $this->prepareRequestHeaders();
|
||||
$this->curlOptions[CURLOPT_HEADERFUNCTION] = [$this, 'fetchResponseHeader'];
|
||||
|
||||
foreach ($this->curlOptions as $opt => $value) {
|
||||
curl_setopt($curl, $opt, $value);
|
||||
}
|
||||
|
||||
$response = curl_exec($curl);
|
||||
|
||||
$this->responseBody = $response;
|
||||
$this->responseHttpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
$this->responseClientError = curl_error($curl);
|
||||
$this->responseClientInfo = curl_getinfo($curl);
|
||||
|
||||
if ($this->logger) {
|
||||
// phpcs:ignore
|
||||
$this->logger->debug(sprintf('%s::request( %s, %s ), response:', get_class($this), $uri, $method), $this->getResponse());
|
||||
|
||||
if (false === $response) {
|
||||
// phpcs:ignore
|
||||
$this->logger->error(sprintf('%s::request( %s, %s ), error:', get_class($this), $uri, $method), [$this->responseClientError]);
|
||||
}
|
||||
}
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
return $this->responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response details
|
||||
*
|
||||
* @return array Map structure of details
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
$curlOptions = $this->curlOptions;
|
||||
|
||||
$curlOptions[CURLOPT_HEADERFUNCTION] = '*omitted';
|
||||
|
||||
return [
|
||||
'request' => $this->getRequestArguments(),
|
||||
'response' => [
|
||||
'code' => $this->getResponseHttpCode(),
|
||||
'headers' => $this->getResponseHeader(),
|
||||
'body' => $this->getResponseBody(),
|
||||
],
|
||||
'client' => [
|
||||
'error' => $this->getResponseClientError(),
|
||||
'info' => $this->getResponseClientInfo(),
|
||||
'opts' => $curlOptions,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset curl options
|
||||
*
|
||||
* @param array $curlOptions
|
||||
*/
|
||||
public function setCurlOptions($curlOptions)
|
||||
{
|
||||
foreach ($curlOptions as $opt => $value) {
|
||||
$this->curlOptions[$opt] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set logger instance
|
||||
*
|
||||
* @param object $logger
|
||||
*/
|
||||
public function setLogger($logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResponseBody()
|
||||
{
|
||||
return $this->responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResponseHeader()
|
||||
{
|
||||
return $this->responseHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResponseHttpCode()
|
||||
{
|
||||
return $this->responseHttpCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResponseClientError()
|
||||
{
|
||||
return $this->responseClientError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getResponseClientInfo()
|
||||
{
|
||||
return $this->responseClientInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns method request() arguments
|
||||
*
|
||||
* This is used for debugging.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRequestArguments()
|
||||
{
|
||||
return $this->requestArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch server response headers
|
||||
*
|
||||
* @param mixed $curl
|
||||
* @param string $header
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function fetchResponseHeader($curl, $header)
|
||||
{
|
||||
$pos = strpos($header, ':');
|
||||
|
||||
if (!empty($pos)) {
|
||||
$key = str_replace('-', '_', strtolower(substr($header, 0, $pos)));
|
||||
|
||||
$value = trim(substr($header, $pos + 2));
|
||||
|
||||
$this->responseHeader[$key] = $value;
|
||||
}
|
||||
|
||||
return strlen($header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert request headers to the expect curl format
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareRequestHeaders()
|
||||
{
|
||||
$headers = [];
|
||||
|
||||
foreach ($this->requestHeader as $header => $value) {
|
||||
$headers[] = trim($header) . ': ' . trim($value);
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\HttpClient;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Exception\ServerException;
|
||||
use GuzzleHttp\Exception\TransferException;
|
||||
|
||||
/**
|
||||
* Hybridauth Guzzle Http client
|
||||
*
|
||||
* Note: This is just a proof of concept. Feel free to improve it.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* <code>
|
||||
* $guzzle = new Hybridauth\HttpClient\Guzzle(new GuzzleHttp\Client(), [
|
||||
* 'verify' => '/path/to/your/certificate.crt',
|
||||
* 'headers' => ['User-Agent' => '..']
|
||||
* // 'proxy' => ...
|
||||
* ]);
|
||||
*
|
||||
* $adapter = new Hybridauth\Provider\Github($config, $guzzle);
|
||||
*
|
||||
* $adapter->authenticate();
|
||||
* </code>
|
||||
*/
|
||||
class Guzzle implements HttpClientInterface
|
||||
{
|
||||
/**
|
||||
* Method request() arguments
|
||||
*
|
||||
* This is used for debugging.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $requestArguments = [];
|
||||
|
||||
/**
|
||||
* Default request headers
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $requestHeader = [];
|
||||
|
||||
/**
|
||||
* Raw response returned by server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $responseBody = '';
|
||||
|
||||
/**
|
||||
* Headers returned in the response
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $responseHeader = [];
|
||||
|
||||
/**
|
||||
* Response HTTP status code
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $responseHttpCode = 0;
|
||||
|
||||
/**
|
||||
* Last curl error number
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $responseClientError = null;
|
||||
|
||||
/**
|
||||
* Information about the last transfer
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $responseClientInfo = [];
|
||||
|
||||
/**
|
||||
* Hybridauth logger instance
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
/**
|
||||
* GuzzleHttp client
|
||||
*
|
||||
* @var \GuzzleHttp\Client
|
||||
*/
|
||||
protected $client = null;
|
||||
|
||||
/**
|
||||
* ..
|
||||
* @param null $client
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($client = null, $config = [])
|
||||
{
|
||||
$this->client = $client ? $client : new Client($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function request($uri, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
|
||||
{
|
||||
$this->requestHeader = array_replace($this->requestHeader, (array)$headers);
|
||||
|
||||
$this->requestArguments = [
|
||||
'uri' => $uri,
|
||||
'method' => $method,
|
||||
'parameters' => $parameters,
|
||||
'headers' => $this->requestHeader,
|
||||
];
|
||||
|
||||
$response = null;
|
||||
|
||||
try {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
case 'DELETE':
|
||||
$response = $this->client->request($method, $uri, [
|
||||
'query' => $parameters,
|
||||
'headers' => $this->requestHeader,
|
||||
]);
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'POST':
|
||||
$body_type = $multipart ? 'multipart' : 'form_params';
|
||||
|
||||
if (isset($this->requestHeader['Content-Type'])
|
||||
&& $this->requestHeader['Content-Type'] === 'application/json'
|
||||
) {
|
||||
$body_type = 'json';
|
||||
}
|
||||
|
||||
$body_content = $parameters;
|
||||
if ($multipart) {
|
||||
$body_content = [];
|
||||
foreach ($parameters as $key => $val) {
|
||||
if ($val instanceof \CURLFile) {
|
||||
$val = fopen($val->getFilename(), 'r');
|
||||
}
|
||||
|
||||
$body_content[] = [
|
||||
'name' => $key,
|
||||
'contents' => $val,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->client->request($method, $uri, [
|
||||
$body_type => $body_content,
|
||||
'headers' => $this->requestHeader,
|
||||
]);
|
||||
break;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$response = $e->getResponse();
|
||||
|
||||
$this->responseClientError = $e->getMessage();
|
||||
}
|
||||
|
||||
if (!$this->responseClientError) {
|
||||
$this->responseBody = $response->getBody();
|
||||
$this->responseHttpCode = $response->getStatusCode();
|
||||
$this->responseHeader = $response->getHeaders();
|
||||
}
|
||||
|
||||
if ($this->logger) {
|
||||
// phpcs:ignore
|
||||
$this->logger->debug(sprintf('%s::request( %s, %s ), response:', get_class($this), $uri, $method), $this->getResponse());
|
||||
|
||||
if ($this->responseClientError) {
|
||||
// phpcs:ignore
|
||||
$this->logger->error(sprintf('%s::request( %s, %s ), error:', get_class($this), $uri, $method), [$this->responseClientError]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response details
|
||||
*
|
||||
* @return array Map structure of details
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return [
|
||||
'request' => $this->getRequestArguments(),
|
||||
'response' => [
|
||||
'code' => $this->getResponseHttpCode(),
|
||||
'headers' => $this->getResponseHeader(),
|
||||
'body' => $this->getResponseBody(),
|
||||
],
|
||||
'client' => [
|
||||
'error' => $this->getResponseClientError(),
|
||||
'info' => $this->getResponseClientInfo(),
|
||||
'opts' => null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set logger instance
|
||||
*
|
||||
* @param object $logger
|
||||
*/
|
||||
public function setLogger($logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResponseBody()
|
||||
{
|
||||
return $this->responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResponseHeader()
|
||||
{
|
||||
return $this->responseHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResponseHttpCode()
|
||||
{
|
||||
return $this->responseHttpCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResponseClientError()
|
||||
{
|
||||
return $this->responseClientError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getResponseClientInfo()
|
||||
{
|
||||
return $this->responseClientInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns method request() arguments
|
||||
*
|
||||
* This is used for debugging.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRequestArguments()
|
||||
{
|
||||
return $this->requestArguments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\HttpClient;
|
||||
|
||||
/**
|
||||
* Hybridauth Http clients interface
|
||||
*/
|
||||
interface HttpClientInterface
|
||||
{
|
||||
/**
|
||||
* Send request to the remote server
|
||||
*
|
||||
* Returns the result (Raw response from the server) on success, FALSE on failure
|
||||
*
|
||||
* @param string $uri
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @param array $headers
|
||||
* @param bool $multipart
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function request($uri, $method = 'GET', $parameters = [], $headers = [], $multipart = false);
|
||||
|
||||
/**
|
||||
* Returns raw response from the server on success, FALSE on failure
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResponseBody();
|
||||
|
||||
/**
|
||||
* Retriever the headers returned in the response
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getResponseHeader();
|
||||
|
||||
/**
|
||||
* Returns latest request HTTP status code
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getResponseHttpCode();
|
||||
|
||||
/**
|
||||
* Returns latest error encountered by the client
|
||||
* This can be either a code or error message
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResponseClientError();
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\HttpClient;
|
||||
|
||||
use Hybridauth\Data;
|
||||
|
||||
/**
|
||||
* HttpClient\Util home to a number of utility functions.
|
||||
*/
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* Redirect handler.
|
||||
*
|
||||
* @var callable|null
|
||||
*/
|
||||
protected static $redirectHandler;
|
||||
|
||||
/**
|
||||
* Exit handler.
|
||||
*
|
||||
* @var callable|null
|
||||
*/
|
||||
protected static $exitHandler;
|
||||
|
||||
/**
|
||||
* Redirect to a given URL.
|
||||
*
|
||||
* In case your application need to perform certain required actions before Hybridauth redirect users
|
||||
* to IDPs websites, the default behaviour can be altered in one of two ways:
|
||||
* If callable $redirectHandler is defined, it will be called instead.
|
||||
* If callable $exitHandler is defined, it will be called instead of exit().
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function redirect($url)
|
||||
{
|
||||
if (static::$redirectHandler) {
|
||||
return call_user_func(static::$redirectHandler, $url);
|
||||
}
|
||||
|
||||
header(sprintf('Location: %s', $url));
|
||||
|
||||
if (static::$exitHandler) {
|
||||
return call_user_func(static::$exitHandler);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect handler to which the regular redirect() will yield the action of redirecting users.
|
||||
*
|
||||
* @param callable $callback
|
||||
*/
|
||||
public static function setRedirectHandler($callback)
|
||||
{
|
||||
self::$redirectHandler = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit handler will be called instead of regular exit() when calling Util::redirect() method.
|
||||
*
|
||||
* @param callable $callback
|
||||
*/
|
||||
public static function setExitHandler($callback)
|
||||
{
|
||||
self::$exitHandler = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Current URL.
|
||||
*
|
||||
* @param bool $requestUri TRUE to use $_SERVER['REQUEST_URI'], FALSE for $_SERVER['PHP_SELF']
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getCurrentUrl($requestUri = false)
|
||||
{
|
||||
$collection = new Data\Collection($_SERVER);
|
||||
|
||||
$protocol = 'http://';
|
||||
|
||||
if (($collection->get('HTTPS') && $collection->get('HTTPS') !== 'off') ||
|
||||
$collection->get('HTTP_X_FORWARDED_PROTO') === 'https') {
|
||||
$protocol = 'https://';
|
||||
}
|
||||
|
||||
return $protocol .
|
||||
$collection->get('HTTP_HOST') .
|
||||
$collection->get($requestUri ? 'REQUEST_URI' : 'PHP_SELF');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth;
|
||||
|
||||
use Hybridauth\Exception\InvalidArgumentException;
|
||||
use Hybridauth\Exception\UnexpectedValueException;
|
||||
use Hybridauth\Storage\StorageInterface;
|
||||
use Hybridauth\Logger\LoggerInterface;
|
||||
use Hybridauth\Logger\Logger;
|
||||
use Hybridauth\HttpClient\HttpClientInterface;
|
||||
|
||||
/**
|
||||
* Hybridauth\Hybridauth
|
||||
*
|
||||
* For ease of use of multiple providers, Hybridauth implements the class Hybridauth\Hybridauth,
|
||||
* a sort of factory/façade which acts as an unified interface or entry point, and it expects a
|
||||
* configuration array containing the list of providers you want to use, their respective credentials
|
||||
* and authorized callback.
|
||||
*/
|
||||
class Hybridauth
|
||||
{
|
||||
/**
|
||||
* Hybridauth config.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Storage.
|
||||
*
|
||||
* @var StorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* HttpClient.
|
||||
*
|
||||
* @var HttpClientInterface
|
||||
*/
|
||||
protected $httpClient;
|
||||
|
||||
/**
|
||||
* Logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* @param array|string $config Array with configuration or Path to PHP file that will return array
|
||||
* @param HttpClientInterface $httpClient
|
||||
* @param StorageInterface $storage
|
||||
* @param LoggerInterface $logger
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(
|
||||
$config,
|
||||
HttpClientInterface $httpClient = null,
|
||||
StorageInterface $storage = null,
|
||||
LoggerInterface $logger = null
|
||||
) {
|
||||
if (is_string($config) && file_exists($config)) {
|
||||
$config = include $config;
|
||||
} elseif (!is_array($config)) {
|
||||
throw new InvalidArgumentException('Hybridauth config does not exist on the given path.');
|
||||
}
|
||||
|
||||
$this->config = $config + [
|
||||
'debug_mode' => Logger::NONE,
|
||||
'debug_file' => '',
|
||||
'curl_options' => null,
|
||||
'providers' => []
|
||||
];
|
||||
$this->storage = $storage;
|
||||
$this->logger = $logger;
|
||||
$this->httpClient = $httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the given provider and authentication or authorization protocol.
|
||||
*
|
||||
* If not authenticated yet, the user will be redirected to the provider's site for
|
||||
* authentication/authorisation, otherwise it will simply return an instance of
|
||||
* provider's adapter.
|
||||
*
|
||||
* @param string $name adapter's name (case insensitive)
|
||||
*
|
||||
* @return \Hybridauth\Adapter\AdapterInterface
|
||||
* @throws InvalidArgumentException
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public function authenticate($name)
|
||||
{
|
||||
$adapter = $this->getAdapter($name);
|
||||
|
||||
$adapter->authenticate();
|
||||
|
||||
return $adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of a provider's adapter by name
|
||||
*
|
||||
* @param string $name adapter's name (case insensitive)
|
||||
*
|
||||
* @return \Hybridauth\Adapter\AdapterInterface
|
||||
* @throws InvalidArgumentException
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public function getAdapter($name)
|
||||
{
|
||||
$config = $this->getProviderConfig($name);
|
||||
|
||||
$adapter = isset($config['adapter']) ? $config['adapter'] : sprintf('Hybridauth\\Provider\\%s', $name);
|
||||
|
||||
if (!class_exists($adapter)) {
|
||||
$adapter = null;
|
||||
$fs = new \FilesystemIterator(__DIR__ . '/Provider/');
|
||||
/** @var \SplFileInfo $file */
|
||||
foreach ($fs as $file) {
|
||||
if (!$file->isDir()) {
|
||||
$provider = strtok($file->getFilename(), '.');
|
||||
if ($name === mb_strtolower($provider)) {
|
||||
$adapter = sprintf('Hybridauth\\Provider\\%s', $provider);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($adapter === null) {
|
||||
throw new InvalidArgumentException('Unknown Provider.');
|
||||
}
|
||||
}
|
||||
|
||||
return new $adapter($config, $this->httpClient, $this->storage, $this->logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get provider config by name.
|
||||
*
|
||||
* @param string $name adapter's name (case insensitive)
|
||||
*
|
||||
* @throws UnexpectedValueException
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getProviderConfig($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
$providersConfig = array_change_key_case($this->config['providers'], CASE_LOWER);
|
||||
|
||||
if (!isset($providersConfig[$name])) {
|
||||
throw new InvalidArgumentException('Unknown Provider.');
|
||||
}
|
||||
|
||||
if (!$providersConfig[$name]['enabled']) {
|
||||
throw new UnexpectedValueException('Disabled Provider.');
|
||||
}
|
||||
|
||||
$config = $providersConfig[$name];
|
||||
$config += [
|
||||
'debug_mode' => $this->config['debug_mode'],
|
||||
'debug_file' => $this->config['debug_file'],
|
||||
];
|
||||
|
||||
if (!isset($config['callback']) && isset($this->config['callback'])) {
|
||||
$config['callback'] = $this->config['callback'];
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean of whether the user is connected with a provider
|
||||
*
|
||||
* @param string $name adapter's name (case insensitive)
|
||||
*
|
||||
* @return bool
|
||||
* @throws InvalidArgumentException
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public function isConnectedWith($name)
|
||||
{
|
||||
return $this->getAdapter($name)->isConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of enabled adapters names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getProviders()
|
||||
{
|
||||
$providers = [];
|
||||
|
||||
foreach ($this->config['providers'] as $name => $config) {
|
||||
if ($config['enabled']) {
|
||||
$providers[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of currently connected adapters names
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidArgumentException
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public function getConnectedProviders()
|
||||
{
|
||||
$providers = [];
|
||||
|
||||
foreach ($this->getProviders() as $name) {
|
||||
if ($this->isConnectedWith($name)) {
|
||||
$providers[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of new instances of currently connected adapters
|
||||
*
|
||||
* @return \Hybridauth\Adapter\AdapterInterface[]
|
||||
* @throws InvalidArgumentException
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public function getConnectedAdapters()
|
||||
{
|
||||
$adapters = [];
|
||||
|
||||
foreach ($this->getProviders() as $name) {
|
||||
$adapter = $this->getAdapter($name);
|
||||
|
||||
if ($adapter->isConnected()) {
|
||||
$adapters[$name] = $adapter;
|
||||
}
|
||||
}
|
||||
|
||||
return $adapters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect all currently connected adapters at once
|
||||
*/
|
||||
public function disconnectAllAdapters()
|
||||
{
|
||||
foreach ($this->getProviders() as $name) {
|
||||
$adapter = $this->getAdapter($name);
|
||||
|
||||
if ($adapter->isConnected()) {
|
||||
$adapter->disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Logger;
|
||||
|
||||
use Hybridauth\Exception\RuntimeException;
|
||||
use Hybridauth\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Debugging and Logging utility.
|
||||
*/
|
||||
class Logger implements LoggerInterface
|
||||
{
|
||||
const NONE = 'none'; // turn logging off
|
||||
const DEBUG = 'debug'; // debug, info and error messages
|
||||
const INFO = 'info'; // info and error messages
|
||||
const ERROR = 'error'; // only error messages
|
||||
|
||||
/**
|
||||
* Debug level.
|
||||
*
|
||||
* One of Logger::NONE, Logger::DEBUG, Logger::INFO, Logger::ERROR
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $level;
|
||||
|
||||
/**
|
||||
* Path to file writeable by the web server. Required if $this->level !== Logger::NONE.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* @param bool|string $level One of Logger::NONE, Logger::DEBUG, Logger::INFO, Logger::ERROR
|
||||
* @param string $file File where to write messages
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct($level, $file)
|
||||
{
|
||||
$this->level = self::NONE;
|
||||
|
||||
if ($level && $level !== self::NONE) {
|
||||
$this->initialize($file);
|
||||
|
||||
$this->level = $level === true ? Logger::DEBUG : $level;
|
||||
$this->file = $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function initialize($file)
|
||||
{
|
||||
if (!$file) {
|
||||
throw new InvalidArgumentException('Log file is not specified.');
|
||||
}
|
||||
|
||||
if (!file_exists($file) && !touch($file)) {
|
||||
throw new RuntimeException(sprintf('Log file %s can not be created.', $file));
|
||||
}
|
||||
|
||||
if (!is_writable($file)) {
|
||||
throw new RuntimeException(sprintf('Log file %s is not writeable.', $file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function info($message, array $context = [])
|
||||
{
|
||||
if (!in_array($this->level, [self::DEBUG, self::INFO])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log(self::INFO, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function debug($message, array $context = [])
|
||||
{
|
||||
if (!in_array($this->level, [self::DEBUG])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log(self::DEBUG, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function error($message, array $context = [])
|
||||
{
|
||||
if (!in_array($this->level, [self::DEBUG, self::INFO, self::ERROR])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log(self::ERROR, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function log($level, $message, array $context = [])
|
||||
{
|
||||
$datetime = new \DateTime();
|
||||
$datetime = $datetime->format(DATE_ATOM);
|
||||
|
||||
$content = sprintf('%s -- %s -- %s -- %s', $level, $_SERVER['REMOTE_ADDR'], $datetime, $message);
|
||||
$content .= ($context ? "\n" . print_r($context, true) : '');
|
||||
$content .= "\n";
|
||||
|
||||
file_put_contents($this->file, $content, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Logger;
|
||||
|
||||
/**
|
||||
* Logger interface, forward-compatible with PSR-3.
|
||||
*/
|
||||
interface LoggerInterface
|
||||
{
|
||||
/**
|
||||
* Interesting events.
|
||||
*
|
||||
* Example: User logs in, SQL logs.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*/
|
||||
public function info($message, array $context = array());
|
||||
|
||||
/**
|
||||
* Detailed debug information.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*/
|
||||
public function debug($message, array $context = array());
|
||||
|
||||
/**
|
||||
* Runtime errors that do not require immediate action but should typically
|
||||
* be logged and monitored.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*/
|
||||
public function error($message, array $context = array());
|
||||
|
||||
/**
|
||||
* Logs with an arbitrary level.
|
||||
*
|
||||
* @param mixed $level
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*/
|
||||
public function log($level, $message, array $context = array());
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Logger;
|
||||
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
|
||||
/**
|
||||
* Wrapper for PSR3 logger.
|
||||
*/
|
||||
class Psr3LoggerWrapper implements LoggerInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function info($message, array $context = [])
|
||||
{
|
||||
$this->logger->info($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function debug($message, array $context = [])
|
||||
{
|
||||
$this->logger->debug($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function error($message, array $context = [])
|
||||
{
|
||||
$this->logger->error($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function log($level, $message, array $context = [])
|
||||
{
|
||||
$this->logger->log($level, $message, $context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OpenID;
|
||||
|
||||
/**
|
||||
* AOL OpenID provider adapter.
|
||||
*/
|
||||
class AOLOpenID extends OpenID
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $openidIdentifier = 'http://openid.aol.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = ''; // Not available
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2019 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Amazon OAuth2 provider adapter.
|
||||
*/
|
||||
class Amazon extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'profile';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.amazon.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://www.amazon.com/ap/oa';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://api.amazon.com/auth/o2/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developer.amazon.com/docs/login-with-amazon/documentation-overview.html';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('user/profile');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('user_id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('user_id');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->email = $data->get('email');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2020 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Exception\InvalidArgumentException;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Exception\InvalidApplicationCredentialsException;
|
||||
use Hybridauth\Exception\UnexpectedValueException;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
use \Firebase\JWT\JWT;
|
||||
use \Firebase\JWT\JWK;
|
||||
|
||||
/**
|
||||
* Apple OAuth2 provider adapter.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $config = [
|
||||
* 'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
* 'keys' => ['id' => '', 'team_id' => '', 'key_id' => '', 'key_file' => '', 'key_content' => ''],
|
||||
* 'scope' => 'name email',
|
||||
*
|
||||
* // Apple's custom auth url params
|
||||
* 'authorize_url_parameters' => [
|
||||
* 'response_mode' => 'form_post'
|
||||
* ]
|
||||
* ];
|
||||
*
|
||||
* $adapter = new Hybridauth\Provider\Apple($config);
|
||||
*
|
||||
* try {
|
||||
* $adapter->authenticate();
|
||||
*
|
||||
* $userProfile = $adapter->getUserProfile();
|
||||
* $tokens = $adapter->getAccessToken();
|
||||
* $response = $adapter->setUserStatus("Hybridauth test message..");
|
||||
* } catch (\Exception $e) {
|
||||
* echo $e->getMessage() ;
|
||||
* }
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* composer require codercat/jwk-to-pem
|
||||
* composer require firebase/php-jwt
|
||||
*
|
||||
* @see https://github.com/sputnik73/hybridauth-sign-in-with-apple
|
||||
* @see https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api
|
||||
*/
|
||||
class Apple extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'name email';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://appleid.apple.com/auth/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://appleid.apple.com/auth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://appleid.apple.com/auth/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developer.apple.com/documentation/sign_in_with_apple';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* The Sign in with Apple servers require percent encoding (or URL encoding)
|
||||
* for its query parameters. If you are using the Sign in with Apple REST API,
|
||||
* you must provide values with encoded spaces (`%20`) instead of plus (`+`) signs.
|
||||
*/
|
||||
protected $AuthorizeUrlParametersEncType = PHP_QUERY_RFC3986;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
$this->AuthorizeUrlParameters['response_mode'] = 'form_post';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$keys = $this->config->get('keys');
|
||||
$keys['secret'] = $this->getSecret();
|
||||
$this->config->set('keys', $keys);
|
||||
return parent::configure();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* include id_token $tokenNames
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
$tokenNames = [
|
||||
'access_token',
|
||||
'id_token',
|
||||
'access_token_secret',
|
||||
'token_type',
|
||||
'refresh_token',
|
||||
'expires_in',
|
||||
'expires_at',
|
||||
];
|
||||
|
||||
$tokens = [];
|
||||
|
||||
foreach ($tokenNames as $name) {
|
||||
if ($this->getStoredData($name)) {
|
||||
$tokens[$name] = $this->getStoredData($name);
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateAccessTokenExchange($response)
|
||||
{
|
||||
$collection = parent::validateAccessTokenExchange($response);
|
||||
|
||||
$this->storeData('id_token', $collection->get('id_token'));
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function getUserProfile()
|
||||
{
|
||||
$id_token = $this->getStoredData('id_token');
|
||||
|
||||
$verifyTokenSignature =
|
||||
$this->config->exists('verifyTokenSignature') ? $this->config->get('verifyTokenSignature') : true;
|
||||
|
||||
if (!$verifyTokenSignature) {
|
||||
// payload extraction by https://github.com/omidborjian
|
||||
// https://github.com/hybridauth/hybridauth/issues/1095#issuecomment-626479263
|
||||
// JWT splits the string to 3 components 1) first is header 2) is payload 3) is signature
|
||||
$payload = explode('.', $id_token)[1];
|
||||
$payload = json_decode(base64_decode($payload));
|
||||
} else {
|
||||
// validate the token signature and get the payload
|
||||
$publicKeys = $this->apiRequest('keys');
|
||||
|
||||
\Firebase\JWT\JWT::$leeway = 120;
|
||||
|
||||
$error = false;
|
||||
$payload = null;
|
||||
|
||||
foreach ($publicKeys->keys as $publicKey) {
|
||||
try {
|
||||
$rsa = new RSA();
|
||||
$jwk = (array)$publicKey;
|
||||
|
||||
$rsa->loadKey(
|
||||
[
|
||||
'e' => new BigInteger(base64_decode($jwk['e']), 256),
|
||||
'n' => new BigInteger(base64_decode(strtr($jwk['n'], '-_', '+/'), true), 256)
|
||||
]
|
||||
);
|
||||
$pem = $rsa->getPublicKey();
|
||||
|
||||
$payload = JWT::decode($id_token, $pem, ['RS256']);
|
||||
break;
|
||||
} catch (\Exception $e) {
|
||||
$error = $e->getMessage();
|
||||
if ($e instanceof \Firebase\JWT\ExpiredException) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($error && !$payload) {
|
||||
throw new \Exception($error);
|
||||
}
|
||||
}
|
||||
|
||||
$data = new Data\Collection($payload);
|
||||
|
||||
if (!$data->exists('sub')) {
|
||||
throw new UnexpectedValueException('Missing token payload.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
$userProfile->identifier = $data->get('sub');
|
||||
$userProfile->email = $data->get('email');
|
||||
$this->storeData('expires_at', $data->get('exp'));
|
||||
|
||||
if (!empty($_REQUEST['user'])) {
|
||||
$objUser = json_decode($_REQUEST['user']);
|
||||
$user = new Data\Collection($objUser);
|
||||
if (!$user->isEmpty()) {
|
||||
$name = $user->get('name');
|
||||
$userProfile->firstName = $name->firstName;
|
||||
$userProfile->lastName = $name->lastName;
|
||||
$userProfile->displayName = join(' ', [$userProfile->firstName, $userProfile->lastName]);
|
||||
}
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string secret token
|
||||
*/
|
||||
private function getSecret()
|
||||
{
|
||||
// Your 10-character Team ID
|
||||
if (!$team_id = $this->config->filter('keys')->get('team_id')) {
|
||||
throw new InvalidApplicationCredentialsException(
|
||||
'Missing parameter team_id: your team id is required to generate the JWS token.'
|
||||
);
|
||||
}
|
||||
|
||||
// Your Services ID, e.g. com.aaronparecki.services
|
||||
if (!$client_id = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key')) {
|
||||
throw new InvalidApplicationCredentialsException(
|
||||
'Missing parameter id: your client id is required to generate the JWS token.'
|
||||
);
|
||||
}
|
||||
|
||||
// Find the 10-char Key ID value from the portal
|
||||
if (!$key_id = $this->config->filter('keys')->get('key_id')) {
|
||||
throw new InvalidApplicationCredentialsException(
|
||||
'Missing parameter key_id: your key id is required to generate the JWS token.'
|
||||
);
|
||||
}
|
||||
|
||||
// Find the 10-char Key ID value from the portal
|
||||
$key_content = $this->config->filter('keys')->get('key_content');
|
||||
|
||||
// Save your private key from Apple in a file called `key.txt`
|
||||
if (!$key_content) {
|
||||
if (!$key_file = $this->config->filter('keys')->get('key_file')) {
|
||||
throw new InvalidApplicationCredentialsException(
|
||||
'Missing parameter key_content or key_file: your key is required to generate the JWS token.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!file_exists($key_file)) {
|
||||
throw new InvalidApplicationCredentialsException(
|
||||
"Your key file $key_file does not exist."
|
||||
);
|
||||
}
|
||||
|
||||
$key_content = file_get_contents($key_file);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'iat' => time(),
|
||||
'exp' => time() + 86400 * 180,
|
||||
'iss' => $team_id,
|
||||
'aud' => 'https://appleid.apple.com',
|
||||
'sub' => $client_id
|
||||
];
|
||||
|
||||
$secret = JWT::encode($data, $key_content, 'ES256', $key_id);
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Authentiq OAuth2 provider adapter.
|
||||
*/
|
||||
class Authentiq extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'aq:name email~rs aq:push openid';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://connect.authentiq.io/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://connect.authentiq.io/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://connect.authentiq.io/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'http://developers.authentiq.io/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->AuthorizeUrlParameters += [
|
||||
'prompt' => 'consent'
|
||||
];
|
||||
|
||||
$this->tokenExchangeHeaders = [
|
||||
'Authorization' => 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret)
|
||||
];
|
||||
|
||||
$this->tokenRefreshHeaders = [
|
||||
'Authorization' => 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('userinfo');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('sub')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('sub');
|
||||
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->firstName = $data->get('given_name');
|
||||
// $userProfile->middleName = $data->get('middle_name'); // not supported
|
||||
$userProfile->lastName = $data->get('family_name');
|
||||
|
||||
if (!empty($userProfile->displayName)) {
|
||||
$userProfile->displayName = join(' ', array($userProfile->firstName,
|
||||
// $userProfile->middleName,
|
||||
$userProfile->lastName));
|
||||
}
|
||||
|
||||
$userProfile->email = $data->get('email');
|
||||
$userProfile->emailVerified = $data->get('email_verified') ? $userProfile->email : '';
|
||||
|
||||
$userProfile->phone = $data->get('phone');
|
||||
// $userProfile->phoneVerified = $data->get('phone_verified') ? $userProfile->phone : ''; // not supported
|
||||
|
||||
$userProfile->profileURL = $data->get('profile');
|
||||
$userProfile->webSiteURL = $data->get('website');
|
||||
$userProfile->photoURL = $data->get('picture');
|
||||
$userProfile->gender = $data->get('gender');
|
||||
$userProfile->address = $data->filter('address')->get('street_address');
|
||||
$userProfile->city = $data->filter('address')->get('locality');
|
||||
$userProfile->country = $data->filter('address')->get('country');
|
||||
$userProfile->region = $data->filter('address')->get('region');
|
||||
$userProfile->zip = $data->filter('address')->get('postal_code');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2020 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* AutoDesk OAuth2 provider adapter.
|
||||
*/
|
||||
class AutoDesk extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'data:read';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://developer.api.autodesk.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl
|
||||
= 'https://developer.api.autodesk.com/authentication/v1/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl
|
||||
= 'https://developer.api.autodesk.com/authentication/v1/gettoken';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $refreshTokenUrl
|
||||
= 'https://developer.api.autodesk.com/authentication/v1/refreshtoken';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation
|
||||
= 'https://forge.autodesk.com/en/docs/oauth/v2/developers_guide/overview/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
if ($this->isRefreshTokenAvailable()) {
|
||||
$this->tokenRefreshParameters += [
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* See: https://forge.autodesk.com/en/docs/oauth/v2/reference/http/users-@me-GET/
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('userprofile/v1/users/@me');
|
||||
|
||||
$collection = new Data\Collection($response);
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $collection->get('userId');
|
||||
$userProfile->displayName
|
||||
= $collection->get('firstName') .' '. $collection->get('lastName');
|
||||
$userProfile->firstName = $collection->get('firstName');
|
||||
$userProfile->lastName = $collection->get('lastName');
|
||||
$userProfile->email = $collection->get('emailId');
|
||||
$userProfile->language = $collection->get('language');
|
||||
$userProfile->webSiteURL = $collection->get('websiteUrl');
|
||||
$userProfile->photoURL
|
||||
= $collection->filter('profileImages')->get('sizeX360');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Set up your OAuth2 at https://bitbucket.org/<yourusername>/workspace/settings/api
|
||||
*/
|
||||
|
||||
/**
|
||||
* BitBucket OAuth2 provider adapter.
|
||||
*/
|
||||
class BitBucket extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'email';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.bitbucket.org/2.0/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://bitbucket.org/site/oauth2/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://bitbucket.org/site/oauth2/access_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developer.atlassian.com/bitbucket/concepts/oauth2.html';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('user');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('uuid')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('uuid');
|
||||
$userProfile->profileURL = 'https://bitbucket.org/' . $data->get('username') . '/';
|
||||
$userProfile->displayName = $data->get('display_name');
|
||||
$userProfile->email = $data->get('email');
|
||||
$userProfile->webSiteURL = $data->get('website');
|
||||
$userProfile->region = $data->get('location');
|
||||
|
||||
$userProfile->displayName = $userProfile->displayName ?: $data->get('username');
|
||||
|
||||
if (empty($userProfile->email) && strpos($this->scope, 'email') !== false) {
|
||||
try {
|
||||
// user email is not mandatory so keep it quiet
|
||||
$userProfile = $this->requestUserEmail($userProfile);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request user email
|
||||
*
|
||||
* @param $userProfile
|
||||
*
|
||||
* @return User\Profile
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function requestUserEmail($userProfile)
|
||||
{
|
||||
$response = $this->apiRequest('user/emails');
|
||||
|
||||
foreach ($response->values as $idx => $item) {
|
||||
if (!empty($item->is_primary) && $item->is_primary == true) {
|
||||
$userProfile->email = $item->email;
|
||||
|
||||
if (!empty($item->is_confirmed) && $item->is_confirmed == true) {
|
||||
$userProfile->emailVerified = $userProfile->email;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Blizzard Battle.net OAuth2 provider adapter.
|
||||
*/
|
||||
class Blizzard extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = '';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://us.battle.net/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://us.battle.net/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://us.battle.net/oauth/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://develop.battle.net/documentation';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('oauth/userinfo');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('battletag') ?: $data->get('login');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Blizzard US/SEA Battle.net OAuth2 provider adapter.
|
||||
*/
|
||||
class BlizzardAPAC extends Blizzard
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://apac.battle.net/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://apac.battle.net/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://apac.battle.net/oauth/token';
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Blizzard EU Battle.net OAuth2 provider adapter.
|
||||
*/
|
||||
class BlizzardEU extends Blizzard
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://eu.battle.net/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://eu.battle.net/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://eu.battle.net/oauth/token';
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* DeviantArt OAuth2 provider adapter.
|
||||
*/
|
||||
class DeviantArt extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'user';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://www.deviantart.com/api/v1/oauth2/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://www.deviantart.com/oauth2/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://www.deviantart.com/oauth2/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://www.deviantart.com/developers/http/v1/20200519';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
if ($this->isRefreshTokenAvailable()) {
|
||||
$this->tokenRefreshParameters += [
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* See: https://www.deviantart.com/developers/http/v1/20200519/user_whoami/2413749853e66c5812c9beccc0ab3495
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('user/whoami');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$full_name = explode(' ', $data->filter('profile')->get('real_name'));
|
||||
if (count($full_name) < 2) {
|
||||
$full_name[1] = '';
|
||||
}
|
||||
|
||||
$userProfile->identifier = $data->get('userid');
|
||||
$userProfile->displayName = $data->get('username');
|
||||
$userProfile->profileURL = $data->get('usericon');
|
||||
$userProfile->webSiteURL = $data->filter('profile')->get('website');
|
||||
$userProfile->firstName = $full_name[0];
|
||||
$userProfile->lastName = $full_name[1];
|
||||
$userProfile->profileURL = $data->filter('profile')->filter('profile_pic')->get('url');
|
||||
$userProfile->gender = $data->filter('details')->get('sex');
|
||||
$userProfile->age = $data->filter('details')->get('age');
|
||||
$userProfile->country = $data->filter('geo')->get('country');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Discord OAuth2 provider adapter.
|
||||
*/
|
||||
class Discord extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'identify email';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://discordapp.com/api/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://discordapp.com/api/oauth2/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://discordapp.com/api/oauth2/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://discordapp.com/developers/docs/topics/oauth2';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
if ($this->isRefreshTokenAvailable()) {
|
||||
$this->tokenRefreshParameters += [
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('users/@me');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
// Makes display name more unique.
|
||||
$displayName = $data->get('username') ?: $data->get('login');
|
||||
if ($discriminator = $data->get('discriminator')) {
|
||||
$displayName .= "#{$discriminator}";
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $displayName;
|
||||
$userProfile->email = $data->get('email');
|
||||
|
||||
if ($data->get('verified')) {
|
||||
$userProfile->emailVerified = $data->get('email');
|
||||
}
|
||||
|
||||
if ($data->get('avatar')) {
|
||||
$userProfile->photoURL = 'https://cdn.discordapp.com/avatars/';
|
||||
$userProfile->photoURL .= $data->get('id') . '/' . $data->get('avatar') . '.png';
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Disqus OAuth2 provider adapter.
|
||||
*/
|
||||
class Disqus extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'read,email';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://disqus.com/api/3.0/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://disqus.com/api/oauth/2.0/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://disqus.com/api/oauth/2.0/access_token/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://disqus.com/api/docs/auth/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->apiRequestParameters = [
|
||||
'api_key' => $this->clientId, 'api_secret' => $this->clientSecret
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('users/details');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->filter('response')->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$data = $data->filter('response');
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->description = $data->get('bio');
|
||||
$userProfile->profileURL = $data->get('profileUrl');
|
||||
$userProfile->email = $data->get('email');
|
||||
$userProfile->region = $data->get('location');
|
||||
$userProfile->description = $data->get('about');
|
||||
|
||||
$userProfile->photoURL = $data->filter('avatar')->get('permalink');
|
||||
|
||||
$userProfile->displayName = $userProfile->displayName ?: $data->get('username');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Dribbble OAuth2 provider adapter.
|
||||
*/
|
||||
class Dribbble extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.dribbble.com/v2/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://dribbble.com/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://dribbble.com/oauth/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'http://developer.dribbble.com/v2/oauth/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('user');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->profileURL = $data->get('html_url');
|
||||
$userProfile->photoURL = $data->get('avatar_url');
|
||||
$userProfile->description = $data->get('bio');
|
||||
$userProfile->region = $data->get('location');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
|
||||
$userProfile->displayName = $userProfile->displayName ?: $data->get('username');
|
||||
|
||||
$userProfile->webSiteURL = $data->filter('links')->get('web');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2020 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Dropbox OAuth2 provider adapter.
|
||||
*/
|
||||
class Dropbox extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'account_info.read';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.dropbox.com/2/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://www.dropbox.com/1/oauth2/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://api.dropbox.com/1/oauth2/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://www.dropbox.com/developers/documentation/http/documentation';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('users/get_current_account', 'POST', [], [], true);
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('account_id') || !$data->get('account_id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('account_id');
|
||||
$userProfile->displayName = $data->filter('name')->get('display_name');
|
||||
$userProfile->firstName = $data->filter('name')->get('given_name');
|
||||
$userProfile->lastName = $data->filter('name')->get('surname');
|
||||
$userProfile->email = $data->get('email');
|
||||
$userProfile->photoURL = $data->get('profile_photo_url');
|
||||
$userProfile->language = $data->get('locale');
|
||||
$userProfile->country = $data->get('country');
|
||||
if ($data->get('email_verified')) {
|
||||
$userProfile->emailVerified = $data->get('email');
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,453 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Exception\InvalidArgumentException;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Facebook OAuth2 provider adapter.
|
||||
*
|
||||
* Facebook doesn't use standard OAuth refresh tokens.
|
||||
* Instead it has a "token exchange" system. You exchange the token prior to
|
||||
* expiry, to push back expiry. You start with a short-lived token and each
|
||||
* exchange gives you a long-lived one (90 days).
|
||||
* We control this with the 'exchange_by_expiry_days' option.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $config = [
|
||||
* 'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
* 'keys' => ['id' => '', 'secret' => ''],
|
||||
* 'scope' => 'email, user_status, user_posts',
|
||||
* 'exchange_by_expiry_days' => 45, // null for no token exchange
|
||||
* ];
|
||||
*
|
||||
* $adapter = new Hybridauth\Provider\Facebook($config);
|
||||
*
|
||||
* try {
|
||||
* $adapter->authenticate();
|
||||
*
|
||||
* $userProfile = $adapter->getUserProfile();
|
||||
* $tokens = $adapter->getAccessToken();
|
||||
* $response = $adapter->setUserStatus("Hybridauth test message..");
|
||||
* } catch (\Exception $e) {
|
||||
* echo $e->getMessage() ;
|
||||
* }
|
||||
*/
|
||||
class Facebook extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'email, public_profile';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://graph.facebook.com/v8.0/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://www.facebook.com/dialog/oauth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://graph.facebook.com/oauth/access_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developers.facebook.com/docs/facebook-login/overview';
|
||||
|
||||
/**
|
||||
* @var string Profile URL template as the fallback when no `link` returned from the API.
|
||||
*/
|
||||
protected $profileUrlTemplate = 'https://www.facebook.com/%s';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
// Require proof on all Facebook api calls
|
||||
// https://developers.facebook.com/docs/graph-api/securing-requests#appsecret_proof
|
||||
if ($accessToken = $this->getStoredData('access_token')) {
|
||||
$this->apiRequestParameters['appsecret_proof'] = hash_hmac('sha256', $accessToken, $this->clientSecret);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function maintainToken()
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle token exchange prior to the standard handler for an API request
|
||||
$exchange_by_expiry_days = $this->config->get('exchange_by_expiry_days') ?: 45;
|
||||
if ($exchange_by_expiry_days !== null) {
|
||||
$projected_timestamp = time() + 60 * 60 * 24 * $exchange_by_expiry_days;
|
||||
if (!$this->hasAccessTokenExpired() && $this->hasAccessTokenExpired($projected_timestamp)) {
|
||||
$this->exchangeAccessToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exchange the Access Token with one that expires further in the future.
|
||||
*
|
||||
* @return string Raw Provider API response
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
* @throws \Hybridauth\Exception\InvalidAccessTokenException
|
||||
*/
|
||||
public function exchangeAccessToken()
|
||||
{
|
||||
$exchangeTokenParameters = [
|
||||
'grant_type' => 'fb_exchange_token',
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
'fb_exchange_token' => $this->getStoredData('access_token'),
|
||||
];
|
||||
|
||||
$response = $this->httpClient->request(
|
||||
$this->accessTokenUrl,
|
||||
'GET',
|
||||
$exchangeTokenParameters
|
||||
);
|
||||
|
||||
$this->validateApiResponse('Unable to exchange the access token');
|
||||
|
||||
$this->validateAccessTokenExchange($response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$fields = [
|
||||
'id',
|
||||
'name',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'gender',
|
||||
'website',
|
||||
'locale',
|
||||
'about',
|
||||
'email',
|
||||
'hometown',
|
||||
'birthday',
|
||||
];
|
||||
|
||||
if (strpos($this->scope, 'user_link') !== false) {
|
||||
$fields[] = 'link';
|
||||
}
|
||||
|
||||
if (strpos($this->scope, 'user_gender') !== false) {
|
||||
$fields[] = 'gender';
|
||||
}
|
||||
|
||||
// Note that en_US is needed for gender fields to match convention.
|
||||
$locale = $this->config->get('locale') ?: 'ko_KR';
|
||||
$response = $this->apiRequest('me', 'GET', [
|
||||
'fields' => implode(',', $fields),
|
||||
'locale' => $locale,
|
||||
]);
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->firstName = $data->get('first_name');
|
||||
$userProfile->lastName = $data->get('last_name');
|
||||
$userProfile->gender = $data->get('gender');
|
||||
$userProfile->profileURL = $data->get('link');
|
||||
$userProfile->webSiteURL = $data->get('website');
|
||||
$userProfile->gender = $data->get('gender');
|
||||
$userProfile->language = $data->get('locale');
|
||||
$userProfile->description = $data->get('about');
|
||||
$userProfile->email = $data->get('email');
|
||||
|
||||
// Fallback for profile URL in case Facebook does not provide "pretty" link with username (if user set it).
|
||||
if (empty($userProfile->profileURL)) {
|
||||
$userProfile->profileURL = $this->getProfileUrl($userProfile->identifier);
|
||||
}
|
||||
|
||||
$userProfile->region = $data->filter('hometown')->get('name');
|
||||
|
||||
$photoSize = $this->config->get('photo_size') ?: '150';
|
||||
|
||||
$userProfile->photoURL = $this->apiBaseUrl . $userProfile->identifier;
|
||||
$userProfile->photoURL .= '/picture?width=' . $photoSize . '&height=' . $photoSize;
|
||||
|
||||
$userProfile->emailVerified = $userProfile->email;
|
||||
|
||||
$userProfile = $this->fetchUserRegion($userProfile);
|
||||
|
||||
$userProfile = $this->fetchBirthday($userProfile, $data->get('birthday'));
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the user region.
|
||||
*
|
||||
* @param User\Profile $userProfile
|
||||
*
|
||||
* @return \Hybridauth\User\Profile
|
||||
*/
|
||||
protected function fetchUserRegion(User\Profile $userProfile)
|
||||
{
|
||||
if (!empty($userProfile->region)) {
|
||||
$regionArr = explode(',', $userProfile->region);
|
||||
|
||||
if (count($regionArr) > 1) {
|
||||
$userProfile->city = trim($regionArr[0]);
|
||||
$userProfile->country = trim($regionArr[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the user birthday.
|
||||
*
|
||||
* @param User\Profile $userProfile
|
||||
* @param string $birthday
|
||||
*
|
||||
* @return \Hybridauth\User\Profile
|
||||
*/
|
||||
protected function fetchBirthday(User\Profile $userProfile, $birthday)
|
||||
{
|
||||
$result = (new Data\Parser())->parseBirthday($birthday, '/');
|
||||
|
||||
$userProfile->birthYear = (int)$result[0];
|
||||
$userProfile->birthMonth = (int)$result[1];
|
||||
$userProfile->birthDay = (int)$result[2];
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* /v2.0/me/friends only returns the user's friends who also use the app.
|
||||
* In the cases where you want to let people tag their friends in stories published by your app,
|
||||
* you can use the Taggable Friends API.
|
||||
*
|
||||
* https://developers.facebook.com/docs/apps/faq#unable_full_friend_list
|
||||
*/
|
||||
public function getUserContacts()
|
||||
{
|
||||
$contacts = [];
|
||||
|
||||
$apiUrl = 'me/friends?fields=link,name';
|
||||
|
||||
do {
|
||||
$response = $this->apiRequest($apiUrl);
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('data')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
if (!$data->filter('data')->isEmpty()) {
|
||||
foreach ($data->filter('data')->toArray() as $item) {
|
||||
$contacts[] = $this->fetchUserContact($item);
|
||||
}
|
||||
}
|
||||
|
||||
if ($data->filter('paging')->exists('next')) {
|
||||
$apiUrl = $data->filter('paging')->get('next');
|
||||
|
||||
$pagedList = true;
|
||||
} else {
|
||||
$pagedList = false;
|
||||
}
|
||||
} while ($pagedList);
|
||||
|
||||
return $contacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the user contact.
|
||||
*
|
||||
* @param array $item
|
||||
*
|
||||
* @return \Hybridauth\User\Contact
|
||||
*/
|
||||
protected function fetchUserContact($item)
|
||||
{
|
||||
$userContact = new User\Contact();
|
||||
|
||||
$item = new Data\Collection($item);
|
||||
|
||||
$userContact->identifier = $item->get('id');
|
||||
$userContact->displayName = $item->get('name');
|
||||
|
||||
$userContact->profileURL = $item->exists('link')
|
||||
?: $this->getProfileUrl($userContact->identifier);
|
||||
|
||||
$userContact->photoURL = $this->apiBaseUrl . $userContact->identifier . '/picture?width=150&height=150';
|
||||
|
||||
return $userContact;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setPageStatus($status, $pageId)
|
||||
{
|
||||
$status = is_string($status) ? ['message' => $status] : $status;
|
||||
|
||||
// Post on user wall.
|
||||
if ($pageId === 'me') {
|
||||
return $this->setUserStatus($status);
|
||||
}
|
||||
|
||||
// Retrieve writable user pages and filter by given one.
|
||||
$pages = $this->getUserPages(true);
|
||||
$pages = array_filter($pages, function ($page) use ($pageId) {
|
||||
return $page->id == $pageId;
|
||||
});
|
||||
|
||||
if (!$pages) {
|
||||
throw new InvalidArgumentException('Could not find a page with given id.');
|
||||
}
|
||||
|
||||
$page = reset($pages);
|
||||
|
||||
// Use page access token instead of user access token.
|
||||
$headers = [
|
||||
'Authorization' => 'Bearer ' . $page->access_token,
|
||||
];
|
||||
|
||||
// Refresh proof for API call.
|
||||
$parameters = $status + [
|
||||
'appsecret_proof' => hash_hmac('sha256', $page->access_token, $this->clientSecret),
|
||||
];
|
||||
|
||||
$response = $this->apiRequest("{$pageId}/feed", 'POST', $parameters, $headers);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserPages($writable = false)
|
||||
{
|
||||
$pages = $this->apiRequest('me/accounts');
|
||||
|
||||
if (!$writable) {
|
||||
return $pages->data;
|
||||
}
|
||||
|
||||
// Filter user pages by CREATE_CONTENT permission.
|
||||
return array_filter($pages->data, function ($page) {
|
||||
return in_array('CREATE_CONTENT', $page->tasks);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserActivity($stream = 'me')
|
||||
{
|
||||
$apiUrl = $stream == 'me' ? 'me/feed' : 'me/home';
|
||||
|
||||
$response = $this->apiRequest($apiUrl);
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('data')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$activities = [];
|
||||
|
||||
foreach ($data->filter('data')->toArray() as $item) {
|
||||
$activities[] = $this->fetchUserActivity($item);
|
||||
}
|
||||
|
||||
return $activities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $item
|
||||
*
|
||||
* @return User\Activity
|
||||
*/
|
||||
protected function fetchUserActivity($item)
|
||||
{
|
||||
$userActivity = new User\Activity();
|
||||
|
||||
$item = new Data\Collection($item);
|
||||
|
||||
$userActivity->id = $item->get('id');
|
||||
$userActivity->date = $item->get('created_time');
|
||||
|
||||
if ('video' == $item->get('type') || 'link' == $item->get('type')) {
|
||||
$userActivity->text = $item->get('link');
|
||||
}
|
||||
|
||||
if (empty($userActivity->text) && $item->exists('story')) {
|
||||
$userActivity->text = $item->get('link');
|
||||
}
|
||||
|
||||
if (empty($userActivity->text) && $item->exists('message')) {
|
||||
$userActivity->text = $item->get('message');
|
||||
}
|
||||
|
||||
if (!empty($userActivity->text) && $item->exists('from')) {
|
||||
$userActivity->user->identifier = $item->filter('from')->get('id');
|
||||
$userActivity->user->displayName = $item->filter('from')->get('name');
|
||||
|
||||
$userActivity->user->profileURL = $this->getProfileUrl($userActivity->user->identifier);
|
||||
|
||||
$userActivity->user->photoURL = $this->apiBaseUrl . $userActivity->user->identifier;
|
||||
$userActivity->user->photoURL .= '/picture?width=150&height=150';
|
||||
}
|
||||
|
||||
return $userActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile URL.
|
||||
*
|
||||
* @param int $identity User ID.
|
||||
* @return string|null NULL when identity is not provided.
|
||||
*/
|
||||
protected function getProfileUrl($identity)
|
||||
{
|
||||
if (!is_numeric($identity)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sprintf($this->profileUrlTemplate, $identity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Foursquare OAuth2 provider adapter.
|
||||
*/
|
||||
class Foursquare extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.foursquare.com/v2/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://foursquare.com/oauth2/authenticate';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://foursquare.com/oauth2/access_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenName = 'oauth_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developer.foursquare.com/overview/auth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$apiVersion = $this->config->get('api_version') ?: '20140201';
|
||||
|
||||
$this->apiRequestParameters = [
|
||||
'oauth_token' => $this->getStoredData('access_token'),
|
||||
'v' => $apiVersion,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('users/self');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('response')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$data = $data->filter('response')->filter('user');
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->firstName = $data->get('firstName');
|
||||
$userProfile->lastName = $data->get('lastName');
|
||||
$userProfile->gender = $data->get('gender');
|
||||
$userProfile->city = $data->get('homeCity');
|
||||
$userProfile->email = $data->filter('contact')->get('email');
|
||||
$userProfile->emailVerified = $userProfile->email;
|
||||
$userProfile->profileURL = 'https://www.foursquare.com/user/' . $userProfile->identifier;
|
||||
$userProfile->displayName = trim($userProfile->firstName . ' ' . $userProfile->lastName);
|
||||
|
||||
if ($data->exists('photo')) {
|
||||
$photoSize = $this->config->get('photo_size') ?: '150x150';
|
||||
|
||||
$userProfile->photoURL = $data->filter('photo')->get('prefix');
|
||||
$userProfile->photoURL .= $photoSize . $data->filter('photo')->get('suffix');
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserContacts()
|
||||
{
|
||||
$response = $this->apiRequest('users/self/friends');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('response')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$contacts = [];
|
||||
|
||||
foreach ($data->filter('response')->filter('friends')->filter('items')->toArray() as $item) {
|
||||
$contacts[] = $this->fetchUserContact($item);
|
||||
}
|
||||
|
||||
return $contacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $item
|
||||
*
|
||||
* @return User\Contact
|
||||
*/
|
||||
protected function fetchUserContact($item)
|
||||
{
|
||||
$photoSize = $this->config->get('photo_size') ?: '150x150';
|
||||
|
||||
$item = new Data\Collection($item);
|
||||
|
||||
$userContact = new User\Contact();
|
||||
|
||||
$userContact->identifier = $item->get('id');
|
||||
$userContact->photoURL = $item->filter('photo')->get('prefix');
|
||||
$userContact->photoURL .= $photoSize . $item->filter('photo')->get('suffix');
|
||||
$userContact->displayName = trim($item->get('firstName') . ' ' . $item->get('lastName'));
|
||||
$userContact->email = $item->filter('contact')->get('email');
|
||||
|
||||
return $userContact;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Github OAuth2 provider adapter.
|
||||
*/
|
||||
class GitHub extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'user:email';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.github.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://github.com/login/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://github.com/login/oauth/access_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developer.github.com/v3/oauth/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('user');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->description = $data->get('bio');
|
||||
$userProfile->photoURL = $data->get('avatar_url');
|
||||
$userProfile->profileURL = $data->get('html_url');
|
||||
$userProfile->email = $data->get('email');
|
||||
$userProfile->webSiteURL = $data->get('blog');
|
||||
$userProfile->region = $data->get('location');
|
||||
|
||||
$userProfile->displayName = $userProfile->displayName ?: $data->get('login');
|
||||
|
||||
if (empty($userProfile->email) && strpos($this->scope, 'user:email') !== false) {
|
||||
try {
|
||||
// user email is not mandatory so keep it quite.
|
||||
$userProfile = $this->requestUserEmail($userProfile);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request connected user email
|
||||
*
|
||||
* https://developer.github.com/v3/users/emails/
|
||||
* @param User\Profile $userProfile
|
||||
*
|
||||
* @return User\Profile
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function requestUserEmail(User\Profile $userProfile)
|
||||
{
|
||||
$response = $this->apiRequest('user/emails');
|
||||
|
||||
foreach ($response as $idx => $item) {
|
||||
if (!empty($item->primary) && $item->primary == 1) {
|
||||
$userProfile->email = $item->email;
|
||||
|
||||
if (!empty($item->verified) && $item->verified == 1) {
|
||||
$userProfile->emailVerified = $userProfile->email;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* GitLab OAuth2 provider adapter.
|
||||
*/
|
||||
class GitLab extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'api';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://gitlab.com/api/v3/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://gitlab.com/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://gitlab.com/oauth/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://docs.gitlab.com/ee/api/oauth2.html';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('user');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->description = $data->get('bio');
|
||||
$userProfile->photoURL = $data->get('avatar_url');
|
||||
$userProfile->profileURL = $data->get('web_url');
|
||||
$userProfile->email = $data->get('email');
|
||||
$userProfile->webSiteURL = $data->get('website_url');
|
||||
|
||||
$userProfile->displayName = $userProfile->displayName ?: $data->get('username');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Google OAuth2 provider adapter.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $config = [
|
||||
* 'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
* 'keys' => ['id' => '', 'secret' => ''],
|
||||
* 'scope' => 'https://www.googleapis.com/auth/userinfo.profile',
|
||||
*
|
||||
* // google's custom auth url params
|
||||
* 'authorize_url_parameters' => [
|
||||
* 'approval_prompt' => 'force', // to pass only when you need to acquire a new refresh token.
|
||||
* 'access_type' => .., // is set to 'offline' by default
|
||||
* 'hd' => ..,
|
||||
* 'state' => ..,
|
||||
* // etc.
|
||||
* ]
|
||||
* ];
|
||||
*
|
||||
* $adapter = new Hybridauth\Provider\Google($config);
|
||||
*
|
||||
* try {
|
||||
* $adapter->authenticate();
|
||||
*
|
||||
* $userProfile = $adapter->getUserProfile();
|
||||
* $tokens = $adapter->getAccessToken();
|
||||
* $contacts = $adapter->getUserContacts(['max-results' => 75]);
|
||||
* } catch (\Exception $e) {
|
||||
* echo $e->getMessage() ;
|
||||
* }
|
||||
*/
|
||||
class Google extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
// phpcs:ignore
|
||||
protected $scope = 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://www.googleapis.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://accounts.google.com/o/oauth2/auth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://accounts.google.com/o/oauth2/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developers.google.com/identity/protocols/OAuth2';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->AuthorizeUrlParameters += [
|
||||
'access_type' => 'offline'
|
||||
];
|
||||
|
||||
if ($this->isRefreshTokenAvailable()) {
|
||||
$this->tokenRefreshParameters += [
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* See: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('oauth2/v3/userinfo');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('sub')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('sub');
|
||||
$userProfile->firstName = $data->get('given_name');
|
||||
$userProfile->lastName = $data->get('family_name');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->photoURL = $data->get('picture');
|
||||
$userProfile->profileURL = $data->get('profile');
|
||||
$userProfile->gender = $data->get('gender');
|
||||
$userProfile->language = $data->get('locale');
|
||||
$userProfile->email = $data->get('email');
|
||||
|
||||
$userProfile->emailVerified = $data->get('email_verified') ? $userProfile->email : '';
|
||||
|
||||
if ($this->config->get('photo_size')) {
|
||||
$userProfile->photoURL .= '?sz=' . $this->config->get('photo_size');
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserContacts($parameters = [])
|
||||
{
|
||||
$parameters = ['max-results' => 500] + $parameters;
|
||||
|
||||
// Google Gmail and Android contacts
|
||||
if (false !== strpos($this->scope, '/m8/feeds/') || false !== strpos($this->scope, '/auth/contacts.readonly')) {
|
||||
return $this->getGmailContacts($parameters);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve Gmail contacts
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getGmailContacts($parameters = [])
|
||||
{
|
||||
$url = 'https://www.google.com/m8/feeds/contacts/default/full?'
|
||||
. http_build_query(array_replace(['alt' => 'json', 'v' => '3.0'], (array)$parameters));
|
||||
|
||||
$response = $this->apiRequest($url);
|
||||
|
||||
if (!$response) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$contacts = [];
|
||||
|
||||
if (isset($response->feed->entry)) {
|
||||
foreach ($response->feed->entry as $idx => $entry) {
|
||||
$uc = new User\Contact();
|
||||
|
||||
$uc->email = isset($entry->{'gd$email'}[0]->address)
|
||||
? (string)$entry->{'gd$email'}[0]->address
|
||||
: '';
|
||||
|
||||
$uc->displayName = isset($entry->title->{'$t'}) ? (string)$entry->title->{'$t'} : '';
|
||||
$uc->identifier = ($uc->email != '') ? $uc->email : '';
|
||||
$uc->description = '';
|
||||
|
||||
if (property_exists($response, 'website')) {
|
||||
if (is_array($response->website)) {
|
||||
foreach ($response->website as $w) {
|
||||
if ($w->primary == true) {
|
||||
$uc->webSiteURL = $w->value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$uc->webSiteURL = $response->website->value;
|
||||
}
|
||||
} else {
|
||||
$uc->webSiteURL = '';
|
||||
}
|
||||
|
||||
$contacts[] = $uc;
|
||||
}
|
||||
}
|
||||
|
||||
return $contacts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2020 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Data\Collection;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Instagram OAuth2 provider adapter via Instagram Basic Display API.
|
||||
*/
|
||||
class Instagram extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'user_profile,user_media';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://graph.instagram.com';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://api.instagram.com/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://api.instagram.com/oauth/access_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developers.facebook.com/docs/instagram-basic-display-api';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
// The Instagram API requires an access_token from authenticated users
|
||||
// for each endpoint.
|
||||
$accessToken = $this->getStoredData($this->accessTokenName);
|
||||
$this->apiRequestParameters[$this->accessTokenName] = $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateAccessTokenExchange($response)
|
||||
{
|
||||
$collection = parent::validateAccessTokenExchange($response);
|
||||
|
||||
if (!$collection->exists('expires_in')) {
|
||||
// Instagram tokens always expire in an hour, but this is implicit not explicit
|
||||
|
||||
$expires_in = 60 * 60;
|
||||
|
||||
$expires_at = time() + $expires_in;
|
||||
|
||||
$this->storeData('expires_in', $expires_in);
|
||||
$this->storeData('expires_at', $expires_at);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function maintainToken()
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle token exchange prior to the standard handler for an API request
|
||||
$exchange_by_expiry_days = $this->config->get('exchange_by_expiry_days') ?: 45;
|
||||
if ($exchange_by_expiry_days !== null) {
|
||||
$projected_timestamp = time() + 60 * 60 * 24 * $exchange_by_expiry_days;
|
||||
if (!$this->hasAccessTokenExpired() && $this->hasAccessTokenExpired($projected_timestamp)) {
|
||||
$this->exchangeAccessToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exchange the Access Token with one that expires further in the future.
|
||||
*
|
||||
* @return string Raw Provider API response
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
* @throws InvalidAccessTokenException
|
||||
*/
|
||||
public function exchangeAccessToken()
|
||||
{
|
||||
if ($this->getStoredData('expires_in') >= 5000000) {
|
||||
/*
|
||||
Refresh a long-lived token (needed on Instagram, but not Facebook).
|
||||
It's not an oAuth style refresh using a refresh token.
|
||||
Actually it's really just another exchange, and invalidates the old token.
|
||||
Facebook/Instagram documentation is not very helpful at explaining that!
|
||||
*/
|
||||
$exchangeTokenParameters = [
|
||||
'grant_type' => 'ig_refresh_token',
|
||||
'client_secret' => $this->clientSecret,
|
||||
'access_token' => $this->getStoredData('access_token'),
|
||||
];
|
||||
$url = 'https://graph.instagram.com/refresh_access_token';
|
||||
} else {
|
||||
// Exchange short-lived to long-lived
|
||||
$exchangeTokenParameters = [
|
||||
'grant_type' => 'ig_exchange_token',
|
||||
'client_secret' => $this->clientSecret,
|
||||
'access_token' => $this->getStoredData('access_token'),
|
||||
];
|
||||
$url = 'https://graph.instagram.com/access_token';
|
||||
}
|
||||
|
||||
$response = $this->httpClient->request(
|
||||
$url,
|
||||
'GET',
|
||||
$exchangeTokenParameters
|
||||
);
|
||||
|
||||
$this->validateApiResponse('Unable to exchange the access token');
|
||||
|
||||
$this->validateAccessTokenExchange($response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('me', 'GET', [
|
||||
'fields' => 'id,username,account_type,media_count',
|
||||
]);
|
||||
|
||||
$data = new Collection($response);
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('username');
|
||||
$userProfile->profileURL = "https://instagram.com/{$userProfile->displayName}";
|
||||
$userProfile->data = [
|
||||
'account_type' => $data->get('account_type'),
|
||||
'media_count' => $data->get('media_count'),
|
||||
];
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch user medias.
|
||||
*
|
||||
* @param int $limit Number of elements per page.
|
||||
* @param string $pageId Current pager ID.
|
||||
* @param array|null $fields Fields to fetch per media.
|
||||
*
|
||||
* @return \Hybridauth\Data\Collection
|
||||
*
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
* @throws \Hybridauth\Exception\InvalidAccessTokenException
|
||||
* @throws \Hybridauth\Exception\UnexpectedApiResponseException
|
||||
*/
|
||||
public function getUserMedia($limit = 12, $pageId = null, array $fields = null)
|
||||
{
|
||||
if (empty($fields)) {
|
||||
$fields = [
|
||||
'id',
|
||||
'caption',
|
||||
'media_type',
|
||||
'media_url',
|
||||
'thumbnail_url',
|
||||
'permalink',
|
||||
'timestamp',
|
||||
'username',
|
||||
];
|
||||
}
|
||||
|
||||
$params = [
|
||||
'fields' => implode(',', $fields),
|
||||
'limit' => $limit,
|
||||
];
|
||||
if ($pageId !== null) {
|
||||
$params['after'] = $pageId;
|
||||
}
|
||||
|
||||
$response = $this->apiRequest('me/media', 'GET', $params);
|
||||
|
||||
$data = new Collection($response);
|
||||
if (!$data->exists('data')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a single user's media.
|
||||
*
|
||||
* @param string $mediaId Media ID.
|
||||
* @param array|null $fields Fields to fetch per media.
|
||||
*
|
||||
* @return \Hybridauth\Data\Collection
|
||||
*
|
||||
* @throws \Hybridauth\Exception\HttpClientFailureException
|
||||
* @throws \Hybridauth\Exception\HttpRequestFailedException
|
||||
* @throws \Hybridauth\Exception\InvalidAccessTokenException
|
||||
* @throws \Hybridauth\Exception\UnexpectedApiResponseException
|
||||
*/
|
||||
public function getMedia($mediaId, array $fields = null)
|
||||
{
|
||||
if (empty($fields)) {
|
||||
$fields = [
|
||||
'id',
|
||||
'caption',
|
||||
'media_type',
|
||||
'media_url',
|
||||
'thumbnail_url',
|
||||
'permalink',
|
||||
'timestamp',
|
||||
'username',
|
||||
];
|
||||
}
|
||||
|
||||
$response = $this->apiRequest($mediaId, 'GET', [
|
||||
'fields' => implode(',', $fields),
|
||||
]);
|
||||
|
||||
$data = new Collection($response);
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Exception\InvalidArgumentException;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
class Kakao extends OAuth2
|
||||
{
|
||||
protected $scope = '';
|
||||
protected $apiBaseUrl = 'https://kapi.kakao.com/v2/';
|
||||
protected $authorizeUrl = 'https://kauth.kakao.com/oauth/authorize';
|
||||
protected $accessTokenUrl = 'https://kauth.kakao.com/oauth/token';
|
||||
protected $apiDocumentation = 'https://developers.kakao.com/docs/latest/ko/kakaologin/common';
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* load the user profile
|
||||
*/
|
||||
function getUserProfile()
|
||||
{
|
||||
//$params = array('property_keys'=>'kaccount_email'); // v1 parameter
|
||||
$params = array('property_keys'=>array('kakao_account.email')); // v2 parameter
|
||||
|
||||
$requestHeader = array( 'Authorization: Bearer ' . $this->getStoredData('access_token') );
|
||||
|
||||
$response = $this->apiRequest("user/me", "POST", $params, $requestHeader);
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
# store the user profile.
|
||||
$userProfile = new User\Profile();
|
||||
$userProfile->identifier = @$data->get('id');
|
||||
$userProfile->displayName = @$data->get('properties')->nickname;
|
||||
$userProfile->photoURL = @$data->get('properties')->thumbnail_image;
|
||||
//$email = @ $data->properties->kaccount_email; // v1 version
|
||||
|
||||
$phone_number = @$data->get('kakao_account')->phone_number; // 010-1111-2222의 경우, +82 10-1111-2222
|
||||
if ($phone_number) {
|
||||
// 국제번호 를 0 으로 변경
|
||||
if (strpos($phone_number, '+82 ') === 0) $phone_number = str_replace('+82 ', '0', $phone_number);
|
||||
$userProfile->phone = preg_replace('/[^0-9]+/', '', $phone_number);
|
||||
}
|
||||
|
||||
$birthyear = @ $data->get('kakao_account')->birthyear; // 1990
|
||||
if ($birthyear) {
|
||||
$userProfile->birthYear = $birthyear;
|
||||
$userProfile->age = date('Y') - $birthyear + 1;
|
||||
}
|
||||
|
||||
$birthday = @ $data->get('kakao_account')->birthday; // 0708
|
||||
if ($birthday) {
|
||||
list($_m, $_d) = str_split($birthday, 2);
|
||||
$userProfile->birthMonth = ltrim($_m, '0');
|
||||
$userProfile->birthDay = ltrim($_d, '0');
|
||||
}
|
||||
|
||||
$nickname = @ $data->get('kakao_account')->profile->nickname;
|
||||
if (!$userProfile->displayName && $nickname) {
|
||||
$userProfile->displayName = $nickname;
|
||||
}
|
||||
|
||||
$email = @ $data->get('kakao_account')->email; // v2 version
|
||||
|
||||
if( $email ){
|
||||
$userProfile->email = $email;
|
||||
}
|
||||
|
||||
// $userProfile->sid = get_social_convert_id( $userProfile->identifier, $this->providerId );
|
||||
// $userProfile->sid = $userProfile->identifier.'.'.$this->providerId;
|
||||
// $this->httpClient->request("https://kapi.kakao.com/v1/user/logout", "POST", [], $requestHeader);
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* LinkedIn OAuth2 provider adapter.
|
||||
*/
|
||||
class LinkedIn extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'r_liteprofile r_emailaddress w_member_social';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.linkedin.com/v2/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://www.linkedin.com/oauth/v2/authorization';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://www.linkedin.com/oauth/v2/accessToken';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://docs.microsoft.com/en-us/linkedin/shared/authentication/authentication';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$fields = [
|
||||
'id',
|
||||
'firstName',
|
||||
'lastName',
|
||||
'profilePicture(displayImage~:playableStreams)',
|
||||
];
|
||||
|
||||
|
||||
$response = $this->apiRequest('me', 'GET', ['projection' => '(' . implode(',', $fields) . ')']);
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
// Handle localized names.
|
||||
$userProfile->firstName = $data
|
||||
->filter('firstName')
|
||||
->filter('localized')
|
||||
->get($this->getPreferredLocale($data, 'firstName'));
|
||||
|
||||
$userProfile->lastName = $data
|
||||
->filter('lastName')
|
||||
->filter('localized')
|
||||
->get($this->getPreferredLocale($data, 'lastName'));
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->email = $this->getUserEmail();
|
||||
$userProfile->emailVerified = $userProfile->email;
|
||||
$userProfile->displayName = trim($userProfile->firstName . ' ' . $userProfile->lastName);
|
||||
|
||||
$photo_elements = $data
|
||||
->filter('profilePicture')
|
||||
->filter('displayImage~')
|
||||
->get('elements');
|
||||
$userProfile->photoURL = $this->getUserPhotoUrl($photo_elements);
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a user photo.
|
||||
*
|
||||
* @param array $elements
|
||||
* List of file identifiers related to this artifact.
|
||||
*
|
||||
* @return string
|
||||
* The user photo URL.
|
||||
*
|
||||
* @see https://docs.microsoft.com/en-us/linkedin/shared/references/v2/profile/profile-picture
|
||||
*/
|
||||
public function getUserPhotoUrl($elements)
|
||||
{
|
||||
if (is_array($elements)) {
|
||||
// Get the largest picture from the list which is the last one.
|
||||
$element = end($elements);
|
||||
if (!empty($element->identifiers)) {
|
||||
return reset($element->identifiers)->identifier;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an email address of user.
|
||||
*
|
||||
* @return string
|
||||
* The user email address.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getUserEmail()
|
||||
{
|
||||
$response = $this->apiRequest('emailAddress', 'GET', [
|
||||
'q' => 'members',
|
||||
'projection' => '(elements*(handle~))',
|
||||
]);
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
foreach ($data->filter('elements')->toArray() as $element) {
|
||||
$item = new Data\Collection($element);
|
||||
|
||||
if ($email = $item->filter('handle~')->get('emailAddress')) {
|
||||
return $email;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @see https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/share-on-linkedin
|
||||
*/
|
||||
public function setUserStatus($status, $userID = null)
|
||||
{
|
||||
if (is_string($status)) {
|
||||
$status = [
|
||||
'author' => 'urn:li:person:' . $userID,
|
||||
'lifecycleState' => 'PUBLISHED',
|
||||
'specificContent' => [
|
||||
'com.linkedin.ugc.ShareContent' => [
|
||||
'shareCommentary' => [
|
||||
'text' => $status,
|
||||
],
|
||||
'shareMediaCategory' => 'NONE',
|
||||
],
|
||||
],
|
||||
'visibility' => [
|
||||
'com.linkedin.ugc.MemberNetworkVisibility' => 'PUBLIC',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
'x-li-format' => 'json',
|
||||
'X-Restli-Protocol-Version' => '2.0.0',
|
||||
];
|
||||
|
||||
$response = $this->apiRequest("ugcPosts", 'POST', $status, $headers);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a preferred locale for given field.
|
||||
*
|
||||
* @param \Hybridauth\Data\Collection $data
|
||||
* A data to check.
|
||||
* @param string $field_name
|
||||
* A field name to perform.
|
||||
*
|
||||
* @return string
|
||||
* A field locale.
|
||||
*/
|
||||
protected function getPreferredLocale($data, $field_name)
|
||||
{
|
||||
$locale = $data->filter($field_name)->filter('preferredLocale');
|
||||
if ($locale) {
|
||||
return $locale->get('language') . '_' . $locale->get('country');
|
||||
}
|
||||
|
||||
return 'en_US';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data\Collection;
|
||||
use Hybridauth\User\Profile;
|
||||
|
||||
/**
|
||||
* Mailru OAuth2 provider adapter.
|
||||
*/
|
||||
class Mailru extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'http://www.appsmail.ru/platform/api';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://connect.mail.ru/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://connect.mail.ru/oauth/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = ''; // Not available
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$params = [
|
||||
'app_id' => $this->clientId,
|
||||
'method' => 'users.getInfo',
|
||||
'secure' => 1,
|
||||
'session_key' => $this->getStoredData('access_token'),
|
||||
];
|
||||
$sign = md5(http_build_query($params, null, '') . $this->clientSecret);
|
||||
|
||||
$param = [
|
||||
'app_id' => $this->clientId,
|
||||
'method' => 'users.getInfo',
|
||||
'secure' => 1,
|
||||
'session_key' => $this->getStoredData('access_token'),
|
||||
'sig' => $sign,
|
||||
];
|
||||
|
||||
$response = $this->apiRequest('', 'GET', $param);
|
||||
|
||||
$data = new Collection($response[0]);
|
||||
|
||||
if (!$data->exists('uid')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('uid');
|
||||
$userProfile->email = $data->get('email');
|
||||
$userProfile->firstName = $data->get('first_name');
|
||||
$userProfile->lastName = $data->get('last_name');
|
||||
$userProfile->displayName = $data->get('nick');
|
||||
$userProfile->photoURL = $data->get('pic');
|
||||
$userProfile->profileURL = $data->get('link');
|
||||
$userProfile->gender = $data->get('sex');
|
||||
$userProfile->age = $data->get('age');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Medium OAuth2 provider adapter.
|
||||
*/
|
||||
class Medium extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'basicProfile';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.medium.com/v1/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://medium.com/m/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://api.medium.com/v1/tokens';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://github.com/Medium/medium-api-docs';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
if ($this->isRefreshTokenAvailable()) {
|
||||
$this->tokenRefreshParameters += [
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* See: https://github.com/Medium/medium-api-docs#getting-the-authenticated-users-details
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('me');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
$data = $data->filter('data');
|
||||
|
||||
$full_name = explode(' ', $data->get('name'));
|
||||
if (count($full_name) < 2) {
|
||||
$full_name[1] = '';
|
||||
}
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('username');
|
||||
$userProfile->profileURL = $data->get('imageUrl');
|
||||
$userProfile->firstName = $full_name[0];
|
||||
$userProfile->lastName = $full_name[1];
|
||||
$userProfile->profileURL = $data->get('url');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Microsoft Graph OAuth2 provider adapter.
|
||||
*
|
||||
* Create an "Azure Active Directory" resource at https://portal.azure.com/
|
||||
* (not from the Visual Studio site).
|
||||
*
|
||||
* The "Supported account types" choice maps to the 'tenant' setting, see "Authority" @
|
||||
* https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-client-application-configuration
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $config = [
|
||||
* 'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
* 'keys' => ['id' => '', 'secret' => ''],
|
||||
* 'tenant' => 'user',
|
||||
* // ^ May be 'common', 'organizations' or 'consumers' or a specific tenant ID or a domain
|
||||
* ];
|
||||
*
|
||||
* $adapter = new Hybridauth\Provider\MicrosoftGraph($config);
|
||||
*
|
||||
* try {
|
||||
* $adapter->authenticate();
|
||||
*
|
||||
* $userProfile = $adapter->getUserProfile();
|
||||
* $tokens = $adapter->getAccessToken();
|
||||
* } catch (\Exception $e) {
|
||||
* echo $e->getMessage() ;
|
||||
* }
|
||||
*/
|
||||
class MicrosoftGraph extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'openid user.read contacts.read';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://graph.microsoft.com/v1.0/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developer.microsoft.com/en-us/graph/docs/concepts/php';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$tenant = $this->config->get('tenant');
|
||||
if (!empty($tenant)) {
|
||||
$adjustedEndpoints = [
|
||||
'authorize_url' => str_replace('/common/', '/' . $tenant . '/', $this->authorizeUrl),
|
||||
'access_token_url' => str_replace('/common/', '/' . $tenant . '/', $this->accessTokenUrl),
|
||||
];
|
||||
|
||||
$this->setApiEndpoints($adjustedEndpoints);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('me');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('displayName');
|
||||
$userProfile->firstName = $data->get('givenName');
|
||||
$userProfile->lastName = $data->get('surname');
|
||||
$userProfile->language = $data->get('preferredLanguage');
|
||||
|
||||
$userProfile->phone = $data->get('mobilePhone');
|
||||
if (empty($userProfile->phone)) {
|
||||
$businessPhones = $data->get('businessPhones');
|
||||
if (isset($businessPhones[0])) {
|
||||
$userProfile->phone = $businessPhones[0];
|
||||
}
|
||||
}
|
||||
|
||||
$userProfile->email = $data->get('mail');
|
||||
if (empty($userProfile->email)) {
|
||||
$email = $data->get('userPrincipalName');
|
||||
if (strpos($email, '@') !== false) {
|
||||
$userProfile->email = $email;
|
||||
}
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserContacts()
|
||||
{
|
||||
$apiUrl = 'me/contacts?$top=50';
|
||||
$contacts = [];
|
||||
|
||||
do {
|
||||
$response = $this->apiRequest($apiUrl);
|
||||
$data = new Data\Collection($response);
|
||||
if (!$data->exists('value')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
foreach ($data->filter('value')->toArray() as $entry) {
|
||||
$entry = new Data\Collection($entry);
|
||||
$userContact = new User\Contact();
|
||||
$userContact->identifier = $entry->get('id');
|
||||
$userContact->displayName = $entry->get('displayName');
|
||||
$emailAddresses = $entry->get('emailAddresses');
|
||||
if (!empty($emailAddresses)) {
|
||||
$userContact->email = $emailAddresses[0]->address;
|
||||
}
|
||||
// only add to collection if we have usefull data
|
||||
if (!empty($userContact->displayName) || !empty($userContact->email)) {
|
||||
$contacts[] = $userContact;
|
||||
}
|
||||
}
|
||||
|
||||
if ($data->exists('@odata.nextLink')) {
|
||||
$apiUrl = $data->get('@odata.nextLink');
|
||||
|
||||
$pagedList = true;
|
||||
} else {
|
||||
$pagedList = false;
|
||||
}
|
||||
} while ($pagedList);
|
||||
|
||||
return $contacts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Exception\InvalidArgumentException;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
class Naver extends OAuth2
|
||||
{
|
||||
protected $scope = '';
|
||||
protected $apiBaseUrl = 'https://apis.naver.com/nidlogin/';
|
||||
protected $authorizeUrl = 'https://nid.naver.com/oauth2.0/authorize';
|
||||
protected $accessTokenUrl = 'https://nid.naver.com/oauth2.0/token';
|
||||
protected $apiDocumentation = 'https://developers.kakao.com/docs/latest/ko/kakaologin/common';
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* load the user profile
|
||||
*/
|
||||
function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest("https://openapi.naver.com/v1/nid/me");
|
||||
// $response = $this->httpClient->request("https://openapi.naver.com/v1/nid/me");
|
||||
$response = new Data\Collection($response);
|
||||
$data = array();
|
||||
if ( $response->get('resultcode') == '00' ) {
|
||||
foreach ($response->get('response') as $k => $v) {
|
||||
if(!is_array($v)) $data[(string)$k] = (string) $v;
|
||||
}
|
||||
} else {
|
||||
throw new UnexpectedApiResponseException("User profile request failed! {$this->providerId} returned an invalid response.", 6);
|
||||
}
|
||||
# store the user profile.
|
||||
$userProfile = new User\Profile();
|
||||
//$this->user->profile->identifier = (array_key_exists('enc_id',$data))?$data['enc_id']:"";
|
||||
$userProfile->identifier = (array_key_exists('id',$data))?@$data['id']:"";
|
||||
$userProfile->age = (array_key_exists('age',$data))?@$data['age']:"";
|
||||
$userProfile->displayName = (array_key_exists('name', $data)) ? @$data['name'] : "";
|
||||
$userProfile->phone = (array_key_exists('mobile', $data)) ? @$data['mobile'] : "";
|
||||
$userProfile->birthYear = (array_key_exists('birthyear', $data)) ? @$data['birthyear'] : "";
|
||||
$userProfile->age = date('Y') - @$data['birthyear'] + 1;
|
||||
if(array_key_exists('birthday', $data))
|
||||
list($userProfile->birthDay, $userProfile->birthMonth) = @explode("-",$data['birthday']);
|
||||
$userProfile->email = (array_key_exists('email',$data))?@$data['email']:"";
|
||||
$userProfile->gender = (array_key_exists('gender',$data))?@$data['gender']:"";
|
||||
$userProfile->photoURL = (array_key_exists('profile_image',$data))?@$data['profile_image']:"";
|
||||
|
||||
// $userProfile->sid = get_social_convert_id( $userProfile->identifier, $this->providerId );
|
||||
// $userProfile->sid = $userProfile->identifier.'.'.$this->providerId;
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* ORCID OAuth2 provider adapter.
|
||||
*/
|
||||
class ORCID extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = '/authenticate';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://pub.orcid.org/v2.1/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://orcid.org/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://orcid.org/oauth/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://members.orcid.org/api/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateAccessTokenExchange($response)
|
||||
{
|
||||
$data = parent::validateAccessTokenExchange($response);
|
||||
$this->storeData('orcid', $data->get('orcid'));
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest($this->getStoredData('orcid') . '/record');
|
||||
$data = new Data\Collection($response['record']);
|
||||
|
||||
if (!$data->exists('orcid-identifier')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$profile = new User\Profile();
|
||||
|
||||
$profile = $this->getDetails($profile, $data);
|
||||
$profile = $this->getBiography($profile, $data);
|
||||
$profile = $this->getWebsite($profile, $data);
|
||||
$profile = $this->getName($profile, $data);
|
||||
$profile = $this->getEmail($profile, $data);
|
||||
$profile = $this->getLanguage($profile, $data);
|
||||
$profile = $this->getAddress($profile, $data);
|
||||
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile details.
|
||||
*
|
||||
* @param User\Profile $profile
|
||||
* @param Data\Collection $data
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function getDetails(User\Profile $profile, Data\Collection $data)
|
||||
{
|
||||
$data = new Data\Collection($data->get('orcid-identifier'));
|
||||
|
||||
$profile->identifier = $data->get('path');
|
||||
$profile->profileURL = $data->get('uri');
|
||||
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile biography.
|
||||
*
|
||||
* @param User\Profile $profile
|
||||
* @param Data\Collection $data
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function getBiography(User\Profile $profile, Data\Collection $data)
|
||||
{
|
||||
$data = new Data\Collection($data->get('person'));
|
||||
$data = new Data\Collection($data->get('biography'));
|
||||
|
||||
$profile->description = $data->get('content');
|
||||
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile website.
|
||||
*
|
||||
* @param User\Profile $profile
|
||||
* @param Data\Collection $data
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function getWebsite(User\Profile $profile, Data\Collection $data)
|
||||
{
|
||||
$data = new Data\Collection($data->get('person'));
|
||||
$data = new Data\Collection($data->get('researcher-urls'));
|
||||
$data = new Data\Collection($data->get('researcher-url'));
|
||||
|
||||
if ($data->exists(0)) {
|
||||
$data = new Data\Collection($data->get(0));
|
||||
}
|
||||
|
||||
$profile->webSiteURL = $data->get('url');
|
||||
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile name.
|
||||
*
|
||||
* @param User\Profile $profile
|
||||
* @param Data\Collection $data
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function getName(User\Profile $profile, Data\Collection $data)
|
||||
{
|
||||
$data = new Data\Collection($data->get('person'));
|
||||
$data = new Data\Collection($data->get('name'));
|
||||
|
||||
if ($data->exists('credit-name')) {
|
||||
$profile->displayName = $data->get('credit-name');
|
||||
} else {
|
||||
$profile->displayName = $data->get('given-names') . ' ' . $data->get('family-name');
|
||||
}
|
||||
|
||||
$profile->firstName = $data->get('given-names');
|
||||
$profile->lastName = $data->get('family-name');
|
||||
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile email.
|
||||
*
|
||||
* @param User\Profile $profile
|
||||
* @param Data\Collection $data
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function getEmail(User\Profile $profile, Data\Collection $data)
|
||||
{
|
||||
$data = new Data\Collection($data->get('person'));
|
||||
$data = new Data\Collection($data->get('emails'));
|
||||
$data = new Data\Collection($data->get('email'));
|
||||
|
||||
if (!$data->exists(0)) {
|
||||
$email = $data;
|
||||
} else {
|
||||
$email = new Data\Collection($data->get(0));
|
||||
|
||||
$i = 1;
|
||||
while ($email->get('@attributes')['primary'] == 'false') {
|
||||
$email = new Data\Collection($data->get($i));
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($email->get('@attributes')['primary'] == 'false') {
|
||||
return $profile;
|
||||
}
|
||||
|
||||
$profile->email = $email->get('email');
|
||||
|
||||
if ($email->get('@attributes')['verified'] == 'true') {
|
||||
$profile->emailVerified = $email->get('email');
|
||||
}
|
||||
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile language.
|
||||
*
|
||||
* @param User\Profile $profile
|
||||
* @param Data\Collection $data
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function getLanguage(User\Profile $profile, Data\Collection $data)
|
||||
{
|
||||
$data = new Data\Collection($data->get('preferences'));
|
||||
|
||||
$profile->language = $data->get('locale');
|
||||
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile address.
|
||||
*
|
||||
* @param User\Profile $profile
|
||||
* @param Data\Collection $data
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function getAddress(User\Profile $profile, Data\Collection $data)
|
||||
{
|
||||
$data = new Data\Collection($data->get('person'));
|
||||
$data = new Data\Collection($data->get('addresses'));
|
||||
$data = new Data\Collection($data->get('address'));
|
||||
|
||||
if ($data->exists(0)) {
|
||||
$data = new Data\Collection($data->get(0));
|
||||
}
|
||||
|
||||
$profile->country = $data->get('country');
|
||||
|
||||
return $profile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Odnoklassniki OAuth2 provider adapter.
|
||||
*/
|
||||
class Odnoklassniki extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.ok.ru/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://connect.ok.ru/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://api.ok.ru/oauth/token.do';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://apiok.ru/en/ext/oauth/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
if ($this->isRefreshTokenAvailable()) {
|
||||
$this->tokenRefreshParameters += [
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$fields = array(
|
||||
'uid', 'locale', 'first_name', 'last_name', 'name', 'gender', 'age', 'birthday',
|
||||
'has_email', 'current_status', 'current_status_id', 'current_status_date', 'online',
|
||||
'photo_id', 'pic_1', 'pic_2', 'pic1024x768', 'location', 'email'
|
||||
);
|
||||
|
||||
$sig = md5(
|
||||
'application_key=' . $this->config->get('keys')['key'] .
|
||||
'fields=' . implode(',', $fields) .
|
||||
'method=users.getCurrentUser' .
|
||||
md5($this->getStoredData('access_token') . $this->config->get('keys')['secret'])
|
||||
);
|
||||
|
||||
$parameters = [
|
||||
'access_token' => $this->getStoredData('access_token'),
|
||||
'application_key' => $this->config->get('keys')['key'],
|
||||
'method' => 'users.getCurrentUser',
|
||||
'fields' => implode(',', $fields),
|
||||
'sig' => $sig,
|
||||
];
|
||||
|
||||
$response = $this->apiRequest('fb.do', 'GET', $parameters);
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('uid')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
|
||||
$userProfile->identifier = $data->get('uid');
|
||||
$userProfile->email = $data->get('email');
|
||||
$userProfile->firstName = $data->get('first_name');
|
||||
$userProfile->lastName = $data->get('last_name');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->photoURL = $data->get('pic1024x768');
|
||||
$userProfile->profileURL = 'http://ok.ru/profile/' . $data->get('uid');
|
||||
|
||||
// Handle birthday.
|
||||
if ($data->get('birthday')) {
|
||||
$bday = explode('-', $data->get('birthday'));
|
||||
$userProfile->birthDay = (int)$bday[0];
|
||||
$userProfile->birthMonth = (int)$bday[1];
|
||||
$userProfile->birthYear = (int)$bday[2];
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter;
|
||||
|
||||
/**
|
||||
* Generic OpenID providers adapter.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $config = [
|
||||
* 'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
*
|
||||
* // authenticate with Yahoo openid
|
||||
* 'openid_identifier' => 'https://open.login.yahooapis.com/openid20/www.yahoo.com/xrds'
|
||||
*
|
||||
* // authenticate with stackexchange network openid
|
||||
* // 'openid_identifier' => 'https://openid.stackexchange.com/',
|
||||
*
|
||||
* // authenticate with Steam openid
|
||||
* // 'openid_identifier' => 'http://steamcommunity.com/openid',
|
||||
*
|
||||
* // etc.
|
||||
* ];
|
||||
*
|
||||
* $adapter = new Hybridauth\Provider\OpenID($config);
|
||||
*
|
||||
* try {
|
||||
* $adapter->authenticate();
|
||||
*
|
||||
* $userProfile = $adapter->getUserProfile();
|
||||
* } catch (\Exception $e) {
|
||||
* echo $e->getMessage() ;
|
||||
* }
|
||||
*/
|
||||
class OpenID extends Adapter\OpenID
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2020 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\User;
|
||||
use Hybridauth\User\Profile;
|
||||
use Hybridauth\Data\Collection;
|
||||
|
||||
/**
|
||||
* Patreon OAuth2 provider adapter.
|
||||
*/
|
||||
class Patreon extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'identity identity[email]';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://www.patreon.com/api';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://www.patreon.com/oauth2/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://www.patreon.com/api/oauth2/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://docs.patreon.com/#oauth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
if ($this->isRefreshTokenAvailable()) {
|
||||
$this->tokenRefreshParameters += [
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('oauth2/v2/identity', 'GET', [
|
||||
'fields[user]' => 'created,first_name,last_name,email,full_name,is_email_verified,thumb_url,url',
|
||||
]);
|
||||
|
||||
$collection = new Collection($response);
|
||||
if (!$collection->exists('data')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new Profile();
|
||||
|
||||
$data = $collection->filter('data');
|
||||
$attributes = $data->filter('attributes');
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->email = $attributes->get('email');
|
||||
$userProfile->firstName = $attributes->get('first_name');
|
||||
$userProfile->lastName = $attributes->get('last_name');
|
||||
$userProfile->displayName = $attributes->get('full_name') ?: $data->get('id');
|
||||
$userProfile->photoURL = $attributes->get('thumb_url');
|
||||
$userProfile->profileURL = $attributes->get('url');
|
||||
|
||||
$userProfile->emailVerified = $attributes->get('is_email_verified') ? $userProfile->email : '';
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts are defined as Patrons here
|
||||
*/
|
||||
public function getUserContacts()
|
||||
{
|
||||
$campaignId = $this->config->get('campaign_id') ?: null;
|
||||
$tierFilter = $this->config->get('tier_filter') ?: null;
|
||||
|
||||
$campaigns = [];
|
||||
if ($campaignId === null) {
|
||||
$campaignsUrl = 'oauth2/v2/campaigns';
|
||||
do {
|
||||
$response = $this->apiRequest($campaignsUrl);
|
||||
$data = new Collection($response);
|
||||
|
||||
if (!$data->exists('data')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
foreach ($data->filter('data')->toArray() as $item) {
|
||||
$campaign = new Collection($item);
|
||||
$campaigns[] = $campaign->get('id');
|
||||
}
|
||||
|
||||
if ($data->filter('links')->exists('next')) {
|
||||
$campaignsUrl = $data->filter('links')->get('next');
|
||||
|
||||
$pagedList = true;
|
||||
} else {
|
||||
$pagedList = false;
|
||||
}
|
||||
} while ($pagedList);
|
||||
} else {
|
||||
$campaigns[] = $campaignId;
|
||||
}
|
||||
|
||||
$contacts = [];
|
||||
|
||||
foreach ($campaigns as $campaignId) {
|
||||
$params = [
|
||||
'include' => 'currently_entitled_tiers',
|
||||
'fields[member]' => 'full_name,patron_status,email',
|
||||
'fields[tier]' => 'title',
|
||||
];
|
||||
$membersUrl = 'oauth2/v2/campaigns/' . $campaignId . '/members?' . http_build_query($params);
|
||||
|
||||
do {
|
||||
$response = $this->apiRequest($membersUrl);
|
||||
|
||||
$data = new Collection($response);
|
||||
|
||||
if (!$data->exists('data')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$tierTitles = [];
|
||||
|
||||
foreach ($data->filter('included')->toArray() as $item) {
|
||||
$includedItem = new Collection($item);
|
||||
if ($includedItem->get('type') == 'tier') {
|
||||
$tierTitles[$includedItem->get('id')] = $includedItem->filter('attributes')->get('title');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($data->filter('data')->toArray() as $item) {
|
||||
$member = new Collection($item);
|
||||
|
||||
if ($member->filter('attributes')->get('patron_status') == 'active_patron') {
|
||||
$tiers = [];
|
||||
$tierObs = $member->filter('relationships')->filter('currently_entitled_tiers')->get('data');
|
||||
foreach ($tierObs as $item) {
|
||||
$tier = new Collection($item);
|
||||
$tierId = $tier->get('id');
|
||||
$tiers[] = $tierTitles[$tierId];
|
||||
}
|
||||
|
||||
if (($tierFilter === null) || (in_array($tierFilter, $tiers))) {
|
||||
$userContact = new User\Contact();
|
||||
|
||||
$userContact->identifier = $member->get('id');
|
||||
$userContact->email = $member->filter('attributes')->get('email');
|
||||
$userContact->displayName = $member->filter('attributes')->get('full_name');
|
||||
$userContact->description = json_encode($tiers);
|
||||
|
||||
$contacts[] = $userContact;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($data->filter('links')->exists('next')) {
|
||||
$membersUrl = $data->filter('links')->get('next');
|
||||
|
||||
$pagedList = true;
|
||||
} else {
|
||||
$pagedList = false;
|
||||
}
|
||||
} while ($pagedList);
|
||||
}
|
||||
|
||||
return $contacts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Paypal OAuth2 provider adapter.
|
||||
*/
|
||||
class Paypal extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'openid profile email address';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.paypal.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://www.paypal.com/signin/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://api.paypal.com/v1/oauth2/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developer.paypal.com/docs/api/overview/#';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->AuthorizeUrlParameters += [
|
||||
'flowEntry' => 'static'
|
||||
];
|
||||
|
||||
$this->tokenExchangeHeaders = [
|
||||
'Authorization' => 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret)
|
||||
];
|
||||
|
||||
$this->tokenRefreshHeaders = [
|
||||
'Authorization' => 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* See: https://developer.paypal.com/docs/api/identity/v1/
|
||||
* See: https://developer.paypal.com/docs/connect-with-paypal/integrate/
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
];
|
||||
|
||||
$parameters = [
|
||||
'schema' => 'paypalv1.1'
|
||||
];
|
||||
|
||||
$response = $this->apiRequest('v1/identity/oauth2/userinfo', 'GET', $parameters, $headers);
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('user_id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
$userProfile->identifier = $data->get('user_id');
|
||||
$userProfile->firstName = $data->get('given_name');
|
||||
$userProfile->lastName = $data->get('family_name');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->address = $data->filter('address')->get('street_address');
|
||||
$userProfile->city = $data->filter('address')->get('locality');
|
||||
$userProfile->country = $data->filter('address')->get('country');
|
||||
$userProfile->region = $data->filter('address')->get('region');
|
||||
$userProfile->zip = $data->filter('address')->get('postal_code');
|
||||
|
||||
$emails = $data->filter('emails')->toArray();
|
||||
foreach ($emails as $email) {
|
||||
$email = new Data\Collection($email);
|
||||
if ($email->get('confirmed')) {
|
||||
$userProfile->emailVerified = $email->get('value');
|
||||
}
|
||||
|
||||
if ($email->get('primary')) {
|
||||
$userProfile->email = $email->get('value');
|
||||
}
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OpenID;
|
||||
use Hybridauth\HttpClient;
|
||||
|
||||
/**
|
||||
* PayPal OpenID provider adapter.
|
||||
*/
|
||||
class PaypalOpenID extends OpenID
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $openidIdentifier = 'https://www.sandbox.paypal.com/webapps/auth/server';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developer.paypal.com/docs/connect-with-paypal/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticateBegin()
|
||||
{
|
||||
$this->openIdClient->identity = $this->openidIdentifier;
|
||||
$this->openIdClient->returnUrl = $this->callback;
|
||||
$this->openIdClient->required = [
|
||||
'namePerson/prefix',
|
||||
'namePerson/first',
|
||||
'namePerson/last',
|
||||
'namePerson/middle',
|
||||
'namePerson/suffix',
|
||||
'namePerson/friendly',
|
||||
'person/guid',
|
||||
'birthDate/birthYear',
|
||||
'birthDate/birthMonth',
|
||||
'birthDate/birthday',
|
||||
'gender',
|
||||
'language/pref',
|
||||
'contact/phone/default',
|
||||
'contact/phone/home',
|
||||
'contact/phone/business',
|
||||
'contact/phone/cell',
|
||||
'contact/phone/fax',
|
||||
'contact/postaladdress/home',
|
||||
'contact/postaladdressadditional/home',
|
||||
'contact/city/home',
|
||||
'contact/state/home',
|
||||
'contact/country/home',
|
||||
'contact/postalcode/home',
|
||||
'contact/postaladdress/business',
|
||||
'contact/postaladdressadditional/business',
|
||||
'contact/city/business',
|
||||
'contact/state/business',
|
||||
'contact/country/business',
|
||||
'contact/postalcode/business',
|
||||
'company/name',
|
||||
'company/title',
|
||||
];
|
||||
|
||||
HttpClient\Util::redirect($this->openIdClient->authUrl());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Pinterest OAuth2 provider adapter.
|
||||
*/
|
||||
class Pinterest extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'read_public';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.pinterest.com/v1/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://api.pinterest.com/oauth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://api.pinterest.com/v1/oauth/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developers.pinterest.com/docs/api/overview/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('me');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
$data = $data->filter('data');
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->description = $data->get('bio');
|
||||
$userProfile->photoURL = $data->get('image');
|
||||
$userProfile->displayName = $data->get('username');
|
||||
$userProfile->firstName = $data->get('first_name');
|
||||
$userProfile->lastName = $data->get('last_name');
|
||||
$userProfile->profileURL = "https://pinterest.com/{$data->get('username')}";
|
||||
|
||||
$userProfile->data = (array)$data->get('counts');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User\Profile;
|
||||
|
||||
/**
|
||||
* Tencent QQ International OAuth2 provider adapter.
|
||||
*/
|
||||
class QQ extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'get_user_info';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://graph.qq.com/oauth2.0/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://graph.qq.com/oauth2.0/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://graph.qq.com/oauth2.0/token';
|
||||
|
||||
/**
|
||||
* {@ịnheritdoc}
|
||||
*/
|
||||
protected $accessTokenInfoUrl = 'https://graph.qq.com/oauth2.0/me';
|
||||
|
||||
/**
|
||||
* User Information Endpoint
|
||||
* @var string
|
||||
*/
|
||||
protected $accessUserInfo = 'https://graph.qq.com/user/get_user_info';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $tokenExchangeMethod = 'GET';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $tokenRefreshMethod = 'GET';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = ''; // Not available
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
if ($this->isRefreshTokenAvailable()) {
|
||||
$this->tokenRefreshParameters += [
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
];
|
||||
}
|
||||
|
||||
$this->apiRequestParameters = [
|
||||
'access_token' => $this->getStoredData('access_token')
|
||||
];
|
||||
|
||||
$this->apiRequestHeaders = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateAccessTokenExchange($response)
|
||||
{
|
||||
$collection = parent::validateAccessTokenExchange($response);
|
||||
|
||||
$resp = $this->apiRequest($this->accessTokenInfoUrl);
|
||||
$resp = key($resp);
|
||||
|
||||
$len = strlen($resp);
|
||||
$res = substr($resp, 10, $len - 14);
|
||||
|
||||
$response = (new Data\Parser())->parse($res);
|
||||
|
||||
if (!isset($response->openid)) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$this->storeData('openid', $response->openid);
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$openid = $this->getStoredData('openid');
|
||||
|
||||
$userRequestParameters = [
|
||||
'oauth_consumer_key' => $this->clientId,
|
||||
'openid' => $openid,
|
||||
'format' => 'json'
|
||||
];
|
||||
|
||||
$response = $this->apiRequest($this->accessUserInfo, 'GET', $userRequestParameters);
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if ($data->get('ret') < 0) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an error: ' . $data->get('msg'));
|
||||
}
|
||||
|
||||
$userProfile = new Profile();
|
||||
|
||||
$userProfile->identifier = $openid;
|
||||
$userProfile->displayName = $data->get('nickname');
|
||||
$userProfile->photoURL = $data->get('figureurl_2');
|
||||
$userProfile->gender = $data->get('gender');
|
||||
$userProfile->region = $data->get('province');
|
||||
$userProfile->city = $data->get('city');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Reddit OAuth2 provider adapter.
|
||||
*/
|
||||
class Reddit extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'identity';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://oauth.reddit.com/api/v1/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://ssl.reddit.com/api/v1/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://ssl.reddit.com/api/v1/access_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://github.com/reddit/reddit/wiki/OAuth2';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->AuthorizeUrlParameters += [
|
||||
'duration' => 'permanent'
|
||||
];
|
||||
|
||||
$this->tokenExchangeParameters = [
|
||||
'client_id' => $this->clientId,
|
||||
'grant_type' => 'authorization_code',
|
||||
'redirect_uri' => $this->callback
|
||||
];
|
||||
|
||||
$this->tokenExchangeHeaders = [
|
||||
'Authorization' => 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret)
|
||||
];
|
||||
|
||||
$this->tokenRefreshHeaders = $this->tokenExchangeHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('me.json');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
$userProfile->profileURL = 'https://www.reddit.com/user/' . $data->get('name') . '/';
|
||||
$userProfile->photoURL = $data->get('icon_img');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2019 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Slack OAuth2 provider adapter.
|
||||
*/
|
||||
class Slack extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'identity.basic identity.email identity.avatar';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://slack.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://slack.com/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://slack.com/api/oauth.access';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://api.slack.com/docs/sign-in-with-slack';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('api/users.identity');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('ok') || !$data->get('ok')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->filter('user')->get('id');
|
||||
$userProfile->displayName = $data->filter('user')->get('name');
|
||||
$userProfile->email = $data->filter('user')->get('email');
|
||||
$userProfile->photoURL = $this->findLargestImage($data);
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url of the image with the highest resolution in the user
|
||||
* object.
|
||||
*
|
||||
* Slack sends multiple image urls with different resolutions. As they make
|
||||
* no guarantees which resolutions will be included we have to search all
|
||||
* <code>image_*</code> properties for the one with the highest resolution.
|
||||
* The resolution is attached to the property name such as
|
||||
* <code>image_32</code> or <code>image_192</code>.
|
||||
*
|
||||
* @param Data\Collection $data response object as returned by
|
||||
* <code>api/users.identity</code>
|
||||
*
|
||||
* @return string|null the value of the <code>image_*</code> property with
|
||||
* the highest resolution.
|
||||
*/
|
||||
private function findLargestImage(Data\Collection $data)
|
||||
{
|
||||
$maxSize = 0;
|
||||
foreach ($data->filter('user')->properties() as $property) {
|
||||
if (preg_match('/^image_(\d+)$/', $property, $matches) === 1) {
|
||||
$availableSize = (int)$matches[1];
|
||||
if ($maxSize < $availableSize) {
|
||||
$maxSize = $availableSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($maxSize > 0) {
|
||||
return $data->filter('user')->get('image_' . $maxSize);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Spotify OAuth2 provider adapter.
|
||||
*/
|
||||
class Spotify extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'user-read-email';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $apiBaseUrl = 'https://api.spotify.com/v1/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $authorizeUrl = 'https://accounts.spotify.com/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://accounts.spotify.com/api/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developer.spotify.com/documentation/general/guides/authorization-guide/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('me');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->displayName = $data->get('display_name');
|
||||
$userProfile->email = $data->get('email');
|
||||
$userProfile->emailVerified = $data->get('email');
|
||||
$userProfile->profileURL = $data->filter('external_urls')->get('spotify');
|
||||
$userProfile->photoURL = $data->filter('images')->get('url');
|
||||
$userProfile->country = $data->get('country');
|
||||
|
||||
if ($data->exists('birthdate')) {
|
||||
$this->fetchBirthday($userProfile, $data->get('birthdate'));
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch use birthday
|
||||
*
|
||||
* @param User\Profile $userProfile
|
||||
* @param $birthday
|
||||
*
|
||||
* @return User\Profile
|
||||
*/
|
||||
protected function fetchBirthday(User\Profile $userProfile, $birthday)
|
||||
{
|
||||
$result = (new Data\Parser())->parseBirthday($birthday, '-');
|
||||
|
||||
$userProfile->birthDay = (int)$result[0];
|
||||
$userProfile->birthMonth = (int)$result[1];
|
||||
$userProfile->birthYear = (int)$result[2];
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* StackExchange OAuth2 provider adapter.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $config = [
|
||||
* 'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
* 'keys' => ['id' => '', 'secret' => ''],
|
||||
* 'site' => 'stackoverflow' // required parameter to call getUserProfile()
|
||||
* 'api_key' => '...' // that thing to receive a higher request quota.
|
||||
* ];
|
||||
*
|
||||
* $adapter = new Hybridauth\Provider\StackExchange($config);
|
||||
*
|
||||
* try {
|
||||
* $adapter->authenticate();
|
||||
*
|
||||
* $userProfile = $adapter->getUserProfile();
|
||||
* $tokens = $adapter->getAccessToken();
|
||||
* } catch (\Exception $e ){
|
||||
* echo $e->getMessage() ;
|
||||
* }
|
||||
*/
|
||||
class StackExchange extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = null;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.stackexchange.com/2.2/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://stackexchange.com/oauth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://stackexchange.com/oauth/access_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://api.stackexchange.com/docs/authentication';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$apiKey = $this->config->get('api_key');
|
||||
|
||||
$this->apiRequestParameters = ['key' => $apiKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$site = $this->config->get('site');
|
||||
|
||||
$response = $this->apiRequest('me', 'GET', [
|
||||
'site' => $site,
|
||||
'access_token' => $this->getStoredData('access_token'),
|
||||
]);
|
||||
|
||||
if (!$response || !isset($response->items) || !isset($response->items[0])) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$data = new Data\Collection($response->items[0]);
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = strval($data->get('user_id'));
|
||||
$userProfile->displayName = $data->get('display_name');
|
||||
$userProfile->photoURL = $data->get('profile_image');
|
||||
$userProfile->profileURL = $data->get('link');
|
||||
$userProfile->region = $data->get('location');
|
||||
$userProfile->age = $data->get('age');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OpenID;
|
||||
|
||||
/**
|
||||
* StackExchange OpenID provider adapter.
|
||||
*/
|
||||
class StackExchangeOpenID extends OpenID
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $openidIdentifier = 'https://openid.stackexchange.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://openid.stackexchange.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticateFinish()
|
||||
{
|
||||
parent::authenticateFinish();
|
||||
|
||||
$userProfile = $this->storage->get($this->providerId . '.user');
|
||||
|
||||
$userProfile->identifier = !empty($userProfile->identifier) ? $userProfile->identifier : $userProfile->email;
|
||||
$userProfile->emailVerified = $userProfile->email;
|
||||
|
||||
// re store the user profile
|
||||
$this->storage->set($this->providerId . '.user', $userProfile);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OpenID;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Steam OpenID provider adapter.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $config = [
|
||||
* 'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
* 'keys' => ['secret' => 'steam-api-key']
|
||||
* ];
|
||||
*
|
||||
* $adapter = new Hybridauth\Provider\Steam($config);
|
||||
*
|
||||
* try {
|
||||
* $adapter->authenticate();
|
||||
*
|
||||
* $userProfile = $adapter->getUserProfile();
|
||||
* } catch (\Exception $e) {
|
||||
* echo $e->getMessage() ;
|
||||
* }
|
||||
*/
|
||||
class Steam extends OpenID
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $openidIdentifier = 'http://steamcommunity.com/openid';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://steamcommunity.com/dev';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticateFinish()
|
||||
{
|
||||
parent::authenticateFinish();
|
||||
|
||||
$userProfile = $this->storage->get($this->providerId . '.user');
|
||||
|
||||
$userProfile->identifier = str_ireplace([
|
||||
'http://steamcommunity.com/openid/id/',
|
||||
'https://steamcommunity.com/openid/id/',
|
||||
], '', $userProfile->identifier);
|
||||
|
||||
if (!$userProfile->identifier) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
try {
|
||||
$apiKey = $this->config->filter('keys')->get('secret');
|
||||
|
||||
// if api key is provided, we attempt to use steam web api
|
||||
if ($apiKey) {
|
||||
$result = $this->getUserProfileWebAPI($apiKey, $userProfile->identifier);
|
||||
} else {
|
||||
// otherwise we fallback to community data
|
||||
$result = $this->getUserProfileLegacyAPI($userProfile->identifier);
|
||||
}
|
||||
|
||||
// fetch user profile
|
||||
foreach ($result as $k => $v) {
|
||||
$userProfile->$k = $v ?: $userProfile->$k;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
// store user profile
|
||||
$this->storage->set($this->providerId . '.user', $userProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch user profile on Steam web API
|
||||
*
|
||||
* @param $apiKey
|
||||
* @param $steam64
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getUserProfileWebAPI($apiKey, $steam64)
|
||||
{
|
||||
$q = http_build_query(['key' => $apiKey, 'steamids' => $steam64]);
|
||||
$apiUrl = 'http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?' . $q;
|
||||
|
||||
$response = $this->httpClient->request($apiUrl);
|
||||
|
||||
$data = json_decode($response);
|
||||
|
||||
$data = isset($data->response->players[0]) ? $data->response->players[0] : null;
|
||||
|
||||
$data = new Data\Collection($data);
|
||||
|
||||
$userProfile = [];
|
||||
|
||||
$userProfile['displayName'] = (string)$data->get('personaname');
|
||||
$userProfile['firstName'] = (string)$data->get('realname');
|
||||
$userProfile['photoURL'] = (string)$data->get('avatarfull');
|
||||
$userProfile['profileURL'] = (string)$data->get('profileurl');
|
||||
$userProfile['country'] = (string)$data->get('loccountrycode');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch user profile on community API
|
||||
* @param $steam64
|
||||
* @return array
|
||||
*/
|
||||
public function getUserProfileLegacyAPI($steam64)
|
||||
{
|
||||
libxml_use_internal_errors(false);
|
||||
|
||||
$apiUrl = 'http://steamcommunity.com/profiles/' . $steam64 . '/?xml=1';
|
||||
|
||||
$response = $this->httpClient->request($apiUrl);
|
||||
|
||||
$data = new \SimpleXMLElement($response);
|
||||
|
||||
$data = new Data\Collection($data);
|
||||
|
||||
$userProfile = [];
|
||||
|
||||
$userProfile['displayName'] = (string)$data->get('steamID');
|
||||
$userProfile['firstName'] = (string)$data->get('realname');
|
||||
$userProfile['photoURL'] = (string)$data->get('avatarFull');
|
||||
$userProfile['description'] = (string)$data->get('summary');
|
||||
$userProfile['region'] = (string)$data->get('location');
|
||||
$userProfile['profileURL'] = (string)$data->get('customURL')
|
||||
? 'http://steamcommunity.com/id/' . (string)$data->get('customURL')
|
||||
: 'http://steamcommunity.com/profiles/' . $steam64;
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Instagram OAuth2 provider adapter.
|
||||
*/
|
||||
class SteemConnect extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'login,vote';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://v2.steemconnect.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://v2.steemconnect.com/oauth2/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://v2.steemconnect.com/api/oauth2/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://steemconnect.com/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('api/me');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('result')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$data = $data->filter('result');
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->description = $data->get('about');
|
||||
$userProfile->photoURL = $data->get('profile_image');
|
||||
$userProfile->webSiteURL = $data->get('website');
|
||||
$userProfile->displayName = $data->get('name');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* GitLab OAuth2 provider adapter.
|
||||
*/
|
||||
class Strava extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'profile:read_all';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://www.strava.com/api/v3/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://www.strava.com/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://www.strava.com/oauth/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://developers.strava.com/docs/reference/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('athlete');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->firstName = $data->get('firstname');
|
||||
$userProfile->lastName = $data->get('lastname');
|
||||
$userProfile->gender = $data->get('sex');
|
||||
$userProfile->country = $data->get('country');
|
||||
$userProfile->city = $data->get('city');
|
||||
$userProfile->email = $data->get('email');
|
||||
|
||||
$userProfile->displayName = $userProfile->displayName ?: $data->get('username');
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\HttpClient\Util;
|
||||
use Hybridauth\Data\Collection;
|
||||
use Hybridauth\User\Profile;
|
||||
use Hybridauth\Adapter\AbstractAdapter;
|
||||
use Hybridauth\Adapter\AdapterInterface;
|
||||
use Hybridauth\Exception\InvalidApplicationCredentialsException;
|
||||
use Hybridauth\Exception\InvalidAuthorizationCodeException;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
|
||||
/**
|
||||
* Telegram provider adapter.
|
||||
*
|
||||
* To set up Telegram you need to interactively create a bot using the
|
||||
* Telegram mobile app, talking to botfather. The minimum conversation
|
||||
* will look like:
|
||||
*
|
||||
* /newbot
|
||||
* My Bot Title
|
||||
* nameofmynewbot
|
||||
* /setdomain
|
||||
* @nameofmynewbot
|
||||
* mydomain.com
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $config = [
|
||||
* 'callback' => Hybridauth\HttpClient\Util::getCurrentUrl(),
|
||||
* 'keys' => ['id' => 'your_bot_name', 'secret' => 'your_bot_token'],
|
||||
* ];
|
||||
*
|
||||
* $adapter = new Hybridauth\Provider\Telegram($config);
|
||||
*
|
||||
* try {
|
||||
* $adapter->authenticate();
|
||||
*
|
||||
* $userProfile = $adapter->getUserProfile();
|
||||
* } catch (\Exception $e) {
|
||||
* print $e->getMessage();
|
||||
* }
|
||||
*/
|
||||
class Telegram extends AbstractAdapter implements AdapterInterface
|
||||
{
|
||||
protected $botId = '';
|
||||
|
||||
protected $botSecret = '';
|
||||
|
||||
protected $callbackUrl = '';
|
||||
|
||||
/**
|
||||
* IPD API Documentation
|
||||
*
|
||||
* OPTIONAL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $apiDocumentation = 'https://core.telegram.org/bots';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->botId = $this->config->filter('keys')->get('id');
|
||||
$this->botSecret = $this->config->filter('keys')->get('secret');
|
||||
$this->callbackUrl = $this->config->get('callback');
|
||||
|
||||
if (!$this->botId || !$this->botSecret) {
|
||||
throw new InvalidApplicationCredentialsException(
|
||||
'Your application id is required in order to connect to ' . $this->providerId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$this->logger->info(sprintf('%s::authenticate()', get_class($this)));
|
||||
if (!filter_input(INPUT_GET, 'hash')) {
|
||||
$this->authenticateBegin();
|
||||
} else {
|
||||
$this->authenticateCheckError();
|
||||
$this->authenticateFinish();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
$authData = $this->getStoredData('auth_data');
|
||||
return !empty($authData);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$data = new Collection($this->getStoredData('auth_data'));
|
||||
|
||||
if (!$data->exists('id')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new Profile();
|
||||
|
||||
$userProfile->identifier = $data->get('id');
|
||||
$userProfile->firstName = $data->get('first_name');
|
||||
$userProfile->lastName = $data->get('last_name');
|
||||
$userProfile->displayName = $data->get('username');
|
||||
$userProfile->photoURL = $data->get('photo_url');
|
||||
$username = $data->get('username');
|
||||
if (!empty($username)) {
|
||||
// Only some accounts have usernames.
|
||||
$userProfile->profileURL = "https://t.me/{$username}";
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* See: https://telegram.im/widget-login.php
|
||||
* See: https://gist.github.com/anonymous/6516521b1fb3b464534fbc30ea3573c2
|
||||
*/
|
||||
protected function authenticateCheckError()
|
||||
{
|
||||
$auth_data = $this->parseAuthData();
|
||||
|
||||
$check_hash = $auth_data['hash'];
|
||||
unset($auth_data['hash']);
|
||||
$data_check_arr = [];
|
||||
|
||||
foreach ($auth_data as $key => $value) {
|
||||
if (!empty($value)) {
|
||||
$data_check_arr[] = $key . '=' . $value;
|
||||
}
|
||||
}
|
||||
sort($data_check_arr);
|
||||
|
||||
$data_check_string = implode("\n", $data_check_arr);
|
||||
$secret_key = hash('sha256', $this->botSecret, true);
|
||||
$hash = hash_hmac('sha256', $data_check_string, $secret_key);
|
||||
|
||||
if (strcmp($hash, $check_hash) !== 0) {
|
||||
throw new InvalidAuthorizationCodeException(
|
||||
sprintf('Provider returned an error: %s', 'Data is NOT from Telegram')
|
||||
);
|
||||
}
|
||||
|
||||
if ((time() - $auth_data['auth_date']) > 86400) {
|
||||
throw new InvalidAuthorizationCodeException(
|
||||
sprintf('Provider returned an error: %s', 'Data is outdated')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See: https://telegram.im/widget-login.php
|
||||
*/
|
||||
protected function authenticateBegin()
|
||||
{
|
||||
$this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)));
|
||||
|
||||
$nonce = $this->config->get('nonce');
|
||||
$nonce_code = empty($nonce) ? '' : "nonce=\"{$nonce}\"";
|
||||
|
||||
exit(
|
||||
<<<HTML
|
||||
<center>
|
||||
<script async src="https://telegram.org/js/telegram-widget.js?7"
|
||||
{$nonce_code}
|
||||
data-telegram-login="{$this->botId}"
|
||||
data-size="large"
|
||||
data-auth-url="{$this->callbackUrl}"
|
||||
data-request-access="write">
|
||||
</script>
|
||||
</center>
|
||||
HTML
|
||||
);
|
||||
}
|
||||
|
||||
protected function authenticateFinish()
|
||||
{
|
||||
$this->logger->debug(
|
||||
sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
|
||||
[Util::getCurrentUrl(true)]
|
||||
);
|
||||
|
||||
$this->storeData('auth_data', $this->parseAuthData());
|
||||
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
protected function parseAuthData()
|
||||
{
|
||||
return [
|
||||
'id' => filter_input(INPUT_GET, 'id'),
|
||||
'first_name' => filter_input(INPUT_GET, 'first_name'),
|
||||
'last_name' => filter_input(INPUT_GET, 'last_name'),
|
||||
'username' => filter_input(INPUT_GET, 'username'),
|
||||
'photo_url' => filter_input(INPUT_GET, 'photo_url'),
|
||||
'auth_date' => filter_input(INPUT_GET, 'auth_date'),
|
||||
'hash' => filter_input(INPUT_GET, 'hash'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth1;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* Tumblr OAuth1 provider adapter.
|
||||
*/
|
||||
class Tumblr extends OAuth1
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.tumblr.com/v2/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://www.tumblr.com/oauth/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $requestTokenUrl = 'https://www.tumblr.com/oauth/request_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://www.tumblr.com/oauth/access_token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://www.tumblr.com/docs/en/api/v2';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('user/info');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('response')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->displayName = $data->filter('response')->filter('user')->get('name');
|
||||
|
||||
foreach ($data->filter('response')->filter('user')->filter('blogs')->toArray() as $blog) {
|
||||
$blog = new Data\Collection($blog);
|
||||
|
||||
if ($blog->get('primary') && $blog->exists('url')) {
|
||||
$userProfile->identifier = $blog->get('url');
|
||||
$userProfile->profileURL = $blog->get('url');
|
||||
$userProfile->webSiteURL = $blog->get('url');
|
||||
$userProfile->description = strip_tags($blog->get('description'));
|
||||
|
||||
$bloghostname = explode('://', $blog->get('url'));
|
||||
$bloghostname = substr($bloghostname[1], 0, -1);
|
||||
|
||||
// store user's primary blog which will be used as target by setUserStatus
|
||||
$this->storeData('primary_blog', $bloghostname);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUserStatus($status)
|
||||
{
|
||||
$status = is_string($status)
|
||||
? ['type' => 'text', 'body' => $status]
|
||||
: $status;
|
||||
|
||||
$response = $this->apiRequest('blog/' . $this->getStoredData('primary_blog') . '/post', 'POST', $status);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/*!
|
||||
* Hybridauth
|
||||
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
|
||||
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html
|
||||
*/
|
||||
|
||||
namespace Hybridauth\Provider;
|
||||
|
||||
use Hybridauth\Adapter\OAuth2;
|
||||
use Hybridauth\Exception\UnexpectedApiResponseException;
|
||||
use Hybridauth\Data;
|
||||
use Hybridauth\User;
|
||||
|
||||
/**
|
||||
* TwitchTV OAuth2 provider adapter.
|
||||
*/
|
||||
class TwitchTV extends OAuth2
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scope = 'user:read:email';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiBaseUrl = 'https://api.twitch.tv/helix/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $authorizeUrl = 'https://id.twitch.tv/oauth2/authorize';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $accessTokenUrl = 'https://id.twitch.tv/oauth2/token';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $apiDocumentation = 'https://dev.twitch.tv/docs/authentication/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->apiRequestHeaders['Client-ID'] = $this->clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserProfile()
|
||||
{
|
||||
$response = $this->apiRequest('users');
|
||||
|
||||
$data = new Data\Collection($response);
|
||||
|
||||
if (!$data->exists('data')) {
|
||||
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
|
||||
}
|
||||
|
||||
$users = $data->filter('data')->values();
|
||||
$user = new Data\Collection($users[0]);
|
||||
|
||||
$userProfile = new User\Profile();
|
||||
|
||||
$userProfile->identifier = $user->get('id');
|
||||
$userProfile->displayName = $user->get('display_name');
|
||||
$userProfile->photoURL = $user->get('profile_image_url');
|
||||
$userProfile->email = $user->get('email');
|
||||
$userProfile->description = strip_tags($user->get('description'));
|
||||
$userProfile->profileURL = "https://www.twitch.tv/{$userProfile->displayName}";
|
||||
|
||||
return $userProfile;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user