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
63
64
65
66
67
68
69
70
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
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 }