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.util.Enumeration;
022 import java.util.HashSet;
023 import java.util.Map;
024 import java.util.Properties;
025 import java.util.Set;
026
027 import javax.security.auth.Subject;
028 import javax.security.auth.callback.Callback;
029 import javax.security.auth.callback.CallbackHandler;
030 import javax.security.auth.callback.NameCallback;
031 import javax.security.auth.callback.PasswordCallback;
032 import javax.security.auth.callback.UnsupportedCallbackException;
033 import javax.security.auth.login.FailedLoginException;
034 import javax.security.auth.login.LoginException;
035 import javax.security.auth.spi.LoginModule;
036
037 import org.apache.commons.logging.Log;
038 import org.apache.commons.logging.LogFactory;
039 import org.apache.servicemix.jbi.security.GroupPrincipal;
040 import org.apache.servicemix.jbi.security.UserPrincipal;
041
042 /**
043 * JAAS Login module for user / password, based on two properties files.
044 *
045 */
046 public class PropertiesLoginModule implements LoginModule {
047
048 private static final String USER_FILE = "org.apache.servicemix.security.properties.user";
049 private static final String GROUP_FILE = "org.apache.servicemix.security.properties.group";
050 private static final Log LOG = LogFactory.getLog(PropertiesLoginModule.class);
051
052 private Subject subject;
053 private CallbackHandler callbackHandler;
054 private boolean debug;
055 private String usersFile;
056 private String groupsFile;
057 private Properties users = new Properties();
058 private Properties groups = new Properties();
059 private String user;
060 private Set principals = new HashSet();
061 private File baseDir;
062
063 public void initialize(Subject sub, CallbackHandler handler, Map sharedState, Map options) {
064 this.subject = sub;
065 this.callbackHandler = handler;
066
067 if (System.getProperty("java.security.auth.login.config") != null) {
068 baseDir = new File(System.getProperty("java.security.auth.login.config")).getParentFile();
069 } else {
070 baseDir = new File(".");
071 }
072
073 debug = "true".equalsIgnoreCase((String) options.get("debug"));
074 usersFile = (String) options.get(USER_FILE) + "";
075 groupsFile = (String) options.get(GROUP_FILE) + "";
076
077 if (debug) {
078 LOG.debug("Initialized debug=" + debug + " usersFile=" + usersFile + " groupsFile=" + groupsFile + " basedir=" + baseDir);
079 }
080 }
081
082 public boolean login() throws LoginException {
083 File f = new File(baseDir, usersFile);
084 try {
085 users.load(new java.io.FileInputStream(f));
086 } catch (IOException ioe) {
087 throw new LoginException("Unable to load user properties file " + f);
088 }
089 f = new File(baseDir, groupsFile);
090 try {
091 groups.load(new java.io.FileInputStream(f));
092 } catch (IOException ioe) {
093 throw new LoginException("Unable to load group properties file " + f);
094 }
095
096 Callback[] callbacks = new Callback[2];
097
098 callbacks[0] = new NameCallback("Username: ");
099 callbacks[1] = new PasswordCallback("Password: ", false);
100 try {
101 callbackHandler.handle(callbacks);
102 } catch (IOException ioe) {
103 throw new LoginException(ioe.getMessage());
104 } catch (UnsupportedCallbackException uce) {
105 throw new LoginException(uce.getMessage() + " not available to obtain information from user");
106 }
107 user = ((NameCallback) callbacks[0]).getName();
108 char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
109 if (tmpPassword == null) {
110 tmpPassword = new char[0];
111 }
112
113 String password = users.getProperty(user);
114
115 if (password == null) {
116 throw new FailedLoginException("User does not exist");
117 }
118 if (!password.equals(new String(tmpPassword))) {
119 throw new FailedLoginException("Password does not match");
120 }
121
122 users.clear();
123
124 if (debug) {
125 LOG.debug("login " + user);
126 }
127 return true;
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 }