1 package com.atlassian.asap.core.server.http;
2
3 import com.atlassian.asap.api.Jwt;
4 import com.atlassian.asap.api.exception.AuthenticationFailedException;
5 import com.atlassian.asap.api.exception.CannotRetrieveKeyException;
6 import com.atlassian.asap.api.exception.InvalidTokenException;
7 import com.atlassian.asap.api.exception.PermanentAuthenticationFailedException;
8 import com.atlassian.asap.api.exception.TransientAuthenticationFailedException;
9 import com.atlassian.asap.api.server.http.RequestAuthenticator;
10 import com.atlassian.asap.core.JwtConstants;
11 import com.atlassian.asap.core.exception.PublicKeyNotFoundException;
12 import com.atlassian.asap.core.validator.JwtValidator;
13 import org.apache.commons.lang3.StringUtils;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16
17 import java.util.Objects;
18 import java.util.Optional;
19
20 import static java.lang.String.format;
21
22 public class RequestAuthenticatorImpl implements RequestAuthenticator {
23 private static final Logger logger = LoggerFactory.getLogger(RequestAuthenticatorImpl.class);
24
25 private final JwtValidator jwtValidator;
26
27 public RequestAuthenticatorImpl(JwtValidator jwtValidator) {
28 this.jwtValidator = Objects.requireNonNull(jwtValidator);
29 }
30
31 @Override
32 public Jwt authenticateRequest(String authorizationHeader) throws AuthenticationFailedException {
33 if (StringUtils.isBlank(authorizationHeader)) {
34 throw new PermanentAuthenticationFailedException("Authorization header is missing");
35 }
36
37 if (!authorizationHeader.startsWith(JwtConstants.HTTP_AUTHORIZATION_HEADER_VALUE_PREFIX)) {
38 throw new PermanentAuthenticationFailedException("Authorization header is not in the expected format. Expected format is 'Bearer <jwt token>'");
39 }
40
41 String serializedJwt = StringUtils.removeStart(authorizationHeader, JwtConstants.HTTP_AUTHORIZATION_HEADER_VALUE_PREFIX);
42 try {
43 return jwtValidator.readAndValidate(serializedJwt);
44 } catch (PublicKeyNotFoundException e) {
45
46 logger.debug("Public key not found when authenticating request: {}", e.getKeyId(), e);
47
48
49
50 final Optional<String> issuer = getUnverifiedIssuer(serializedJwt);
51 throw new PermanentAuthenticationFailedException(
52 format("Public key not found when authenticating request from %s: %s",
53 formatIssuer(issuer), e.getMessage()),
54 issuer.orElse(null));
55 } catch (CannotRetrieveKeyException e) {
56
57 logger.error("Error retrieving key required to authenticate request", e);
58
59
60
61 final Optional<String> issuer = getUnverifiedIssuer(serializedJwt);
62 throw new TransientAuthenticationFailedException(
63 format("Failed to retrieve the key required to authenticate request from %s: %s",
64 formatIssuer(issuer), e.getMessage()),
65 e.getKeyId().orElse(null),
66 e.getKeyUri().orElse(null),
67 issuer.orElse(null));
68 } catch (InvalidTokenException e) {
69
70 logger.debug("Failed to authenticate request", e);
71
72
73
74
75 final Optional<String> issuer = getUnverifiedIssuer(serializedJwt);
76 throw new PermanentAuthenticationFailedException(
77 format("Failed to authenticate request from %s: %s", formatIssuer(issuer), e.getSafeDetails()),
78 issuer.orElse(null));
79 }
80 }
81
82 private Optional<String> getUnverifiedIssuer(String serializedJwt) {
83 return jwtValidator.determineUnverifiedIssuer(serializedJwt);
84 }
85
86 @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
87 private static String formatIssuer(Optional<String> issuer) {
88 return issuer.map(iss -> iss + " (issuer not verified)").orElse("unknown issuer");
89 }
90 }