Accueil > OpenID Connect OAuth Serveur dédié > Développer > Service OAuthSD pour Lusitanian/PHPoAuthLib

Service OAuthSD pour Lusitanian/PHPoAuthLib

La bibliothèque Lusitanian/PHPoAuthLib fournit un support OAuth en PHP et est très facile à intégrer à tout projet nécessitant un client OAuth 2.

Cet article présente le code du service OAuthSD à inclure dans la librairie.


Si la classe Oauthsd n’est pas fournie par un plugin ou une extension, le code ci-dessous doit être inséré dans la librairie à l’emplacement et sous le nom indiqué :

.../vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Oauthsd.php

Notes :
- Le scope ’openid’ indique que nous utilisons la couche OpenID Connect.
- ’response_type’ => ’code’ indique que nous utilisons le flux Authorization code.
- Le scope "sli" permet (notamment) la connexion unique.
- Pour une utilisation en simple SSO, il est inutile de risquer de dévoiler les données de l’utilisateur avec le scope profile. En supprimant le scope profile, OAuthSD utilisera le scope par défaut basic, et seul le champ sub (subject) sera retourné par la demande d’authentification.

PHP

  1. <?php
  2. /**  
  3. * OpenID Connect Authentication with OAuthSD
  4. * @link     https://oa.dnc.global
  5. * Oauthsd.php OAuth service for the Lusitanian PHPoAuthLib
  6. * @link     https://github.com/Lusitanian/PHPoAuthLib
  7. * @author   Bertrand Degoy bertrand@degoy.com
  8. * @copyright (c) 2018 B.Degoy DnC https://degoy.com
  9. * @license  http://www.opensource.org/licenses/mit-license.html MIT License
  10. */
  11.  
  12. //dnc4
  13.  
  14. namespace OAuth\OAuth2\Service;
  15.  
  16. use OAuth\OAuth2\Token\StdOAuth2Token;
  17. use OAuth\Common\Http\Exception\TokenResponseException;
  18. use OAuth\Common\Http\Uri\Uri;
  19. use OAuth\Common\Consumer\CredentialsInterface;
  20. use OAuth\Common\Http\Client\ClientInterface;
  21. use OAuth\Common\Storage\TokenStorageInterface;
  22. use OAuth\Common\Http\Uri\UriInterface;
  23.  
  24.  
  25. class Oauthsd extends AbstractService
  26. {
  27.  
  28.     /**
  29.     * Available scopes (will be tested by AbstractService).
  30.     * Might be larger than those defined by client application.
  31.     * @link https://oa.dnc.global/-Sujets-communs-.html#definitionetgestiondesscopesdansOAuthsd
  32.     * @see  #attributes
  33.     */
  34.     const SCOPE_OPENID           = 'openid';
  35.     const SCOPE_PROFILE          = 'profile';
  36.     const SCOPE_EMAIL            = 'email';
  37.     const SCOPE_ADDRESS          = 'address';
  38.     const SCOPE_PHONE            = 'phone';
  39.     const SCOPE_SLI              = 'sli';
  40.  
  41.     public function __construct(
  42.         CredentialsInterface $credentials,
  43.         ClientInterface $httpClient,
  44.         TokenStorageInterface $storage,
  45.         $scopes = array(),
  46.         UriInterface $baseApiUri = null
  47.     ) {
  48.  
  49.         $scopes = array_merge($scopes, array(openid, sli, profile));   // profile ???
  50.  
  51.         parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
  52.  
  53.         if (null === $baseApiUri) {
  54.             $this->baseApiUri = new Uri('https://oa.dnc.global/');
  55.         }
  56.     }
  57.  
  58.     /**
  59.     * Override abstract function in order to provide required parameters in authorization request.
  60.     * State is required by OAuthSD
  61.     * Scopes :
  62.     * openid is required by OpenID Connect, sli is particular to OAuthSD, basic is enough for phpBB.
  63.     * @link https://oa.dnc.global/-Sujets-communs-.html#definitionetgestiondesscopesdansOAuthsd
  64.     */
  65.     public function getAuthorizationUri(array $additionalParameters = array())
  66.     {
  67.         $parameters = array_merge(
  68.             $additionalParameters,
  69.             array(
  70.                 //'type'          => 'web_server',
  71.                 'client_id'     => $this->credentials->getConsumerId(),
  72.                 'redirect_uri'  => $this->credentials->getCallbackUrl(),
  73.                 'response_type' => 'code',
  74.                 'scope'         => 'openid sli',    // do not mention basic.      
  75.             )
  76.         );
  77.  
  78.         if (!isset($parameters['state'])) {
  79.             $parameters['state'] = $this->generateAuthorizationState();
  80.         }
  81.         $this->storeAuthorizationState($parameters['state']);
  82.  
  83.         // Build the url
  84.         $url = clone $this->getAuthorizationEndpoint();
  85.         foreach ($parameters as $key => $val) {
  86.             $url->addToQuery($key, $val);
  87.         }
  88.         return $url;
  89.     }
  90.  
  91.     /**
  92.     * {@inheritdoc}
  93.     */
  94.     public function getAuthorizationEndpoint()
  95.     {
  96.         return new Uri('https://oa.dnc.global/authorize');
  97.     }
  98.  
  99.     /**
  100.     * {@inheritdoc}
  101.     */
  102.     public function getAccessTokenEndpoint()
  103.     {
  104.         return new Uri('https://oa.dnc.global/token');
  105.     }
  106.  
  107.     /**
  108.     * {@inheritdoc}
  109.     */
  110.     protected function getAuthorizationMethod()
  111.     {
  112.         return static::AUTHORIZATION_METHOD_HEADER_BEARER;        // ou AUTHORIZATION_METHOD_QUERY_STRING ???
  113.     }
  114.  
  115.     /**
  116.     * {@inheritdoc}
  117.     */
  118.     protected function parseAccessTokenResponse($responseBody)
  119.     {
  120.         $data = json_decode($responseBody, true);
  121.  
  122.         if (null === $data || !is_array($data)) {
  123.             throw new TokenResponseException('Unable to parse response.');
  124.         } elseif (isset($data['message'])) {
  125.             throw new TokenResponseException('Error in retrieving token: "' . $data['message'] . '"');
  126.         } elseif (isset($data['name'])) {
  127.             throw new TokenResponseException('Error in retrieving token: "' . $data['name'] . '"');
  128.         }
  129.  
  130.         $token = new StdOAuth2Token();
  131.         $token->setAccessToken($data['access_token']);
  132.         $token->setLifeTime($data['expires_in']);
  133.  
  134.         if (isset($data['refresh_token'])) {
  135.             $token->setRefreshToken($data['refresh_token']);
  136.             unset($data['refresh_token']);
  137.         }
  138.  
  139.         unset($data['access_token']);
  140.         unset($data['expires_in']);
  141.  
  142.         $token->setExtraParams($data);
  143.  
  144.         return $token;
  145.     }
  146.  
  147.     /**
  148.     * {@inheritdoc}
  149.     */
  150.     public function requestAccessToken($code, $state = null)
  151.     {
  152.         if (null !== $state) {
  153.             $this->validateAuthorizationState($state);
  154.         }
  155.  
  156.         $bodyParams = array(
  157.             'code'          => $code,
  158.             'client_id'     => $this->credentials->getConsumerId(),
  159.             'client_secret' => $this->credentials->getConsumerSecret(),
  160.             'redirect_uri'  => $this->credentials->getCallbackUrl(),
  161.             'grant_type'    => 'authorization_code',
  162.         );
  163.  
  164.         $responseBody = $this->httpClient->retrieveResponse(
  165.             $this->getAccessTokenEndpoint(),
  166.             $bodyParams,
  167.             $this->getExtraOAuthHeaders()
  168.         );
  169.        
  170.         $token = $this->parseAccessTokenResponse($responseBody);
  171.         $this->storage->storeAccessToken($this->service(), $token);
  172.  
  173.         return $token;
  174.     }
  175. }

Télécharger

Feuille de route

Dans une organisation fermée (corporate realm), on souhaite posséder son propre serveur OIDC et obtenir des données Userinfo selon un format spécifique, généralement en utilisant une table users existante.
Pour cela, il faudrait :
- une fonction setter pour l’URL du serveur OIDC afin de pouvoir choisir le serveur d’authentification.
- une fonction setter pour configurer les données de Userinfo.
- cela devrait conduire à un client OpenID Connect universel. Tenter alors un pull request vers lusitanian ?