-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Frank Rochlitzer <f.rochlitzer@b3-it.de>
- Loading branch information
Showing
5 changed files
with
475 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/build | ||
/vendor | ||
/.idea | ||
composer.phar | ||
composer.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,115 @@ | ||
# oauth2-adfs | ||
This package provides Microsoft ADFS OAuth 2.0 support for the PHP League's OAuth 2.0 Client. | ||
# Microsoft ADFS Provider for OAuth 2.0 Client | ||
[![Latest Version](https://img.shields.io/github/release/b3-it/oauth2-adfs.svg?style=flat-square)](https://github.com/b3-it/oauth2-adfs/releases) | ||
[![Build Status](https://img.shields.io/travis/b3-it/oauth2-adfs/master.svg?style=flat-square)](https://travis-ci.org/b3-it/oauth2-adfs) | ||
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/b3-it/oauth2-adfs.svg?style=flat-square)](https://scrutinizer-ci.com/g/b3-it/oauth2-adfs/code-structure) | ||
[![Quality Score](https://img.shields.io/scrutinizer/g/b3-it/oauth2-adfs.svg?style=flat-square)](https://scrutinizer-ci.com/g/b3-it/oauth2-adfs) | ||
[![Total Downloads](https://img.shields.io/packagist/dt/b3-it/oauth2-adfs.svg?style=flat-square)](https://packagist.org/packages/b3-it/oauth2-adfs) | ||
[![Software License](https://img.shields.io/packagist/l/b3-it/oauth2-adfs.svg?style=flat-square)](LICENSE.md) | ||
|
||
This package provides Microsoft ADFS OAuth 2.0 support for the PHP League's [OAuth 2.0 Client](https://github.com/thephpleague/oauth2-client). | ||
|
||
## Installation | ||
|
||
To install, use composer: | ||
|
||
``` | ||
composer require b3-it/oauth2-adfs | ||
``` | ||
|
||
## Usage | ||
|
||
Usage is the same as The League's OAuth client, using `\B3it\OAuth2\Client\Provider\Adfs` as the provider. | ||
|
||
### Authorization Code Flow | ||
|
||
```php | ||
$provider = new B3it\OAuth2\Client\Provider\Adfs([ | ||
// Required | ||
'clientId' => '{microsoft-client-id}', | ||
'clientSecret' => '{microsoft-client-secret}', | ||
'authServerUrl' => 'https://my.ms-server.de/adfs', | ||
// Optional | ||
'redirectUri' => 'https://example.com/callback-url', | ||
'resource' => 'https://example.com' | ||
|
||
]); | ||
|
||
if (!isset($_GET['code'])) { | ||
|
||
// If we don't have an authorization code then get one | ||
$authUrl = $provider->getAuthorizationUrl(); | ||
$_SESSION['oauth2state'] = $provider->getState(); | ||
header('Location: '.$authUrl); | ||
exit; | ||
|
||
// Check given state against previously stored one to mitigate CSRF attack | ||
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) { | ||
|
||
unset($_SESSION['oauth2state']); | ||
exit('Invalid state'); | ||
|
||
} else { | ||
|
||
// Try to get an access token (using the authorization code grant) | ||
$token = $provider->getAccessToken('authorization_code', [ | ||
'code' => $_GET['code'] | ||
]); | ||
|
||
// Optional: Now you have a token you can look up a users profile data | ||
try { | ||
|
||
// We got an access token, let's now get the user's details | ||
$user = $provider->getResourceOwner($token); | ||
|
||
// Use these details to create a new profile | ||
printf('Hello %s!', $user->geName()); | ||
|
||
} catch (Exception $e) { | ||
|
||
// Failed to get user details | ||
exit('Oh dear...'); | ||
} | ||
|
||
// Use this to interact with an API on the users behalf | ||
echo $token->getToken(); | ||
} | ||
``` | ||
|
||
#### Managing Scopes and State | ||
|
||
When creating your Microsoft ADFS authorization URL, you can specify the state and scopes your application may authorize. | ||
|
||
```php | ||
$options = [ | ||
'scope' => ['allatclaims', 'openid'] // array or string | ||
]; | ||
|
||
$authorizationUrl = $provider->getAuthorizationUrl($options); | ||
``` | ||
If neither are defined, the provider will utilize internal defaults. | ||
|
||
At the time of authoring this documentation, the following scopes are available. | ||
|
||
|
||
##### Scopes | ||
- logon_cert | ||
- aza | ||
- allatclaims | ||
- profile | ||
- winhello_cert | ||
- openid | ||
- vpn_cert | ||
- user_impersonation | ||
|
||
|
||
## Credits | ||
|
||
- [B3 IT Systeme GmbH](https://github.com/b3-it) | ||
- [All Contributors](https://github.com/b3-it/oauth2-adfs/contributors) | ||
|
||
|
||
## License | ||
|
||
The MIT License (MIT). Please see [License File](https://github.com/b3-it/oauth2-adfs/blob/master/LICENSE) for more information. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
{ | ||
"name": "b3-it/oauth2-adfs", | ||
"version": "1.0.0.0", | ||
"description": "Microsoft Active Directory Federation Service (ADFS) OAuth 2.0 Client Provider for The PHP League OAuth2-Client", | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"name": "Frank Rochlitzer", | ||
"email": "f.rochlitzer@b3-it.de", | ||
"homepage": "https://github.com/b3-it" | ||
} | ||
], | ||
"keywords": [ | ||
"oauth", | ||
"oauth2", | ||
"client", | ||
"authorization", | ||
"authorisation", | ||
"microsoft", | ||
"adfs" | ||
], | ||
"require": { | ||
"league/oauth2-client": "^2.0" | ||
}, | ||
"require-dev": { | ||
"roave/security-advisories": "dev-master", | ||
"phpunit/phpunit": "~4.0", | ||
"mockery/mockery": "~0.9", | ||
"squizlabs/php_codesniffer": "~2.0" | ||
}, | ||
"autoload": { | ||
"psr-4": { | ||
"B3it\\OAuth2\\Client\\": "src/" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"B3it\\OAuth2\\Client\\Test\\": "tests/src/" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
<?php | ||
namespace B3it\OAuth2\Client\Provider; | ||
|
||
use League\OAuth2\Client\Provider\GenericProvider; | ||
use League\OAuth2\Client\Provider\ResourceOwnerInterface; | ||
use League\OAuth2\Client\Token\AccessToken; | ||
|
||
class Adfs extends GenericProvider | ||
{ | ||
private $responseResourceOwnerId = 'upn'; | ||
|
||
private $scopes = ['openid']; | ||
|
||
protected $idToken = null; | ||
|
||
protected $resource = null; | ||
|
||
/** | ||
* ADFS URL, eg. https://localhost/adfs. | ||
* | ||
* @var string | ||
*/ | ||
public $authServerUrl = null; | ||
|
||
public function __construct(array $options = [], array $collaborators = []) | ||
{ | ||
if (isset($options['idToken'])) { | ||
$token = $options['idToken']; | ||
if ($token instanceof AccessToken) { | ||
$options['idToken'] = $this->getIdTokenFromAccessToken($token); | ||
} | ||
} | ||
parent::__construct($options, $collaborators); | ||
} | ||
|
||
/** | ||
* Get authorization url to begin OAuth flow | ||
* | ||
* @return string | ||
*/ | ||
public function getBaseAuthorizationUrl() | ||
{ | ||
return $this->getBaseUrl().'/oauth2/authorize/'; | ||
} | ||
|
||
/** | ||
* Get access token url to retrieve token | ||
* | ||
* @param array $params | ||
* | ||
* @return string | ||
*/ | ||
public function getBaseAccessTokenUrl(array $params) | ||
{ | ||
return $this->getBaseUrl().'/oauth2/token/'; | ||
} | ||
|
||
/** | ||
* Builds the logout URL. | ||
* | ||
* @param array $options | ||
* @return string Authorization URL | ||
*/ | ||
public function getLogoutUrl(array $options = []) | ||
{ | ||
$base = $this->getBaseLogoutUrl(); | ||
$params = $this->getAuthorizationParameters($options); | ||
if (isset($params['redirect_uri'])) { | ||
$params['post_logout_redirect_uri'] = $params['redirect_uri']; | ||
unset($params['redirect_uri']); | ||
if ($this->idToken) { | ||
$params['id_token_hint'] = $this->idToken; | ||
} | ||
} | ||
$query = $this->getAuthorizationQuery($params); | ||
return $this->appendQuery($base, $query); | ||
} | ||
|
||
public function getAccessToken($grant, array $options = []) | ||
{ | ||
$token = parent::getAccessToken($grant, $options); | ||
|
||
//We have to preserve the id_token for id_token_hint in the logout url | ||
$this->idToken = $this->getIdTokenFromAccessToken($token); | ||
return $token; | ||
} | ||
|
||
/** | ||
* Requests and returns the resource owner of given access token. | ||
* | ||
* @param AccessToken $token | ||
* @return ResourceOwnerInterface | ||
*/ | ||
public function getResourceOwner(AccessToken $token) | ||
{ | ||
$response = []; | ||
|
||
return $this->createResourceOwner($response, $token); | ||
} | ||
|
||
public function getIdTokenFromAccessToken($token) { | ||
if (!($token instanceof AccessToken)) { | ||
return null; | ||
} | ||
|
||
$values = $token->getValues(); | ||
return $values['id_token'] ?? null; | ||
} | ||
|
||
public function getIdToken() { | ||
return $this->idToken; | ||
} | ||
|
||
public function getDefaultScopes() | ||
{ | ||
$defaults = parent::getDefaultScopes(); | ||
|
||
if (is_array($defaults)) { | ||
return array_merge($defaults, $this->scopes); | ||
} | ||
return $this->scopes; | ||
} | ||
|
||
/** | ||
* Get logout url to logout of session token | ||
* | ||
* @return string | ||
*/ | ||
private function getBaseLogoutUrl() | ||
{ | ||
return $this->getBaseUrl() . '/oauth2/logout'; | ||
} | ||
|
||
/** | ||
* Returns all options that are required. | ||
* | ||
* @return array | ||
*/ | ||
protected function getRequiredOptions() | ||
{ | ||
return [ | ||
'authServerUrl', | ||
]; | ||
} | ||
|
||
/** | ||
* Creates base url from provider configuration. | ||
* | ||
* @return string | ||
*/ | ||
protected function getBaseUrl() | ||
{ | ||
return trim($this->authServerUrl, " \t\n\r\0\x0B/"); | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
protected function createResourceOwner(array $response, AccessToken $token) | ||
{ | ||
return new AdfsResourceOwner($token, $response, $this->responseResourceOwnerId); | ||
} | ||
|
||
/** | ||
* Returns the list of options that can be passed to the HttpClient | ||
* | ||
* @param array $options An array of options to set on this provider. | ||
* Options include `clientId`, `clientSecret`, `redirectUri`, and `state`. | ||
* Individual providers may introduce more options, as needed. | ||
* @return array The options to pass to the HttpClient constructor | ||
*/ | ||
protected function getAllowedClientOptions(array $options) | ||
{ | ||
$client_options = ['timeout', 'proxy', 'verify']; | ||
|
||
return $client_options; | ||
} | ||
|
||
protected function getAuthorizationParameters(array $options) | ||
{ | ||
$params = parent::getAuthorizationParameters($options); | ||
|
||
if ($this->resource) { | ||
$params['resource'] = $this->resource; | ||
} | ||
|
||
return $params; | ||
} | ||
} |
Oops, something went wrong.