Commit 0517db8c authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Implemented client credentials grant type

parent b94e3eeb
Loading
Loading
Loading
Loading
+30 −10
Original line number Original line Diff line number Diff line
@@ -17,6 +17,35 @@ class ClientAuthChecker {


    public function validateClientAuth(): void {
    public function validateClientAuth(): void {


        $basic = $this->getBasicAuthArray();

        $clientId = $basic[0];
        $clientSecret = $basic[1];

        $client = $this->locator->getOAuth2ClientDAO()->getOAuth2ClientByClientId($clientId);
        if ($client === null) {
            throw new UnauthorizedException("Client '$clientId' not configured");
        }
        if ($clientSecret !== $client->secret) {
            throw new UnauthorizedException("Invalid client secret");
        }
    }

    public function validateCliClientAuth(): CliClient {

        $basic = $this->getBasicAuthArray();

        $clientId = $basic[0];
        $clientSecret = $basic[1];

        $client = $this->locator->getOAuth2ClientDAO()->getCliClient($clientId, $clientSecret);
        if ($client === null) {
            throw new UnauthorizedException("Client '$clientId' not configured or wrong password");
        }
        return $client;
    }

    private function getBasicAuthArray(): array {
        $headers = apache_request_headers();
        $headers = apache_request_headers();


        if (!isset($headers['Authorization'])) {
        if (!isset($headers['Authorization'])) {
@@ -29,16 +58,7 @@ class ClientAuthChecker {
            if (count($basic) !== 2) {
            if (count($basic) !== 2) {
                throw new BadRequestException("Malformed Basic-Auth header");
                throw new BadRequestException("Malformed Basic-Auth header");
            }
            }
            $clientId = $basic[0];
            return $basic;
            $clientSecret = $basic[1];

            $client = $this->locator->getOAuth2ClientDAO()->getOAuth2ClientByClientId($clientId);
            if ($client === null) {
                throw new UnauthorizedException("Client '$clientId' not configured");
            }
            if ($clientSecret !== $client->secret) {
                throw new UnauthorizedException("Invalid client secret");
            }
        } else {
        } else {
            throw new UnauthorizedException("Expected Basic authorization header");
            throw new UnauthorizedException("Expected Basic authorization header");
        }
        }
+1 −5
Original line number Original line Diff line number Diff line
@@ -107,11 +107,7 @@ class JWKSHandler {
                $dao->updatePublicJWK($jwk);
                $dao->updatePublicJWK($jwk);
            }
            }
        } else {
        } else {
            $errorMessage = 'Error while retrieving JWKS: ' . curl_error($conn);
            error_log('Error while retrieving JWKS from ' . $url);
            error_log($result);
            curl_close($conn);
            http_response_code(500);
            die($errorMessage);
        }
        }


        curl_close($conn);
        curl_close($conn);
+18 −3
Original line number Original line Diff line number Diff line
@@ -91,7 +91,7 @@ class OAuth2RequestHandler {
        return $redirectUrl;
        return $redirectUrl;
    }
    }


    public function handleAccessTokenRequest($params): array {
    public function handleGetTokenFromCodeRequest($params): array {


        $this->locator->getClientAuthChecker()->validateClientAuth();
        $this->locator->getClientAuthChecker()->validateClientAuth();


@@ -123,6 +123,19 @@ class OAuth2RequestHandler {
        return $response;
        return $response;
    }
    }


    public function handleClientCredentialsRequest($params): array {

        $client = $this->locator->getClientAuthChecker()->validateCliClientAuth();

        $accessTokenData = new AccessTokenData();
        $accessTokenData->clientId = $client->id;
        $accessTokenData->userId = $client->id;
        $accessTokenData->scope = $client->scope;
        $accessTokenData->audience = $client->audience;

        return $this->getAccessTokenResponse($accessTokenData, false);
    }

    public function handleRefreshTokenRequest($params): array {
    public function handleRefreshTokenRequest($params): array {


        $this->locator->getClientAuthChecker()->validateClientAuth();
        $this->locator->getClientAuthChecker()->validateClientAuth();
@@ -182,14 +195,16 @@ class OAuth2RequestHandler {
        return $scope;
        return $scope;
    }
    }


    private function getAccessTokenResponse(AccessTokenData $tokenData) {
    private function getAccessTokenResponse(AccessTokenData $tokenData, bool $refreshToken = true) {


        $result = [];
        $result = [];
        $result['access_token'] = $this->locator->getTokenBuilder()->getAccessToken($tokenData);
        $result['access_token'] = $this->locator->getTokenBuilder()->getAccessToken($tokenData);
        $result['token_type'] = 'Bearer';
        $result['token_type'] = 'Bearer';
        $result['expires_in'] = $tokenData->expirationTime - time();
        $result['expires_in'] = $tokenData->expirationTime - time();


        if ($refreshToken) {
            $result['refresh_token'] = $this->buildRefreshToken($tokenData);
            $result['refresh_token'] = $this->buildRefreshToken($tokenData);
        }


        if ($tokenData->scope !== null && in_array('openid', $tokenData->scope)) {
        if ($tokenData->scope !== null && in_array('openid', $tokenData->scope)) {
            $result['id_token'] = $this->locator->getTokenBuilder()->getIdToken($tokenData);
            $result['id_token'] = $this->locator->getTokenBuilder()->getIdToken($tokenData);
+19 −1
Original line number Original line Diff line number Diff line
@@ -58,10 +58,16 @@ class TokenBuilder {
        $keyPair = $this->locator->getJWKSDAO()->getNewestKeyPair();
        $keyPair = $this->locator->getJWKSDAO()->getNewestKeyPair();


        $user = $this->locator->getUserDAO()->findUserById($tokenData->userId);
        $user = $this->locator->getUserDAO()->findUserById($tokenData->userId);
        if ($user === null) {
            // CLI client
            $sub = $tokenData->clientId;
        } else {
            $sub = $user->id;
        }


        $payload = array(
        $payload = array(
            'iss' => $this->locator->config->jwtIssuer,
            'iss' => $this->locator->config->jwtIssuer,
            'sub' => strval($user->id),
            'sub' => strval($sub),
            'iat' => intval($tokenData->creationTime),
            'iat' => intval($tokenData->creationTime),
            'exp' => intval($tokenData->expirationTime),
            'exp' => intval($tokenData->expirationTime),
            'aud' => $this->getAudience($tokenData),
            'aud' => $this->getAudience($tokenData),
@@ -77,7 +83,15 @@ class TokenBuilder {


    private function getAudience(AccessTokenData $tokenData) {
    private function getAudience(AccessTokenData $tokenData) {


        if ($tokenData->audience !== null) {
            return $this->getAudienceClaim($tokenData->audience);
        }

        $client = $this->locator->getOAuth2ClientDAO()->getOAuth2ClientByClientId($tokenData->clientId);
        $client = $this->locator->getOAuth2ClientDAO()->getOAuth2ClientByClientId($tokenData->clientId);
        if ($client === null) {
            // CLI client without audience
            return null;
        }


        $audiences = [$tokenData->clientId];
        $audiences = [$tokenData->clientId];


@@ -90,6 +104,10 @@ class TokenBuilder {
            }
            }
        }
        }


        return $this->getAudienceClaim($audiences);
    }

    private function getAudienceClaim($audiences) {
        if (count($audiences) === 1) {
        if (count($audiences) === 1) {
            // according to RFC 7519 audience can be a single value or an array
            // according to RFC 7519 audience can be a single value or an array
            return $audiences[0];
            return $audiences[0];
+2 −0
Original line number Original line Diff line number Diff line
@@ -20,4 +20,6 @@ interface OAuth2ClientDAO {
     * the secret, not the database id).
     * the secret, not the database id).
     */
     */
    function getOAuth2ClientByClientId($clientId): ?OAuth2Client;
    function getOAuth2ClientByClientId($clientId): ?OAuth2Client;
    
    function getCliClient(string $clientId, string $secret): ?CliClient; 
}
}
Loading