View Javadoc

1   package com.atlassian.asap.core.validator;
2   
3   import com.atlassian.asap.api.JwsHeader;
4   import com.atlassian.asap.api.JwtClaims;
5   import com.atlassian.asap.api.SigningAlgorithm;
6   import com.atlassian.asap.core.exception.InvalidClaimException;
7   import com.atlassian.asap.core.exception.JwtParseException;
8   import com.atlassian.asap.core.exception.PublicKeyRetrievalException;
9   import com.atlassian.asap.core.exception.SignatureMismatchException;
10  import com.atlassian.asap.core.keys.KeyProvider;
11  import com.atlassian.asap.core.parser.JwtParser;
12  import com.atlassian.asap.core.parser.VerifiableJwt;
13  import org.junit.Before;
14  import org.junit.Test;
15  import org.junit.runner.RunWith;
16  import org.mockito.Mock;
17  import org.mockito.runners.MockitoJUnitRunner;
18  
19  import java.security.PublicKey;
20  import java.util.Collections;
21  import java.util.Optional;
22  
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.fail;
25  import static org.mockito.Mockito.doThrow;
26  import static org.mockito.Mockito.verify;
27  import static org.mockito.Mockito.when;
28  
29  @RunWith(MockitoJUnitRunner.class)
30  public class JwtValidatorImplTest {
31      private static final String ISSUER = "issuer";
32      private static final String SERIALIZED_JWT = "some serialized jwt";
33      private static final String RESOURCE_SERVER_AUDIENCE = "theResourceServerAudience";
34  
35      @Mock
36      private KeyProvider<PublicKey> publicKeyProvider;
37      @Mock
38      private JwtParser jwtParser;
39      @Mock
40      private VerifiableJwt jwt;
41      @Mock
42      private JwsHeader jwsHeader;
43      @Mock
44      private JwtClaims jwtClaims;
45      @Mock
46      private PublicKey publicKey;
47      @Mock
48      private JwtClaimsValidator jwtClaimsValidator;
49  
50      private JwtValidator jwtValidator;
51  
52      @Before
53      public void setUp() throws Exception {
54          when(jwsHeader.getAlgorithm()).thenReturn(SigningAlgorithm.RS256);
55          when(jwt.getHeader()).thenReturn(jwsHeader);
56          when(jwt.getClaims()).thenReturn(jwtClaims);
57          when(jwsHeader.getKeyId()).thenReturn("public-key");
58  
59          jwtValidator = new JwtValidatorImpl(
60                  publicKeyProvider,
61                  jwtParser,
62                  jwtClaimsValidator,
63                  RESOURCE_SERVER_AUDIENCE
64          );
65      }
66  
67      @Test(expected = JwtParseException.class)
68      public void shouldFailIfJwtUnparseable() throws Exception {
69          when(jwtParser.parse(SERIALIZED_JWT)).thenThrow(new JwtParseException("Can't parse jwt"));
70          jwtValidator.readAndValidate(SERIALIZED_JWT);
71      }
72  
73      @Test(expected = PublicKeyRetrievalException.class)
74      public void shouldFailIfPublicKeyNotRetrievable() throws Exception {
75          String issuer = "an issuer without a public key";
76          when(jwt.getClaims().getIssuer()).thenReturn(issuer);
77  
78          when(jwtParser.parse(SERIALIZED_JWT)).thenReturn(jwt);
79          final ValidatedKeyId validatedKeyId = ValidatedKeyId.validate("public-key");
80          when(publicKeyProvider.getKey(validatedKeyId)).thenThrow(new PublicKeyRetrievalException("Can't retrieve public key", validatedKeyId, null));
81  
82          jwtValidator.readAndValidate(SERIALIZED_JWT);
83      }
84  
85      @Test
86      public void shouldFailIfJwtNotVerified() throws Exception {
87          String issuer = "issuer";
88  
89          when(jwt.getClaims().getIssuer()).thenReturn(issuer);
90          when(publicKeyProvider.getKey(ValidatedKeyId.validate("public-key"))).thenReturn(publicKey);
91          when(jwtParser.parse(SERIALIZED_JWT)).thenReturn(jwt);
92          doThrow(new SignatureMismatchException("Couldn't verifySignature jwt")).when(jwt).verifySignature(publicKey);
93  
94          try {
95              jwtValidator.readAndValidate(SERIALIZED_JWT);
96              fail("Should have thrown");
97          } catch (SignatureMismatchException ex) {
98              verify(jwt).verifySignature(publicKey);
99          }
100     }
101 
102     @Test(expected = InvalidClaimException.class)
103     public void shouldFailIfClaimsMismatch() throws Exception {
104         String issuer = "issuer";
105 
106         when(jwt.getClaims().getIssuer()).thenReturn(issuer);
107         when(publicKeyProvider.getKey(ValidatedKeyId.validate("public-key"))).thenReturn(publicKey);
108         when(jwtParser.parse(SERIALIZED_JWT)).thenReturn(jwt);
109         doThrow(new InvalidClaimException(JwtClaims.RegisteredClaim.JWT_ID, "Bad Claim"))
110                 .when(jwtClaimsValidator).validate(jwt, Collections.singleton(RESOURCE_SERVER_AUDIENCE));
111 
112         jwtValidator.readAndValidate(SERIALIZED_JWT);
113     }
114 
115     @Test
116     public void shouldReturnTrueIfVerificationSucceeds() throws Exception {
117         String issuer = "an issuer";
118 
119         when(jwt.getClaims().getIssuer()).thenReturn(issuer);
120         when(publicKeyProvider.getKey(ValidatedKeyId.validate(jwsHeader.getKeyId()))).thenReturn(publicKey);
121         when(jwtParser.parse(SERIALIZED_JWT)).thenReturn(jwt);
122 
123         assertEquals(jwt, jwtValidator.readAndValidate(SERIALIZED_JWT));
124         verify(jwt).verifySignature(publicKey);
125         verify(jwtClaimsValidator).validate(jwt, Collections.singleton(RESOURCE_SERVER_AUDIENCE));
126     }
127 
128     @Test
129     public void shouldDelegateDetermineIssuerToParser() {
130         when(jwtParser.determineUnverifiedIssuer(SERIALIZED_JWT)).thenReturn(Optional.of(ISSUER));
131 
132         Optional<String> issuer = jwtValidator.determineUnverifiedIssuer(SERIALIZED_JWT);
133 
134         assertEquals(ISSUER, issuer.get());
135     }
136 }