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

com.sap.cloud.security.spring.token.authentication.ReactiveHybridJwtDecoder Maven / Gradle / Ivy

There is a newer version: 3.5.6
Show newest version
package com.sap.cloud.security.spring.token.authentication;

import com.sap.cloud.security.token.Token;
import com.sap.cloud.security.token.TokenClaims;
import com.sap.cloud.security.token.validation.CombiningValidator;
import com.sap.cloud.security.token.validation.ValidationResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.oauth2.jwt.BadJwtException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;

import java.time.Instant;

public class ReactiveHybridJwtDecoder implements ReactiveJwtDecoder {

	final CombiningValidator xsuaaTokenValidators;
	final CombiningValidator iasTokenValidators;
	private final Logger logger = LoggerFactory.getLogger(getClass());

	public ReactiveHybridJwtDecoder(CombiningValidator xsuaaTokenValidators,
			CombiningValidator iasTokenValidators) {
		this.xsuaaTokenValidators = xsuaaTokenValidators;
		this.iasTokenValidators = iasTokenValidators;
	}

	@Override
	public Mono decode(String encodedToken) throws JwtException {
		return Mono.justOrEmpty(encodedToken)
				.filter(StringUtils::hasText)
				.switchIfEmpty(Mono.error(new BadJwtException("Encoded Token must neither be null nor empty String.")))
				.map(Token::create)
				.flatMap(token -> {
					Mono jwt = parseJwt(token);
					Mono validationResult;

					switch (token.getService()) {
					case IAS:
						if (iasTokenValidators == null) {
							return Mono.error(new BadJwtException("Tokens issued by IAS service aren't accepted"));
						}
						validationResult = Mono.just(iasTokenValidators.validate(token));
						break;
					case XSUAA:
						validationResult = Mono.just(xsuaaTokenValidators.validate(token));
						break;
					default:
						return Mono.error(new BadJwtException(
								"Tokens issued by " + token.getService() + " service aren´t supported."));
					}
					return validationResult
							.filter(vr -> !vr.isErroneous())
							.switchIfEmpty(Mono.error(new BadJwtException(
									"The token is invalid: " + validationResult.block().getErrorDescription())))
							.doOnNext(result -> logger.debug("Token issued by {} service was successfully validated.",
									token.getService()))
							.then(jwt);
				})
				.onErrorMap(RuntimeException.class,
						ex -> new BadJwtException("Error initializing JWT decoder: " + ex.getMessage(), ex));
	}

    static Mono parseJwt(Token token) {
        try{
            Instant issuedAt = token.hasClaim(TokenClaims.XSUAA.ISSUED_AT)
                    ? Instant.ofEpochSecond(Long.parseLong(token.getClaims().get(TokenClaims.XSUAA.ISSUED_AT).toString()))
                    : null;
            return Mono.just(new Jwt(token.getTokenValue(), issuedAt,
                    token.getExpiration(), token.getHeaders(), token.getClaims()));
        }
        catch (NumberFormatException e){
            throw new BadJwtException("Error parsing JWT: " + e.getMessage(), e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy