View Javadoc

1   /**
2    *
3    * Copyright 2003-2005 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package org.apache.geronimo.security.realm.providers;
19  
20  import java.io.IOException;
21  import java.security.cert.Certificate;
22  import java.security.cert.X509Certificate;
23  import java.util.Map;
24  import java.util.Set;
25  import javax.security.auth.Subject;
26  import javax.security.auth.callback.Callback;
27  import javax.security.auth.callback.CallbackHandler;
28  import javax.security.auth.callback.UnsupportedCallbackException;
29  import javax.security.auth.login.LoginException;
30  import javax.security.auth.spi.LoginModule;
31  import javax.security.auth.x500.X500Principal;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  
37  /**
38   * An example LoginModule that reads a list of users and group from a file on disk.
39   * Authentication is provided by the SSL layer supplying the client certificate.
40   * All we check is that it is present.  The
41   * file should be formatted using standard Java properties syntax.  Expects
42   * to be run by a GenericSecurityRealm (doesn't work on its own).
43   *
44   * The usersURI property file should have lines of the form token=certificatename
45   * where certificate name is X509Certificate.getSubjectX500Principal().getName()
46   *
47   * The groupsURI property file should have lines of the form group=token1,token2,...
48   * where the tokens were associated to the certificate names in the usersURI properties file.
49   *
50   * @version $Rev: 355877 $ $Date: 2005-12-10 18:48:27 -0800 (Sat, 10 Dec 2005) $
51   */
52  public class CertificateChainLoginModule implements LoginModule {
53      private static Log log = LogFactory.getLog(CertificateChainLoginModule.class);
54  
55      Subject subject;
56      CallbackHandler handler;
57      X500Principal principal;
58  
59      public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
60          this.subject = subject;
61          this.handler = callbackHandler;
62  //        try {
63  //            Kernel kernel = KernelRegistry.getKernel((String)options.get(JaasLoginModuleUse.KERNEL_LM_OPTION));
64  //            ServerInfo serverInfo = (ServerInfo) options.get(JaasLoginModuleUse.SERVERINFO_LM_OPTION);
65  //            URI usersURI = new URI((String)options.get(USERS_URI));
66  //            URI groupsURI = new URI((String)options.get(GROUPS_URI));
67  //            loadProperties(kernel, serverInfo, usersURI, groupsURI);
68  //        } catch (Exception e) {
69  //            log.error(e);
70  //            throw new IllegalArgumentException("Unable to configure properties file login module: "+e);
71  //        }
72      }
73  
74  
75  
76      public boolean login() throws LoginException {
77          Callback[] callbacks = new Callback[1];
78  
79          callbacks[0] = new CertificateChainCallback();
80          try {
81              handler.handle(callbacks);
82          } catch (IOException ioe) {
83              throw (LoginException) new LoginException().initCause(ioe);
84          } catch (UnsupportedCallbackException uce) {
85              throw (LoginException) new LoginException().initCause(uce);
86          }
87          assert callbacks.length == 1;
88          Certificate[] certificateChain = ((CertificateChainCallback)callbacks[0]).getCertificateChain();
89          if (certificateChain == null || certificateChain.length == 0) {
90              return false;
91          }
92          if (!(certificateChain[0] instanceof X509Certificate)) {
93              return false;
94          }
95          //TODO actually validate chain
96          principal = ((X509Certificate)certificateChain[0]).getSubjectX500Principal();
97  
98          return true;
99      }
100 
101     public boolean commit() throws LoginException {
102         Set principals = subject.getPrincipals();
103 
104         principals.add(principal);
105         principals.add(new GeronimoUserPrincipal(principal.getName()));
106 
107         return true;
108     }
109 
110     public boolean abort() throws LoginException {
111         principal = null;
112 
113         return true;
114     }
115 
116     public boolean logout() throws LoginException {
117         principal = null;
118 
119         return true;
120     }
121 
122     /**
123      * Gets the names of all principal classes that may be populated into
124      * a Subject.
125      */
126     public String[] getPrincipalClassNames() {
127         return new String[]{GeronimoUserPrincipal.class.getName()};
128     }
129 
130 }