1 package com.atlassian.security.auth.trustedapps.filter;
2
3 import java.security.KeyPair;
4 import java.security.NoSuchAlgorithmException;
5 import java.security.NoSuchProviderException;
6 import java.security.Principal;
7
8 import javax.servlet.http.HttpServletRequest;
9
10 import com.atlassian.security.auth.trustedapps.ApplicationCertificate;
11 import com.atlassian.security.auth.trustedapps.BouncyCastleEncryptionProvider;
12 import com.atlassian.security.auth.trustedapps.CurrentApplication;
13 import com.atlassian.security.auth.trustedapps.DefaultCurrentApplication;
14 import com.atlassian.security.auth.trustedapps.DefaultTrustedApplication;
15 import com.atlassian.security.auth.trustedapps.EncryptedCertificate;
16 import com.atlassian.security.auth.trustedapps.EncryptionProvider;
17 import com.atlassian.security.auth.trustedapps.InvalidCertificateException;
18 import com.atlassian.security.auth.trustedapps.InvalidRemoteAddressException;
19 import com.atlassian.security.auth.trustedapps.InvalidRequestException;
20 import com.atlassian.security.auth.trustedapps.InvalidRequestUrlException;
21 import com.atlassian.security.auth.trustedapps.InvalidXForwardedForAddressException;
22 import com.atlassian.security.auth.trustedapps.RequestConditions;
23 import com.atlassian.security.auth.trustedapps.TrustedApplication;
24 import com.atlassian.security.auth.trustedapps.TrustedApplicationUtils;
25 import com.atlassian.security.auth.trustedapps.TrustedApplicationsManager;
26 import com.atlassian.security.auth.trustedapps.UserResolver;
27
28 import junit.framework.TestCase;
29
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.when;
32
33
34
35
36 public class TestTrustedApplicationsFilterAuthenticate extends TestCase
37 {
38
39
40
41
42 private final EncryptionProvider provider = new BouncyCastleEncryptionProvider();
43 private final TrustedApplicationsManager manager = new TrustedApplicationsManager()
44 {
45 final KeyPair pair;
46 final CurrentApplication me;
47
48 {
49 try
50 {
51 pair = provider.generateNewKeyPair();
52 }
53 catch (NoSuchAlgorithmException e)
54 {
55 throw new RuntimeException(e);
56 }
57 catch (NoSuchProviderException e)
58 {
59 throw new RuntimeException(e);
60 }
61 me = new DefaultCurrentApplication(pair.getPublic(), pair.getPrivate(), "me");
62 }
63
64 public CurrentApplication getCurrentApplication()
65 {
66 return me;
67 }
68
69 public TrustedApplication getTrustedApplication(String id)
70 {
71 if (id.equals("me"))
72 {
73 return new DefaultTrustedApplication(provider, pair.getPublic(), "me", RequestConditions.builder().setCertificateTimeout(1000L).build())
74 {
75 @Override
76 protected void checkRequest(HttpServletRequest request) throws InvalidCertificateException
77 {
78 try
79 {
80 if (request.getHeader("ip-mismatch") != null)
81 {
82 throw new InvalidRemoteAddressException(request.getRemoteAddr());
83 }
84 if (request.getHeader("forward-mismatch") != null)
85 {
86 throw new InvalidXForwardedForAddressException(request.getRemoteAddr());
87 }
88 if (request.getHeader("url-mismatch") != null)
89 {
90 throw new InvalidRequestUrlException(request.getPathInfo());
91 }
92 }
93 catch (final InvalidRequestException e)
94 {
95 throw new InvalidCertificateException(e);
96 }
97 }
98 };
99 }
100 return null;
101 }
102 };
103
104 private Principal principal = null;
105 private final UserResolver userResolver = new UserResolver()
106 {
107 public Principal resolve(ApplicationCertificate certificate)
108 {
109 return principal;
110 }
111 };
112 private final TrustedApplicationsFilter filter = new TrustedApplicationsFilter(manager, userResolver, new AuthenticationController()
113 {
114 public boolean canLogin(Principal user, HttpServletRequest request)
115 {
116 return true;
117 }
118
119 public boolean shouldAttemptAuthentication(HttpServletRequest request)
120 {
121 return true;
122 }
123
124 }, mock(AuthenticationListener.class));
125
126 protected void setUp() throws Exception
127 {
128 principal = null;
129 }
130
131
132
133
134
135 public void testNoTrustedAppAttempt() throws Exception
136 {
137 MockRequest request = new MockRequest("/some/path");
138 MockResponse response = new MockResponse();
139 assertFalse(filter.authenticate(request, response));
140
141 final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
142 assertNull(error, error);
143 }
144
145 public void testKnownAppProtocolVersion0() throws Exception
146 {
147 CurrentApplication me = manager.getCurrentApplication();
148 principal = new Principal()
149 {
150 public String getName()
151 {
152 return "blah-de-blah-blah";
153 }
154 };
155 EncryptedCertificate cert = me.encode("blah-de-blah-blah");
156 MockRequest request = new MockTrustedAppRequestV0(cert);
157 MockResponse response = new MockResponse();
158 assertTrue(filter.authenticate(request, response));
159
160 final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
161 assertNull(error, error);
162 }
163
164 public void testKnownAppProtocolVersion1() throws Exception
165 {
166 CurrentApplication me = manager.getCurrentApplication();
167 principal = new Principal()
168 {
169 public String getName()
170 {
171 return "blah-de-blah-blah";
172 }
173 };
174 EncryptedCertificate cert = me.encode("blah-de-blah-blah");
175 MockRequest request = new MockTrustedAppRequestV1(cert);
176
177 MockResponse response = new MockResponse();
178 assertTrue(filter.authenticate(request, response));
179
180 final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
181 assertNull(error, error);
182 }
183
184 public void testUnknownApp() throws Exception
185 {
186 EncryptedCertificate cert = mock(EncryptedCertificate.class);
187 when(cert.getCertificate()).thenReturn("cert");
188 when(cert.getID()).thenReturn("appId");
189 when(cert.getMagicNumber()).thenReturn("majick");
190 when(cert.getSecretKey()).thenReturn("dis-is-a-sekrit");
191
192 MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
193 assertFailed("Unknown Application:", request);
194 }
195
196 public void testBadSecretKey() throws Exception
197 {
198 CurrentApplication me = manager.getCurrentApplication();
199 EncryptedCertificate cert = me.encode("blad-de-blah-blah");
200 MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
201 request.addHeader(TrustedApplicationUtils.Header.Request.SECRET_KEY, "0123981237123827234842374");
202 assertError("BAD_MAGIC;\tUnable to decrypt certificate {0} for application {1};\t[\"secret key\",\"me\"]", request);
203 }
204
205 public void testBadCertificate() throws Exception
206 {
207 CurrentApplication me = manager.getCurrentApplication();
208 EncryptedCertificate cert = me.encode("blad-de-blah-blah");
209 MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
210 request.addHeader(TrustedApplicationUtils.Header.Request.CERTIFICATE, "0123981237123827234842374");
211 assertError("BAD_MAGIC;\tUnable to decrypt certificate {0} for application {1};\t[\"secret key\",\"me\"]", request);
212 }
213
214 public void testBadPublicKey() throws Exception
215 {
216 CurrentApplication me = manager.getCurrentApplication();
217 EncryptedCertificate cert = me.encode("blad-de-blah-blah");
218 MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
219 request.addHeader(TrustedApplicationUtils.Header.Request.MAGIC, "123798211233723187217");
220 assertError("BAD_MAGIC;\tUnable to decrypt certificate {0} for application {1};\t[\"public key\",\"me\"]", request);
221 }
222
223 public void testBadRequestIp() throws Exception
224 {
225 CurrentApplication me = manager.getCurrentApplication();
226 EncryptedCertificate cert = me.encode("blad-de-blah-blah");
227 MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
228 request.addHeader("ip-mismatch", "true");
229 assertError("BAD_REMOTE_IP;\tRequest not allowed from IP address: {0};\t[\"i.am.a.teapot\"]", request);
230 }
231
232 public void testBadXForwardIp() throws Exception
233 {
234 CurrentApplication me = manager.getCurrentApplication();
235 EncryptedCertificate cert = me.encode("blad-de-blah-blah");
236 MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
237 request.addHeader("forward-mismatch", "true");
238 assertError("BAD_XFORWARD_IP;\tRequest not allowed from IP address: {0};\t[\"i.am.a.teapot\"]", request);
239 }
240
241 public void testBadRequestUrl() throws Exception
242 {
243 CurrentApplication me = manager.getCurrentApplication();
244 EncryptedCertificate cert = me.encode("blad-de-blah-blah");
245 MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1("/jira/secure/DeleteProject.jspa", cert);
246 request.addHeader("url-mismatch", "true");
247 assertError("BAD_URL;\tRequest not allowed to access URL: {0};\t[\"/jira/secure/DeleteProject.jspa\"]", request);
248 }
249
250
251
252
253
254 private void assertFailed(String msg, MockRequest request)
255 {
256 MockResponse response = new MockResponse();
257
258 assertFalse(filter.authenticate(request, response));
259
260 final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
261 System.out.println(error);
262 assertNotNull(error);
263 assertTrue("Expected: '" + msg + "' got:" + error, error.indexOf(msg) >= 0);
264 }
265
266 private void assertError(String msg, MockRequest request)
267 {
268 MockResponse response = new MockResponse();
269
270 assertFalse(filter.authenticate(request, response));
271
272 final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
273 System.out.println(error);
274 assertNotNull(error);
275 assertEquals(msg, error);
276
277 }
278 }