1 package com.atlassian.asap.core.server.springsecurity;
2
3 import com.atlassian.asap.api.Jwt;
4 import com.atlassian.asap.api.JwtBuilder;
5 import com.atlassian.asap.core.exception.InvalidHeaderException;
6 import com.atlassian.asap.core.exception.JwtParseException;
7 import com.atlassian.asap.core.exception.PublicKeyNotFoundException;
8 import com.atlassian.asap.core.exception.PublicKeyRetrievalException;
9 import com.atlassian.asap.core.validator.JwtValidator;
10 import com.atlassian.asap.core.validator.ValidatedKeyId;
11 import org.junit.Before;
12 import org.junit.Rule;
13 import org.junit.Test;
14 import org.mockito.Mock;
15 import org.mockito.junit.MockitoJUnit;
16 import org.mockito.junit.MockitoRule;
17 import org.springframework.security.authentication.AuthenticationServiceException;
18 import org.springframework.security.authentication.BadCredentialsException;
19 import org.springframework.security.authentication.InsufficientAuthenticationException;
20 import org.springframework.security.core.Authentication;
21 import org.springframework.security.core.AuthenticationException;
22 import org.springframework.security.core.GrantedAuthority;
23
24 import java.io.Serializable;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Optional;
28
29 import static org.hamcrest.MatcherAssert.assertThat;
30 import static org.hamcrest.Matchers.contains;
31 import static org.hamcrest.Matchers.instanceOf;
32 import static org.junit.Assert.assertEquals;
33 import static org.mockito.Mockito.when;
34
35 public class AsapAuthenticationProviderTest {
36 private static final String SERIALISED_TOKEN = "my-token";
37 private static final Jwt JWT = JwtBuilder.newJwt().keyId("key-id").issuer("issuer").audience("audience").build();
38
39 @Rule
40 public MockitoRule mockitoRule = MockitoJUnit.rule();
41
42 @Mock
43 private Authentication authentication;
44
45 @Mock
46 private JwtValidator jwtValidator;
47
48 @Mock
49 private GrantedAuthority grantedAuthority;
50
51 private ValidatedKeyId validatedKeyId;
52
53 @Before
54 public void prepareValidatedKey() throws InvalidHeaderException {
55 validatedKeyId = ValidatedKeyId.validate("key-id");
56 }
57
58 @Before
59 public void prepareAuthenticationContext() {
60 when(authentication.getCredentials()).thenReturn(SERIALISED_TOKEN);
61 }
62
63 @Test(expected = BadCredentialsException.class)
64 public void shouldFailIfTokenIsInvalid() throws Exception {
65 when(jwtValidator.readAndValidate(SERIALISED_TOKEN))
66 .thenThrow(new JwtParseException("token is invalid"));
67
68 createSut().authenticate(authentication);
69 }
70
71 @Test(expected = AuthenticationServiceException.class)
72 public void shouldFailIfRetrievingPublicKeyFails() throws Exception {
73
74 when(jwtValidator.readAndValidate(SERIALISED_TOKEN))
75 .thenThrow(new PublicKeyRetrievalException("key repo fail", validatedKeyId, null));
76
77 createSut().authenticate(authentication);
78 }
79
80 @Test(expected = BadCredentialsException.class)
81 public void shouldFailIfPublicKeyCannotBeFound() throws Exception {
82
83 when(jwtValidator.readAndValidate(SERIALISED_TOKEN))
84 .thenThrow(new PublicKeyNotFoundException("public key not found", validatedKeyId, null));
85
86 createSut().authenticate(authentication);
87 }
88
89 @Test
90 public void shouldReturnDefaultGrantedAuthoritiesAndSerializableJwtIfValidationSucceeds() throws Exception {
91 when(jwtValidator.readAndValidate(SERIALISED_TOKEN)).thenReturn(JWT);
92
93 Authentication authenticationResult = createSut().authenticate(authentication);
94 assertEquals("issuer", authenticationResult.getPrincipal());
95 assertEquals(JWT, authenticationResult.getCredentials());
96 assertThat(authenticationResult.getCredentials(), instanceOf(Serializable.class));
97 assertThat(authenticationResult.getAuthorities(), contains(grantedAuthority));
98 }
99
100 @Test(expected = InsufficientAuthenticationException.class)
101 public void shouldFailIfPrincipalValidationFails() throws Exception {
102 AsapAuthenticationProvider sut = new AsapAuthenticationProvider(jwtValidator) {
103 @Override
104 protected Collection<GrantedAuthority> getGrantedAuthorities(Jwt validJwt) throws AuthenticationException {
105 throw new InsufficientAuthenticationException("no, you cannot authenticate");
106 }
107 };
108
109 when(jwtValidator.readAndValidate(SERIALISED_TOKEN)).thenReturn(JWT);
110
111 sut.authenticate(authentication);
112 }
113
114 @Test
115 public void effectiveSubjectIsTheSubjectIfPresent() throws Exception {
116 Jwt jwtWithSubject = JwtBuilder.copyJwt(JWT).subject(Optional.of("explicit-subject")).build();
117 assertEquals("explicit-subject", AsapAuthenticationProvider.effectiveSubject(jwtWithSubject));
118 }
119
120 @Test
121 public void effectiveSubjectIsTheIssuerIfSubjectNotPresent() throws Exception {
122 Jwt jwtWithoutSubject = JwtBuilder.copyJwt(JWT).subject(Optional.<String>empty()).build();
123 assertEquals(JWT.getClaims().getIssuer(), AsapAuthenticationProvider.effectiveSubject(jwtWithoutSubject));
124 }
125
126 private AsapAuthenticationProvider createSut() {
127 return new AsapAuthenticationProvider(jwtValidator, Collections.singleton(grantedAuthority));
128 }
129 }