-
Notifications
You must be signed in to change notification settings - Fork 0
/
TokenGeneratorTest.java
309 lines (257 loc) · 13.7 KB
/
TokenGeneratorTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
package org.dataone.portal;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.util.Arrays;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import org.dataone.service.types.v1.Session;
import org.dataone.client.auth.CertificateManager;
import org.dataone.configuration.Settings;
import org.junit.Test;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jwt.SignedJWT;
public class TokenGeneratorTest {
public static final String TEST_USER_ID = "test-user-id";
public static final String TEST_FULL_NAME = "Jane Scientist";
public static final String PUB_CERT_KEY = "cn.server.publiccert.filename";
private static final String CERT_BASE = "src/test/resources/org/dataone/portal/";
public static final String LOCAL_CERT_1 = CERT_BASE + "unitTestSelfSignedCert.pem";
public static final String LOCAL_CERT_2 = CERT_BASE + "unitTestSelfSignedCert2.pem";
@Test
public void testBasicCalendarInstanceAssumptions() {
// make sure getInstance() doesn't mean it's a singleton
Calendar x = Calendar.getInstance();
Date now = x.getTime();
Calendar y = Calendar.getInstance();
System.out.println(y);
if (x == y) {
fail("Calendar instances are the same. Not expected");
}
Date later = x.getTime();
if (now.getTime() != later.getTime()) {
fail("Calendar.getTime() should return a constant value over time (a Date object)");
}
}
@Test
public void testFetchServerCertificate() throws IOException {
assertTrue(CertificateManager.getInstance().getSubjectDN(fetchServerCertificate())
.contains("dataone.org"));
}
@Test
public void testGetJWT() throws Exception {
// To parse the JWS and verify it, e.g. on client-side
SignedJWT signedJWT = SignedJWT.parse(getTestToken());
// verify
String certificateFileName =
Settings.getConfiguration().getString(PUB_CERT_KEY);
RSAPublicKey publicKey = (RSAPublicKey) CertificateManager.getInstance()
.loadCertificateFromFile(certificateFileName).getPublicKey();
JWSVerifier verifier = new RSASSAVerifier(publicKey);
assertTrue(signedJWT.verify(verifier));
// make sure the secret is required for verification
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
keyGenerator.initialize(1024);
KeyPair kp = keyGenerator.genKeyPair();
RSAPublicKey otherKey = (RSAPublicKey) kp.getPublic();
JWSVerifier invalidVerifier = new RSASSAVerifier(otherKey);
assertFalse(signedJWT.verify(invalidVerifier));
// Retrieve the JWT claims
assertEquals(TEST_USER_ID, signedJWT.getJWTClaimsSet().getClaim("userId"));
assertEquals(TEST_USER_ID, signedJWT.getJWTClaimsSet().getClaim("sub"));
assertEquals(TEST_USER_ID, signedJWT.getJWTClaimsSet().getSubject());
assertTrue(Calendar.getInstance().getTime()
.before(signedJWT.getJWTClaimsSet().getExpirationTime()));
}
@Test
public void testGetSession() throws Exception {
Session session = TokenGenerator.getInstance().getSession(getTestToken());
assertNotNull(session);
assertEquals(TEST_USER_ID, session.getSubject().getValue());
}
@Test
public void testGetSession_multipleCerts() throws Exception {
// save original values so we can clean up afterward
String pvtKeyKey = "cn.server.privatekey.filename";
String origPvtKey = Settings.getConfiguration().getString(pvtKeyKey);
String origLocalCert = Settings.getConfiguration().getString(PUB_CERT_KEY);
String cnUrlKey = "D1Client.CN_URL";
String origCnUrl = Settings.getConfiguration().getString(cnUrlKey);
////////
// should fail: sign with pvt key 1; verify against pub key 2
Settings.getConfiguration().setProperty(pvtKeyKey, LOCAL_CERT_1);
Settings.getConfiguration().setProperty(PUB_CERT_KEY, LOCAL_CERT_2);
TokenGenerator.getInstance().setPublicKeys();
Session session = TokenGenerator.getInstance().getSession(getTestToken());
assertNull(session);
// should be 2 certs in store: one from CN and 1 local
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 2,
TokenGenerator.publicKeys.size());
// should fail: sign with pvt key 2; verify against pub key 1
Settings.getConfiguration().setProperty(pvtKeyKey, LOCAL_CERT_1);
Settings.getConfiguration().setProperty(PUB_CERT_KEY, LOCAL_CERT_2);
TokenGenerator.getInstance().setPublicKeys();
session = TokenGenerator.getInstance().getSession(getTestToken());
assertNull(session);
// should be 2 certs in store: one from CN and 1 local
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 2,
TokenGenerator.publicKeys.size());
// should pass: sign with pvt key 1; verify against pvt keys 1 & 2
Settings.getConfiguration().setProperty(pvtKeyKey, LOCAL_CERT_1);
Settings.getConfiguration().setProperty(PUB_CERT_KEY, LOCAL_CERT_2 + ";" + LOCAL_CERT_1);
TokenGenerator.getInstance().setPublicKeys();
session = TokenGenerator.getInstance().getSession(getTestToken());
assertNotNull(session);
assertEquals(TEST_USER_ID, session.getSubject().getValue());
// should be 3 certs in store: one from CN and 2 local
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 3,
TokenGenerator.publicKeys.size());
// should pass: sign with pvt key 2; verify against pvt keys 1 & 2
Settings.getConfiguration().setProperty(pvtKeyKey, LOCAL_CERT_2);
Settings.getConfiguration().setProperty(PUB_CERT_KEY, LOCAL_CERT_1 + ";" + LOCAL_CERT_2);
TokenGenerator.getInstance().setPublicKeys();
session = TokenGenerator.getInstance().getSession(getTestToken());
assertNotNull(session);
assertEquals(TEST_USER_ID, session.getSubject().getValue());
// should be 3 certs in store: one from CN and 2 local
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 3,
TokenGenerator.publicKeys.size());
// clean up
Settings.getConfiguration().setProperty(pvtKeyKey, origPvtKey);
Settings.getConfiguration().setProperty(PUB_CERT_KEY, origLocalCert);
Settings.getConfiguration().setProperty(cnUrlKey, origCnUrl);
}
@Test
public void testSetPublicKeys_singleCerts() throws Exception {
String orig = Settings.getConfiguration().getString(PUB_CERT_KEY);
String bogusLocalCert = "/tmp/nonExistentCert.pem";
///////////////////////////////////////////
// Verify 1 local cert & 1 server cert case
// (i.e. backwards compatible)
///////////////////////////////////////////
Settings.getConfiguration().setProperty(PUB_CERT_KEY, LOCAL_CERT_1);
TokenGenerator.getInstance().setPublicKeys();
// should be 2 public keys total: one from disk & one from CN server
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 2,
TokenGenerator.publicKeys.size());
///////////////////////////////////////////
// Verify code can handle missing config
// (i.e. backwards compatible)
///////////////////////////////////////////
Settings.getConfiguration().clearProperty(PUB_CERT_KEY);
TokenGenerator.getInstance().setPublicKeys();
// should be 1 public key total: none from disk & one from CN server
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 1,
TokenGenerator.publicKeys.size());
Settings.getConfiguration().addProperty(PUB_CERT_KEY, null);
TokenGenerator.getInstance().setPublicKeys();
// should be 1 public key total: none from disk & one from CN server
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 1,
TokenGenerator.publicKeys.size());
// Key present, but empty value
Settings.getConfiguration().addProperty(PUB_CERT_KEY, "");
TokenGenerator.getInstance().setPublicKeys();
// should be 1 public key total: none from disk & one from CN server
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 1,
TokenGenerator.publicKeys.size());
// Value set to paths that are invalid in this context (i.e. no filename)
Settings.getConfiguration().addProperty(PUB_CERT_KEY, ".");
TokenGenerator.getInstance().setPublicKeys();
// should be 1 public key total: none from disk & one from CN server
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 1,
TokenGenerator.publicKeys.size());
Settings.getConfiguration().addProperty(PUB_CERT_KEY, "/");
TokenGenerator.getInstance().setPublicKeys();
// should be 1 public key total: none from disk & one from CN server
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 1,
TokenGenerator.publicKeys.size());
// Value set to non-existent path
Settings.getConfiguration().addProperty(PUB_CERT_KEY, bogusLocalCert);
TokenGenerator.getInstance().setPublicKeys();
// should be 1 public key total: none from disk & one from CN server
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 1,
TokenGenerator.publicKeys.size());
// clean up
Settings.getConfiguration().setProperty(PUB_CERT_KEY, orig);
}
@Test
public void testSetPublicKeys_multipleCerts() throws Exception {
String orig = Settings.getConfiguration().getString(PUB_CERT_KEY);
String bogusLocalCert = "/tmp/nonExistentCert.pem";
///////////////////////////////////////////
// Verify 1 present & 1 missing local cert
///////////////////////////////////////////
Settings.getConfiguration()
.setProperty(PUB_CERT_KEY, LOCAL_CERT_1 + ";" + bogusLocalCert);
TokenGenerator.getInstance().setPublicKeys();
// should be 2 public keys total: one from disk & one from CN server. Other one from
// disk
// was a bogus path
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 2,
TokenGenerator.publicKeys.size());
///////////////////////////////////////////
// Verify duplicate local certs appear once
///////////////////////////////////////////
Settings.getConfiguration()
.setProperty(PUB_CERT_KEY, LOCAL_CERT_1 + ";" + LOCAL_CERT_1);
TokenGenerator.getInstance().setPublicKeys();
// should be 2 public keys total: one from disk & one from CN server.
// Other one from disk was a repeat
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 2,
TokenGenerator.publicKeys.size());
// clean up
Settings.getConfiguration().setProperty(PUB_CERT_KEY, orig);
}
@Test
public void testSetPublicKeys_ordering() throws Exception {
////////////////////////////////////////////////////
// Verify duplicate server & local certs appear once
// and server cert appears first in list
////////////////////////////////////////////////////
X509Certificate serverCertCopy = fetchServerCertificate();
assertNotNull(serverCertCopy);
String locServerCertCopy = CERT_BASE + "unitTestLocalServerCertCopy.pem";
Path serverCertCopyFile = null;
try {
String encodedCert = Base64.getEncoder().encodeToString(serverCertCopy.getEncoded());
// Wrap the encoded certificate with PEM headers and footers
String pemCert = "-----BEGIN CERTIFICATE-----\n" + encodedCert + "\n-----END CERTIFICATE-----";
// Write the PEM formatted certificate to a file
serverCertCopyFile = Files.write(Paths.get(locServerCertCopy), pemCert.getBytes());
Settings.getConfiguration().setProperty(
PUB_CERT_KEY, LOCAL_CERT_1 + ";" + locServerCertCopy + ";" + LOCAL_CERT_2);
TokenGenerator.getInstance().setPublicKeys();
// should be 3 public keys total: two from disk & one from CN server.
// Other one from disk was a repeat of server one
assertEquals(Arrays.toString(TokenGenerator.publicKeys.toArray()), 3,
TokenGenerator.publicKeys.size());
// Ensure server cert appears first in list
RSAPublicKey serverPubKey = (RSAPublicKey) serverCertCopy.getPublicKey();
assertEquals(serverPubKey, TokenGenerator.publicKeys.get(0));
} finally {
// delete file
if (serverCertCopyFile != null) {
Files.deleteIfExists(serverCertCopyFile);
}
}
}
private String getTestToken() throws Exception {
return TokenGenerator.getInstance().getJWT(TEST_USER_ID, TEST_FULL_NAME);
}
private X509Certificate fetchServerCertificate() throws IOException {
return (X509Certificate) TokenGenerator.getInstance().fetchServerCertificate();
}
}