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

fi.evolver.basics.spring.auth.JwtAuthorization Maven / Gradle / Ivy

package fi.evolver.basics.spring.auth;

import java.time.Instant;
import java.util.Date;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import fi.evolver.basics.spring.auth.entity.JwtToken;
import fi.evolver.utils.collection.BoundedLinkedHashMap;
import fi.evolver.utils.timing.TimingUtils;


@Component
@ConditionalOnProperty(JwtAuthorization.ENV_AUTHORIZATION_SECRET)
public class JwtAuthorization {
	private static final Logger LOG = LoggerFactory.getLogger(JwtAuthorization.class);

	public static final String ENV_AUTHORIZATION_SECRET = "AUTHORIZATION_SECRET";

	private static final Pattern HEADER_REGEX = Pattern.compile("^Bearer (?.*)$");

	private static final Map cache = new BoundedLinkedHashMap<>(50, BoundedLinkedHashMap.Order.ACCESS);

	private final Algorithm jwtAlgorithm;
	private final JWTVerifier jwtVerifier;
	private final JwtTokenRepository jwtTokenRepository;
	private final String applicationName;

	@Autowired
	public JwtAuthorization(JwtTokenRepository jwtTokenRepository, Environment environment) {
		this.jwtTokenRepository = jwtTokenRepository;
		this.applicationName = environment.getRequiredProperty("application.name.pretty").replaceAll("\\W", "");
		this.jwtAlgorithm = Algorithm.HMAC256(getAuthorizationSecret());
		this.jwtVerifier = JWT.require(jwtAlgorithm)
				.withIssuer(applicationName)
				.build();
		LOG.warn("{}", getAuthorizationSecret());
	}

	public JwtToken authorizeToken(String authorization) {
		CachedToken cached = cache.get(authorization);
		if (cached != null && cached.isValid())
			return cached.getToken();

		Optional jwtToken = parseAuthorization(authorization);
		String jwtId = JwtToken.DEFAULT_JWT_ID;
		if (jwtToken.isPresent()) {
			try {
				jwtId = verifyJwtToken(jwtToken.get()).getId();
			}
			catch (RuntimeException e) {
				LOG.warn("Invalid JWT token", e);
				return JwtToken.INVALID;
			}
		}

		JwtToken result = fetchToken(jwtId);
		cache.put(authorization, new CachedToken(result));
		return result;
	}


	private JwtToken fetchToken(String jwtId) {
		return jwtTokenRepository.findByJwtId(jwtId)
				.stream()
				.findFirst()
				.orElse(JwtToken.UNKNOWN);
	}


	private static Optional parseAuthorization(String authorization) {
		if (authorization == null)
			return Optional.empty();

		Matcher matcher = HEADER_REGEX.matcher(authorization);
		if (!matcher.find())
			throw new IllegalArgumentException("Unsupported authorization");

		return Optional.of(matcher.group("data"));
	}


	public String generateJwtToken(String jwtId) {
		try (TimingUtils.AutoCloser ignored = TimingUtils.begin("JWT", "Create")) {
			return JWT.create()
					.withIssuer(applicationName)
					.withIssuedAt(new Date())
					.withJWTId(jwtId)
					.sign(jwtAlgorithm);
		}
	}


	private DecodedJWT verifyJwtToken(String token) {
		try (TimingUtils.AutoCloser ignored = TimingUtils.begin("JWT", "Verify")) {
			return jwtVerifier.verify(token);
		}
	}


	public static String getAuthorizationSecret() {
		return System.getenv(ENV_AUTHORIZATION_SECRET);
	}


	private static class CachedToken {
		private final Instant validUntil = Instant.now().plusSeconds(60);
		private final JwtToken token;

		public CachedToken(JwtToken token) {
			this.token = token;
		}

		public boolean isValid() {
			return Instant.now().isBefore(validUntil);
		}

		public JwtToken getToken() {
			return token;
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy