001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.jbi.security.login;
018
019 import java.io.File;
020 import java.io.IOException;
021 import java.security.Principal;
022 import java.security.cert.X509Certificate;
023 import java.util.Enumeration;
024 import java.util.HashSet;
025 import java.util.Iterator;
026 import java.util.Map;
027 import java.util.Properties;
028 import java.util.Set;
029
030 import javax.security.auth.Subject;
031 import javax.security.auth.callback.Callback;
032 import javax.security.auth.callback.CallbackHandler;
033 import javax.security.auth.callback.UnsupportedCallbackException;
034 import javax.security.auth.login.FailedLoginException;
035 import javax.security.auth.login.LoginException;
036 import javax.security.auth.spi.LoginModule;
037
038 import org.apache.commons.logging.Log;
039 import org.apache.commons.logging.LogFactory;
040 import org.apache.servicemix.jbi.security.GroupPrincipal;
041 import org.apache.servicemix.jbi.security.UserPrincipal;
042
043
044 /**
045 * This login module authenticate users given an X509 certificate.
046 *
047 */
048 public class CertificatesLoginModule implements LoginModule {
049
050 private static final String USER_FILE = "org.apache.servicemix.security.certificates.user";
051 private static final String GROUP_FILE = "org.apache.servicemix.security.certificates.group";
052
053 private static final Log LOG = LogFactory.getLog(CertificatesLoginModule.class);
054
055 private Subject subject;
056 private CallbackHandler callbackHandler;
057 private boolean debug;
058 private String usersFile;
059 private String groupsFile;
060 private Properties users = new Properties();
061 private Properties groups = new Properties();
062 private String user;
063 private Set principals = new HashSet();
064 private File baseDir;
065
066 public void initialize(Subject sub, CallbackHandler handler, Map sharedState, Map options) {
067 this.subject = sub;
068 this.callbackHandler = handler;
069
070 if (System.getProperty("java.security.auth.login.config") != null) {
071 baseDir = new File(System.getProperty("java.security.auth.login.config")).getParentFile();
072 } else {
073 baseDir = new File(".");
074 }
075
076 debug = "true".equalsIgnoreCase((String) options.get("debug"));
077 usersFile = (String) options.get(USER_FILE) + "";
078 groupsFile = (String) options.get(GROUP_FILE) + "";
079
080 if (debug) {
081 LOG.debug("Initialized debug=" + debug + " usersFile=" + usersFile + " groupsFile=" + groupsFile
082 + " basedir=" + baseDir);
083 }
084 }
085
086 public boolean login() throws LoginException {
087 File f = new File(baseDir, usersFile);
088 try {
089 users.load(new java.io.FileInputStream(f));
090 } catch (IOException ioe) {
091 throw new LoginException("Unable to load user properties file " + f);
092 }
093 f = new File(baseDir, groupsFile);
094 try {
095 groups.load(new java.io.FileInputStream(f));
096 } catch (IOException ioe) {
097 throw new LoginException("Unable to load group properties file " + f);
098 }
099
100 Callback[] callbacks = new Callback[1];
101 callbacks[0] = new CertificateCallback();
102 try {
103 callbackHandler.handle(callbacks);
104 } catch (IOException ioe) {
105 throw new LoginException(ioe.getMessage());
106 } catch (UnsupportedCallbackException uce) {
107 throw new LoginException(uce.getMessage() + " not available to obtain information from user");
108 }
109 X509Certificate cert = ((CertificateCallback) callbacks[0]).getCertificate();
110 if (cert == null) {
111 throw new FailedLoginException("Unable to retrieve certificate");
112 }
113
114 Principal principal = cert.getSubjectX500Principal();
115 String certName = principal.getName();
116 for (Iterator it = users.entrySet().iterator(); it.hasNext();) {
117 Map.Entry entry = (Map.Entry) it.next();
118 if (certName.equals(entry.getValue())) {
119 user = (String) entry.getKey();
120 principals.add(principal);
121 if (debug) {
122 LOG.debug("login " + user);
123 }
124 return true;
125 }
126 }
127 throw new FailedLoginException();
128 }
129
130 public boolean commit() throws LoginException {
131 principals.add(new UserPrincipal(user));
132
133 for (Enumeration enumeration = groups.keys(); enumeration.hasMoreElements();) {
134 String name = (String) enumeration.nextElement();
135 String[] userList = ((String) groups.getProperty(name) + "").split(",");
136 for (int i = 0; i < userList.length; i++) {
137 if (user.equals(userList[i])) {
138 principals.add(new GroupPrincipal(name));
139 break;
140 }
141 }
142 }
143
144 subject.getPrincipals().addAll(principals);
145
146 clear();
147
148 if (debug) {
149 LOG.debug("commit");
150 }
151 return true;
152 }
153
154 public boolean abort() throws LoginException {
155 clear();
156
157 if (debug) {
158 LOG.debug("abort");
159 }
160 return true;
161 }
162
163 public boolean logout() throws LoginException {
164 subject.getPrincipals().removeAll(principals);
165 principals.clear();
166
167 if (debug) {
168 LOG.debug("logout");
169 }
170 return true;
171 }
172
173 private void clear() {
174 groups.clear();
175 user = null;
176 }
177 }