All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.cloud.sdk.cloudplatform.security.AuthTokenDecoder Maven / Gradle / Ivy

/*
 * Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved.
 */

package com.sap.cloud.sdk.cloudplatform.security;

import java.security.interfaces.RSAPublicKey;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;

import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.net.HttpHeaders;
import com.sap.cloud.sdk.cloudplatform.security.exception.AuthTokenAccessException;

import io.vavr.control.Try;

class AuthTokenDecoder
{
    // We handle the value of Authorization header case insensitive. To prevent repetitive toLowerCase calls we store this prefix in lower case.
    private static final String BEARER_PREFIX = "bearer ";

    private int getNumberOfAuthHeaders( final HttpServletRequest request )
    {
        @Nullable
        final Enumeration headers = request.getHeaders(HttpHeaders.AUTHORIZATION);

        int numHeaders = 0;
        if( headers != null ) {
            while( headers.hasMoreElements() ) {
                headers.nextElement();
                ++numHeaders;
            }
        }

        return numHeaders;
    }

    @Nonnull
    AuthToken decode( @Nonnull final String encodedJwt, @Nullable final String refreshToken )
        throws AuthTokenAccessException
    {
        final List verificationKeys = AuthTokenValidator.getVerificationPublicKeysForJwt(encodedJwt);
        final String targetAlgorithm =
            Try.of(() -> JWT.decode(encodedJwt).getAlgorithm()).getOrElseThrow(
                e -> new AuthTokenAccessException("Failed to verify JWT bearer.", e));

        final AuthTokenValidator authTokenValidator = new AuthTokenValidator(targetAlgorithm, verificationKeys);

        Optional verifiedToken = authTokenValidator.verifyToken(encodedJwt);

        // fallback: use refresh token to request new access token and try to verify once more
        if( !verifiedToken.isPresent() && refreshToken != null ) {
            final String refreshedEncodedJwt = new RefreshJwtTokenCommand(encodedJwt, refreshToken).run();
            verifiedToken = authTokenValidator.verifyToken(refreshedEncodedJwt);
        }

        return verifiedToken.map(AuthToken::new).orElseThrow(
            () -> new AuthTokenAccessException("Failed to verify JWT bearer."));
    }

    @Nonnull
    Optional decode( @Nonnull final HttpServletRequest request )
        throws AuthTokenAccessException
    {
        @Nullable
        final String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);

        if( authorizationHeader == null ) {
            return Optional.empty();
        }

        if( getNumberOfAuthHeaders(request) != 1 ) {
            throw new AuthTokenAccessException(
                "Failed to decode JWT bearer: multiple '"
                    + HttpHeaders.AUTHORIZATION
                    + "' headers present in request.");
        }

        if( !authorizationHeader.toLowerCase(Locale.ENGLISH).startsWith(BEARER_PREFIX) ) {
            throw new AuthTokenAccessException(
                "Failed to decode JWT bearer: no JWT bearer present in '"
                    + HttpHeaders.AUTHORIZATION
                    + "' header of request.");
        }

        final String tokenValue = authorizationHeader.substring(BEARER_PREFIX.length());
        return Optional.of(decode(tokenValue, null));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy