/**
  * Implementation of https://tools.ietf.org/html/draft-richer-oauth-introspection
  */
 private function _introspectToken(array $param)
 {
     $r = array();
     $token = Utils::getParameter($param, 'token');
     if (NULL === $token) {
         throw new TokenIntrospectionException("invalid_token", "the token parameter is missing");
     }
     $accessToken = $this->_storage->getAccessToken($token);
     if (FALSE === $accessToken) {
         // token does not exist
         $r['active'] = FALSE;
     } elseif (time() > $accessToken['issue_time'] + $accessToken['expires_in']) {
         // token expired
         $r['active'] = FALSE;
     } else {
         // token exists and did not expire
         $r['active'] = TRUE;
         $r['exp'] = intval($accessToken['issue_time'] + $accessToken['expires_in']);
         $r['iat'] = intval($accessToken['issue_time']);
         $r['scope'] = $accessToken['scope'];
         $r['client_id'] = $accessToken['client_id'];
         $r['sub'] = $accessToken['resource_owner_id'];
         $r['token_type'] = 'bearer';
         // as long as we have no RS registration we cannot set the audience...
         // $response['aud'] = 'foo';
         // add proprietary "x-entitlement"
         $resourceOwner = $this->_storage->getResourceOwner($accessToken['resource_owner_id']);
         if (isset($resourceOwner['entitlement'])) {
             $e = Json::dec($resourceOwner['entitlement']);
             if (0 !== count($e)) {
                 $r['x-entitlement'] = $e;
             }
         }
         // add proprietary "x-ext"
         if (isset($resourceOwner['ext'])) {
             $e = Json::dec($resourceOwner['ext']);
             if (0 !== count($e)) {
                 $r['x-ext'] = $e;
             }
         }
     }
     return $r;
 }
 private function _handleApprove(IResourceOwner $resourceOwner, array $get, array $post)
 {
     try {
         $clientId = Utils::getParameter($get, 'client_id');
         $responseType = Utils::getParameter($get, 'response_type');
         $redirectUri = Utils::getParameter($get, 'redirect_uri');
         $scope = new Scope(Utils::getParameter($get, 'scope'));
         $state = Utils::getParameter($get, 'state');
         $result = $this->_handleAuthorize($resourceOwner, $get);
         if (AuthorizeResult::ASK_APPROVAL !== $result->getAction()) {
             return $result;
         }
         $approval = Utils::getParameter($post, 'approval');
         // FIXME: are we sure this client is always valid?
         $client = $this->_storage->getClient($clientId);
         if ("approve" === $approval) {
             $approvedScope = $this->_storage->getApprovalByResourceOwnerId($clientId, $resourceOwner->getId());
             if (FALSE === $approvedScope) {
                 // no approved scope stored yet, new entry
                 $refreshToken = "code" === $responseType ? Utils::randomHex(16) : NULL;
                 $this->_storage->addApproval($clientId, $resourceOwner->getId(), $scope->getScope(), $refreshToken);
             } else {
                 $this->_storage->updateApproval($clientId, $resourceOwner->getId(), $scope->getScope());
             }
             return $this->_handleAuthorize($resourceOwner, $get);
         } else {
             throw new ClientException("access_denied", "not authorized by resource owner", $client, $state);
         }
     } catch (ScopeException $e) {
         throw new ClientException("invalid_scope", "malformed scope", $client, $state);
     }
 }
예제 #3
0
 private function _handleToken(array $post, $user = NULL, $pass = NULL)
 {
     // exchange authorization code for access token
     $grantType = Utils::getParameter($post, 'grant_type');
     $code = Utils::getParameter($post, 'code');
     $redirectUri = Utils::getParameter($post, 'redirect_uri');
     $refreshToken = Utils::getParameter($post, 'refresh_token');
     $token = Utils::getParameter($post, 'token');
     $clientId = Utils::getParameter($post, 'client_id');
     $scope = Utils::getParameter($post, 'scope');
     if (NULL !== $user && !empty($user) && NULL !== $pass && !empty($pass)) {
         // client provided authentication, it MUST be valid now...
         $client = $this->_storage->getClient($user);
         if (FALSE === $client) {
             throw new TokenException("invalid_client", "client authentication failed");
         }
         // check pass
         if ($pass !== $client['secret']) {
             throw new TokenException("invalid_client", "client authentication failed");
         }
         // if client_id in POST is set, it must match the user
         if (NULL !== $clientId && $clientId !== $user) {
             throw new TokenException("invalid_grant", "client_id inconsistency: authenticating user must match POST body client_id");
         }
         $hasAuthenticated = TRUE;
     } else {
         // client provided no authentication, client_id must be in POST body
         if (NULL === $clientId || empty($clientId)) {
             throw new TokenException("invalid_request", "no client authentication used nor client_id POST parameter");
         }
         $client = $this->_storage->getClient($clientId);
         if (FALSE === $client) {
             throw new TokenException("invalid_client", "client identity could not be established");
         }
         $hasAuthenticated = FALSE;
     }
     if ("user_agent_based_application" === $client['type']) {
         throw new TokenException("unauthorized_client", "this client type is not allowed to use the token endpoint");
     }
     if ("web_application" === $client['type'] && !$hasAuthenticated) {
         // web_application type MUST have authenticated
         throw new TokenException("invalid_client", "client authentication failed");
     }
     if (NULL === $grantType) {
         throw new TokenException("invalid_request", "the grant_type parameter is missing");
     }
     switch ($grantType) {
         case "authorization_code":
             if (NULL === $code) {
                 throw new TokenException("invalid_request", "the code parameter is missing");
             }
             // If the redirect_uri was present in the authorize request, it MUST also be there
             // in the token request. If it was not there in authorize request, it MUST NOT be
             // there in the token request (this is not explicit in the spec!)
             $result = $this->_storage->getAuthorizationCode($client['id'], $code, $redirectUri);
             if (FALSE === $result) {
                 throw new TokenException("invalid_grant", "the authorization code was not found");
             }
             if (time() > $result['issue_time'] + 600) {
                 throw new TokenException("invalid_grant", "the authorization code expired");
             }
             // we MUST be able to delete the authorization code, otherwise it was used before
             if (FALSE === $this->_storage->deleteAuthorizationCode($client['id'], $code, $redirectUri)) {
                 // check to prevent deletion race condition
                 throw new TokenException("invalid_grant", "this authorization code grant was already used");
             }
             $approval = $this->_storage->getApprovalByResourceOwnerId($client['id'], $result['resource_owner_id']);
             $token = array();
             $token['access_token'] = Utils::randomHex(16);
             $token['expires_in'] = intval($this->_config->getValue('accessTokenExpiry'));
             // we always grant the scope the user authorized, no further restrictions here...
             // FIXME: the merging of authorized scopes in the authorize function is a bit of a mess!
             // we should deal with that there and come up with a good solution...
             $token['scope'] = $result['scope'];
             $token['refresh_token'] = $approval['refresh_token'];
             $token['token_type'] = "bearer";
             $this->_storage->storeAccessToken($token['access_token'], time(), $client['id'], $result['resource_owner_id'], $token['scope'], $token['expires_in']);
             break;
         case "refresh_token":
             if (NULL === $refreshToken) {
                 throw new TokenException("invalid_request", "the refresh_token parameter is missing");
             }
             $result = $this->_storage->getApprovalByRefreshToken($client['id'], $refreshToken);
             if (FALSE === $result) {
                 throw new TokenException("invalid_grant", "the refresh_token was not found");
             }
             $token = array();
             $token['access_token'] = Utils::randomHex(16);
             $token['expires_in'] = intval($this->_config->getValue('accessTokenExpiry'));
             if (NULL !== $scope) {
                 // the client wants to obtain a specific scope
                 $requestedScope = new Scope($scope);
                 $authorizedScope = new Scope($result['scope']);
                 if ($requestedScope->isSubsetOf($authorizedScope)) {
                     // if it is a subset of the authorized scope we honor that
                     $token['scope'] = $requestedScope->getScope();
                 } else {
                     // if not the client gets the authorized scope
                     $token['scope'] = $result['scope'];
                 }
             } else {
                 $token['scope'] = $result['scope'];
             }
             $token['token_type'] = "bearer";
             $this->_storage->storeAccessToken($token['access_token'], time(), $client['id'], $result['resource_owner_id'], $token['scope'], $token['expires_in']);
             break;
         default:
             throw new TokenException("unsupported_grant_type", "the requested grant type is not supported");
     }
     return $token;
 }