private function _handleAuthorize(IResourceOwner $resourceOwner, array $get)
 {
     try {
         $clientId = Utils::getParameter($get, 'client_id');
         $responseType = Utils::getParameter($get, 'response_type');
         $redirectUri = Utils::getParameter($get, 'redirect_uri');
         // FIXME: scope can never be empty, if the client requests no scope we should have a default scope!
         $scope = new Scope(Utils::getParameter($get, 'scope'));
         $state = Utils::getParameter($get, 'state');
         if (NULL === $clientId) {
             throw new ResourceOwnerException('client_id missing');
         }
         if (NULL === $responseType) {
             throw new ResourceOwnerException('response_type missing');
         }
         $client = $this->_storage->getClient($clientId);
         if (FALSE === $client) {
             throw new ResourceOwnerException('client not registered');
         }
         if (NULL !== $redirectUri) {
             if ($client['redirect_uri'] !== $redirectUri) {
                 throw new ResourceOwnerException('specified redirect_uri not the same as registered redirect_uri');
             }
         }
         // we need to make sure the client can only request the grant types belonging to its profile
         $allowedClientProfiles = array("web_application" => array("code"), "native_application" => array("token", "code"), "user_agent_based_application" => array("token"));
         if (!in_array($responseType, $allowedClientProfiles[$client['type']])) {
             throw new ClientException("unsupported_response_type", "response_type not supported by client profile", $client, $state);
         }
         if (!$scope->isSubsetOf(new Scope($client['allowed_scope']))) {
             throw new ClientException("invalid_scope", "not authorized to request this scope", $client, $state);
         }
         $this->_storage->updateResourceOwner($resourceOwner);
         $approvedScope = $this->_storage->getApprovalByResourceOwnerId($clientId, $resourceOwner->getId());
         if (FALSE === $approvedScope || FALSE === $scope->isSubsetOf(new Scope($approvedScope['scope']))) {
             $ar = new AuthorizeResult(AuthorizeResult::ASK_APPROVAL);
             $ar->setClient(ClientRegistration::fromArray($client));
             $ar->setScope($scope);
             return $ar;
         } else {
             if ("token" === $responseType) {
                 // implicit grant
                 // FIXME: return existing access token if it exists for this exact client, resource owner and scope?
                 $accessToken = Utils::randomHex(16);
                 $this->_storage->storeAccessToken($accessToken, time(), $clientId, $resourceOwner->getId(), $scope->getScope(), $this->_config->getValue('accessTokenExpiry'));
                 $token = array("access_token" => $accessToken, "expires_in" => $this->_config->getValue('accessTokenExpiry'), "token_type" => "bearer");
                 $s = $scope->getScope();
                 if (!empty($s)) {
                     $token += array("scope" => $s);
                 }
                 if (NULL !== $state) {
                     $token += array("state" => $state);
                 }
                 $ar = new AuthorizeResult(AuthorizeResult::REDIRECT);
                 $ar->setRedirectUri(new Uri($client['redirect_uri'] . "#" . http_build_query($token)));
                 return $ar;
             } else {
                 // authorization code grant
                 $authorizationCode = Utils::randomHex(16);
                 $this->_storage->storeAuthorizationCode($authorizationCode, $resourceOwner->getId(), time(), $clientId, $redirectUri, $scope->getScope());
                 $token = array("code" => $authorizationCode);
                 if (NULL !== $state) {
                     $token += array("state" => $state);
                 }
                 $ar = new AuthorizeResult(AuthorizeResult::REDIRECT);
                 $separator = FALSE === strpos($client['redirect_uri'], "?") ? "?" : "&";
                 $ar->setRedirectUri(new Uri($client['redirect_uri'] . $separator . http_build_query($token)));
                 return $ar;
             }
         }
     } catch (ScopeException $e) {
         throw new ClientException("invalid_scope", "malformed scope", $client, $state);
     }
 }
 public function testFailingScope()
 {
     $s = new Scope("read write delete");
     $this->assertFalse($s->isSubsetOf(new Scope("read write update")));
     $this->assertFalse($s->hasScope(new Scope("foo")));
 }
Esempio n. 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;
 }