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 package org.ogf.graap.wsag.api.security;
36
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.security.KeyStore;
40 import java.security.KeyStoreException;
41 import java.security.NoSuchAlgorithmException;
42 import java.security.PrivateKey;
43 import java.security.cert.Certificate;
44 import java.security.cert.CertificateException;
45 import java.security.cert.X509Certificate;
46 import java.text.MessageFormat;
47 import java.util.Map;
48
49 import javax.security.auth.Subject;
50 import javax.security.auth.callback.Callback;
51 import javax.security.auth.callback.CallbackHandler;
52 import javax.security.auth.callback.UnsupportedCallbackException;
53 import javax.security.auth.login.LoginException;
54 import javax.security.auth.spi.LoginModule;
55 import javax.security.auth.x500.X500Principal;
56 import javax.security.auth.x500.X500PrivateCredential;
57
58 import org.ogf.graap.wsag.api.configuration.WSAG4JConfiguration;
59
60
61
62
63
64
65
66 public class KeystoreLoginModule
67 implements LoginModule
68 {
69 private Subject klmSubject;
70
71 private CallbackHandler cbHandler;
72
73
74
75 @SuppressWarnings( "rawtypes" )
76 private Map klmOptions;
77
78
79 private KeyStore keystore;
80
81 private String keystoreType;
82
83 private String keystoreFile;
84
85 private String keystorePassword;
86
87 private String alias;
88
89 private String privateKeyPassword;
90
91 private String truststoreType;
92
93 private String truststoreFile;
94
95 private String truststorePassword;
96
97
98 private X500Principal userPrincipal;
99
100
101 private boolean login = false;
102
103 private boolean commit = false;
104
105
106
107
108
109
110
111 @SuppressWarnings( "rawtypes" )
112 public void initialize( Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options )
113 {
114 this.klmSubject = subject;
115 this.cbHandler = callbackHandler;
116
117 this.klmOptions = options;
118
119 initializeOptions();
120 }
121
122 private void initializeOptions()
123 {
124
125 keystoreFile = (String) klmOptions.get( "keyStoreURL" );
126 keystoreType = (String) klmOptions.get( "keyStoreType" );
127 alias = (String) klmOptions.get( "keyStoreAlias" );
128
129 truststoreFile = (String) klmOptions.get( "trustStoreURL" );
130 truststoreType = (String) klmOptions.get( "trustStoreType" );
131
132
133
134
135
136
137
138 keystoreType = ( keystoreType == null ) ? "JKS" : keystoreType;
139 truststoreType = ( truststoreType == null ) ? "JKS" : truststoreType;
140 }
141
142
143
144
145
146
147 public boolean login() throws LoginException
148 {
149 KeystoreCallback ksCallback = new KeystoreCallback();
150 Callback[] callbacks = new Callback[] { ksCallback };
151
152
153 try
154 {
155 cbHandler.handle( callbacks );
156 }
157 catch ( IOException e )
158 {
159 String message = "IO error during login";
160 LoginException le = new LoginException( message );
161 le.initCause( e );
162 throw le;
163 }
164 catch ( UnsupportedCallbackException e )
165 {
166 String message = "Invalid callback handler. Callback not supported.";
167 LoginException le = new LoginException( message );
168 le.initCause( e );
169 throw le;
170 }
171
172 keystorePassword = ksCallback.getKeystorePassword();
173
174 truststorePassword = ksCallback.getTruststorePassword();
175
176 privateKeyPassword = ksCallback.getPrivateKeyPassword();
177
178
179
180
181
182
183
184
185 if ( ( keystoreFile == null ) || ( keystorePassword == null ) || ( privateKeyPassword == null ) )
186 {
187
188 String message =
189 "Missing required parameter. "
190 + "The KeystoreLoginModule requires the following parameters: "
191 + "[keystoreFilename, keystorePassword, alias, privateKeyPassword]";
192
193 throw new LoginException( message );
194 }
195
196 loadKeyStore();
197
198 login = true;
199
200 return true;
201 }
202
203
204
205
206
207
208 public boolean commit() throws LoginException
209 {
210 if ( !login )
211 {
212 return false;
213 }
214
215 PrivateKey userKey;
216 X500PrivateCredential userCredential;
217 X509Certificate[] userCertificateChain;
218
219 try
220 {
221 userCertificateChain = getCertificates( alias );
222 userKey = (PrivateKey) keystore.getKey( alias, privateKeyPassword.toCharArray() );
223 }
224 catch ( KeyStoreException e )
225 {
226
227 String message = "Could not get default certificate from KeyStoreManager";
228 LoginException le = new LoginException( message );
229 le.initCause( e );
230 throw le;
231 }
232 catch ( Exception e )
233 {
234
235 String message = "Could not get private key from KeyStoreManager";
236 LoginException le = new LoginException( message );
237 le.initCause( e );
238 throw le;
239 }
240
241 if ( userCertificateChain == null )
242 {
243 Object[] filler = new Object[] { alias };
244 String message = MessageFormat.format( "No certificates found for user {0}", filler );
245 throw new LoginException( message );
246 }
247
248 userCredential = new X500PrivateCredential( userCertificateChain[0], userKey );
249
250 userPrincipal =
251 new X500Principal( userCredential.getCertificate().getSubjectX500Principal().getName() );
252
253 klmSubject.getPrivateCredentials().add( userCredential );
254 klmSubject.getPrivateCredentials().add( keystore );
255 klmSubject.getPrincipals().add( userPrincipal );
256
257 commit = true;
258
259 return true;
260 }
261
262
263
264
265
266
267 public boolean abort() throws LoginException
268 {
269 if ( !login )
270 {
271 return false;
272 }
273 if ( ( login ) && ( !commit ) )
274 {
275
276 login = false;
277
278 klmSubject.getPrincipals().remove( userPrincipal );
279
280
281 userPrincipal = null;
282
283 keystore = null;
284 keystoreFile = null;
285 keystorePassword = null;
286 keystoreType = null;
287
288 alias = null;
289 privateKeyPassword = null;
290 }
291 else
292 {
293
294
295 logout();
296 }
297
298 return true;
299 }
300
301
302
303
304
305
306 public boolean logout() throws LoginException
307 {
308 klmSubject.getPrincipals().remove( userPrincipal );
309 klmSubject.getPrivateCredentials().remove( keystore );
310
311 login = false;
312 commit = false;
313
314 userPrincipal = null;
315
316 keystore = null;
317 keystoreFile = null;
318 keystorePassword = null;
319 keystoreType = null;
320
321 alias = null;
322 privateKeyPassword = null;
323
324 return true;
325 }
326
327 private synchronized KeyStore getKeystore() throws LoginException
328 {
329 if ( keystore == null )
330 {
331 loadKeyStore();
332 }
333 return keystore;
334 }
335
336 private void loadKeyStore() throws LoginException
337 {
338 try
339 {
340 String actualKSType = ( keystoreType == null ) ? KeyStore.getDefaultType() : keystoreType;
341
342 keystore = KeyStore.getInstance( actualKSType );
343
344 if ( keystoreFile == null )
345 {
346 throw new IOException( "No keystore specified by user." );
347 }
348
349 InputStream ksInput = WSAG4JConfiguration.findResource( keystoreFile );
350 keystore.load( ksInput, keystorePassword.toCharArray() );
351
352 }
353 catch ( KeyStoreException e )
354 {
355 throw new LoginException( e.getMessage() );
356 }
357 catch ( IOException e )
358 {
359 throw new LoginException( e.getMessage() );
360 }
361 catch ( CertificateException e )
362 {
363 throw new LoginException( e.getMessage() );
364 }
365 catch ( NoSuchAlgorithmException e )
366 {
367 throw new LoginException( e.getMessage() );
368 }
369
370 }
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388 private X509Certificate[] getCertificates( String ksAlias ) throws KeyStoreException, LoginException
389 {
390 Certificate[] certs = null;
391 Certificate cert = null;
392
393 KeyStore store = getKeystore();
394
395 if ( store != null )
396 {
397
398 certs = store.getCertificateChain( ksAlias );
399 if ( certs == null || certs.length == 0 )
400 {
401
402
403 cert = store.getCertificate( ksAlias );
404 }
405 }
406
407 if ( cert != null )
408 {
409 certs = new Certificate[] { cert };
410 }
411 else if ( certs == null )
412 {
413
414 return null;
415 }
416
417 X509Certificate[] x509certs = new X509Certificate[certs.length];
418 for ( int i = 0; i < certs.length; i++ )
419 {
420 x509certs[i] = (X509Certificate) certs[i];
421 }
422 return x509certs;
423 }
424
425 }