content: package io.aiven.klaw.service;
  
  import io.aiven.klaw.error.KlawNotAuthorizedException;
  import io.jsonwebtoken.Claims;
  import io.jsonwebtoken.Jws;
  import io.jsonwebtoken.Jwts;
  import io.jsonwebtoken.SignatureAlgorithm;
  import java.security.Key;
  import java.util.Date;
  import java.util.List;
  import java.util.function.Function;
  import javax.crypto.spec.SecretKeySpec;
  import org.apache.tomcat.util.codec.binary.Base64;
  import org.springframework.beans.factory.InitializingBean;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  import org.springframework.security.core.userdetails.UserDetails;
  import org.springframework.security.core.userdetails.UserDetailsService;
  import org.springframework.stereotype.Service;
  
  @Service
  @ConditionalOnProperty(prefix = "klaw.core.ha", name = "enable")
  public class JwtTokenUtilService implements InitializingBean {
    @Value("${klaw.core.app2app.base64.secret:#{''}}")
    private String app2AppSecret;
  
    public static final String BEARER = "Bearer ";
    @Autowired UserDetailsService userDetailsService;
    private static byte[] decodedSecret;
  
    // retrieve username from jwt token
    public String getUsernameFromToken(String token) {
      return getClaimFromToken(token, Claims::getSubject);
    }
  
    // retrieve expiration date from jwt token
    private Date getExpirationDateFromToken(String token) {
      return getClaimFromToken(token, Claims::getExpiration);
    }
  
    private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
      final Claims claims = getAllClaimsFromToken(token);
      return claimsResolver.apply(claims);
    }
  
    // for retrieving any information from token we will need the secret key
    public Claims getAllClaimsFromToken(String token) {
      Key hmacKey = new SecretKeySpec(decodedSecret, SignatureAlgorithm.HS256.getJcaName());
      Jws<Claims> jwt = Jwts.parser().setSigningKey(hmacKey).build().parseClaimsJws(token);
      return jwt.getBody();
    }
  
    // check if the token has expired
    private Boolean isTokenExpired(String token) {
      final Date expiration = getExpirationDateFromToken(token);
      return expiration.before(new Date());
    }
  
    // validate token
    public Boolean validateToken(String token) {
      return !isTokenExpired(token);
    }
  
    public void validateRole(String token, String... expectedRole) throws KlawNotAuthorizedException {
  
      token = token.substring(BEARER.length()).trim();
      Claims claims = getAllClaimsFromToken(token);
      UserDetails user = userDetailsService.loadUserByUsername(getUsernameFromToken(token));
      if (user == null
          && !validateToken(token)
          && !claims.get("Roles", List.class).containsAll(List.<String>of(expectedRole))) {
        throw new KlawNotAuthorizedException("UnAuthorized");
      }
    }
  
    // validate secret during app initialization
    @Override
    public void afterPropertiesSet() throws Exception {
      if (app2AppSecret != null && !app2AppSecret.trim().isEmpty()) {
        try {
          decodedSecret = Base64.decodeBase64(app2AppSecret);
          return;
        } catch (Exception e) {
          throw new Exception("Invalid Base64 value configured. klaw.core.app2app.base64.secret");
        }
      }
      throw new Exception("Property not configured. klaw.core.app2app.base64.secret");
    }
  }
  