setEncryptionKeyPath($options['encryptionKeyPath']); unset($options['encryptionKeyPath']); } parent::__construct($options, $collaborators); } /** * Attempts to decrypt the given response. * * @param string|array|null $response * * @return string|array|null */ public function decryptResponse($response) { if (is_string($response)) { if ($this->encryptionAlgorithm && $this->encryptionKey) { $response = json_decode( json_encode( JWT::decode( $response, $this->encryptionKey, array($this->encryptionAlgorithm) ) ), true ); } else { throw new EncryptionConfigurationException( 'The given response may be encrypted and sufficient '. 'encryption configuration has not been provided.', 400 ); } } return $response; } /** * Get authorization url to begin OAuth flow * * @return string */ public function getBaseAuthorizationUrl() { return $this->getBaseUrlWithRealm().'/protocol/openid-connect/auth'; } /** * Get access token url to retrieve token * * @param array $params * * @return string */ public function getBaseAccessTokenUrl(array $params) { return $this->getBaseUrlWithRealm().'/protocol/openid-connect/token'; } /** * Get provider url to fetch user details * * @param AccessToken $token * * @return string */ public function getResourceOwnerDetailsUrl(AccessToken $token) { return $this->getBaseUrlWithRealm().'/protocol/openid-connect/userinfo'; } /** * Creates base url from provider configuration. * * @return string */ protected function getBaseUrlWithRealm() { return $this->authServerUrl.'/realms/'.$this->realm; } /** * Get the default scopes used by this provider. * * This should not be a complete list of all scopes, but the minimum * required for the provider user interface! * * @return string[] */ protected function getDefaultScopes() { return ['name', 'email']; } /** * Check a provider response for errors. * * @throws IdentityProviderException * @param ResponseInterface $response * @param string $data Parsed response data * @return void */ protected function checkResponse(ResponseInterface $response, $data) { if (!empty($data['error'])) { $error = $data['error'].': '.$data['error_description']; throw new IdentityProviderException($error, 0, $data); } } /** * Generate a user object from a successful user details request. * * @param array $response * @param AccessToken $token * @return KeycloakResourceOwner */ protected function createResourceOwner(array $response, AccessToken $token) { return new KeycloakResourceOwner($response); } /** * Requests and returns the resource owner of given access token. * * @param AccessToken $token * @return KeycloakResourceOwner */ public function getResourceOwner(AccessToken $token) { $response = $this->fetchResourceOwnerDetails($token); $response = $this->decryptResponse($response); return $this->createResourceOwner($response, $token); } /** * Updates expected encryption algorithm of Keycloak instance. * * @param string $encryptionAlgorithm * * @return Keycloak */ public function setEncryptionAlgorithm($encryptionAlgorithm) { $this->encryptionAlgorithm = $encryptionAlgorithm; return $this; } /** * Updates expected encryption key of Keycloak instance. * * @param string $encryptionKey * * @return Keycloak */ public function setEncryptionKey($encryptionKey) { $this->encryptionKey = $encryptionKey; return $this; } /** * Updates expected encryption key of Keycloak instance to content of given * file path. * * @param string $encryptionKeyPath * * @return Keycloak */ public function setEncryptionKeyPath($encryptionKeyPath) { try { $this->encryptionKey = file_get_contents($encryptionKeyPath); } catch (Exception $e) { // Not sure how to handle this yet. } return $this; } }