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 }