Skip to content
Snippets Groups Projects
Select Git revision
  • d919b3bc547d80ace8271a3b32ad884ba48e7d6d
  • main default protected
  • renovate/lock-file-maintenance
  • demo protected
  • person-select-custom
  • dbp-translation-component
  • icon-set-mapping
  • port-i18next-parser
  • remove-sentry
  • favorites-and-recent-files
  • revert-6c632dc6
  • lit2
  • advertisement
  • wc-part
  • automagic
  • publish
  • wip-cleanup
  • demo-file-handling
18 results

rollup.config.js

Blame
  • LocalTokenValidator.php 3.07 KiB
    <?php
    
    declare(strict_types=1);
    
    namespace Dbp\Relay\AuthBundle\Authenticator;
    
    use Dbp\Relay\AuthBundle\OIDC\OIDError;
    use Dbp\Relay\AuthBundle\OIDC\OIDProvider;
    use Jose\Component\Core\JWKSet;
    use Jose\Easy\Load;
    use Jose\Easy\Validate;
    
    class LocalTokenValidator extends TokenValidatorBase
    {
        private $oidProvider;
        private $leewaySeconds;
    
        public function __construct(OIDProvider $oidProvider, int $leewaySeconds)
        {
            $this->oidProvider = $oidProvider;
            $this->leewaySeconds = $leewaySeconds;
        }
    
        /**
         * Validates the token locally using the public JWK of the OIDC server.
         *
         * This is faster because everything can be cached, but tokens/sessions revoked on the OIDC server
         * will still be considered valid as long as they are not expired.
         *
         * @return array the token
         *
         * @throws TokenValidationException
         */
        public function validate(string $accessToken): array
        {
            try {
                $jwks = $this->oidProvider->getJWKs();
                $providerConfig = $this->oidProvider->getProviderConfig();
            } catch (OIDError $e) {
                throw new TokenValidationException($e->getMessage());
            }
    
            $issuer = $providerConfig->getIssuer();
            // Allow the same algorithms that the introspection endpoint allows
            $algs = $providerConfig->getIntrospectionEndpointSigningAlgorithms();
            // The spec doesn't allow this, but just to be sure
            assert(!in_array('none', $algs, true));
    
            // Checks not needed/used here:
            // * sub(): This is the keycloak user ID by default, nothing we know beforehand
            // * jti(): Nothing we know beforehand
            // * aud(): The audience needs to be checked afterwards with checkAudience()
            try {
                $keySet = JWKSet::createFromKeyData($jwks);
                $validate = Load::jws($accessToken);
                $validate = $validate
                    ->algs($algs)
                    ->keyset($keySet)
                    ->exp($this->leewaySeconds)
                    ->iat($this->leewaySeconds)
                    ->nbf($this->leewaySeconds)
                    ->iss($issuer);
                assert($validate instanceof Validate);
                $jwtResult = $validate->run();
            } catch (\Exception $e) {
                throw new TokenValidationException('Token validation failed: '.$e->getMessage());
            }
    
            $jwt = $jwtResult->claims->all();
    
            // XXX: Keycloak will add extra data to the token returned by introspection, mirror this behaviour here
            // to avoid breakage when switching between local/remote validation.
            // https://github.com/keycloak/keycloak/blob/8225157a1cecef30034530aa/services/src/main/java/org/keycloak/protocol/oidc/AccessTokenIntrospectionProvider.java#L59
            if (isset($jwt['preferred_username'])) {
                $jwt['username'] = $jwt['preferred_username'];
            }
            if (!isset($jwt['username'])) {
                $jwt['username'] = null;
            }
            if (isset($jwt['azp'])) {
                $jwt['client_id'] = $jwt['azp'];
            }
            $jwt['active'] = true;
    
            return $jwt;
        }
    }