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.activemq.jaas;
018
019 import java.io.File;
020 import java.io.IOException;
021 import java.security.Principal;
022 import java.util.Enumeration;
023 import java.util.HashSet;
024 import java.util.Map;
025 import java.util.Properties;
026 import java.util.Set;
027
028 import javax.security.auth.Subject;
029 import javax.security.auth.callback.Callback;
030 import javax.security.auth.callback.CallbackHandler;
031 import javax.security.auth.callback.NameCallback;
032 import javax.security.auth.callback.PasswordCallback;
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.slf4j.Logger;
039 import org.slf4j.LoggerFactory;
040
041 /**
042 * @version $Rev: $ $Date: $
043 */
044 public class PropertiesLoginModule implements LoginModule {
045
046 private static final String USER_FILE = "org.apache.activemq.jaas.properties.user";
047 private static final String GROUP_FILE = "org.apache.activemq.jaas.properties.group";
048
049 private static final Logger LOG = LoggerFactory.getLogger(PropertiesLoginModule.class);
050
051 private Subject subject;
052 private CallbackHandler callbackHandler;
053
054 private boolean debug;
055 private boolean reload = true;
056 private static String usersFile;
057 private static String groupsFile;
058 private static Properties users;
059 private static Properties groups;
060 private String user;
061 private Set<Principal> principals = new HashSet<Principal>();
062 private File baseDir;
063 private boolean loginSucceeded;
064
065
066 public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
067 this.subject = subject;
068 this.callbackHandler = callbackHandler;
069 loginSucceeded = false;
070
071 debug = "true".equalsIgnoreCase((String)options.get("debug"));
072 if (options.get("reload") != null) {
073 reload = "true".equalsIgnoreCase((String)options.get("reload"));
074 }
075
076 if (reload || users == null) {
077 setBaseDir();
078 usersFile = (String)options.get(USER_FILE) + "";
079 File uf = new File(baseDir, usersFile);
080 try {
081 users = new Properties();
082 java.io.FileInputStream in = new java.io.FileInputStream(uf);
083 users.load(in);
084 in.close();
085 } catch (IOException ioe) {
086 LOG.warn("Unable to load user properties file " + uf);
087 }
088 if (debug) {
089 LOG.debug("Using usersFile=" + usersFile);
090 }
091 }
092 if (reload || groups == null) {
093 setBaseDir();
094 groupsFile = (String)options.get(GROUP_FILE) + "";
095 File gf = new File(baseDir, groupsFile);
096 try {
097 groups = new Properties();
098 java.io.FileInputStream in = new java.io.FileInputStream(gf);
099 groups.load(in);
100 in.close();
101 } catch (IOException ioe) {
102 LOG.warn("Unable to load group properties file " + gf);
103 }
104 if (debug) {
105 LOG.debug("Using groupsFile=" + groupsFile);
106 }
107 }
108 }
109
110 private void setBaseDir() {
111 if (baseDir == null) {
112 if (System.getProperty("java.security.auth.login.config") != null) {
113 baseDir = new File(System.getProperty("java.security.auth.login.config")).getParentFile();
114 } else {
115 baseDir = new File(".");
116 }
117 if (debug) {
118 LOG.debug("Using basedir=" + baseDir);
119 }
120 }
121 }
122
123 public boolean login() throws LoginException {
124 Callback[] callbacks = new Callback[2];
125
126 callbacks[0] = new NameCallback("Username: ");
127 callbacks[1] = new PasswordCallback("Password: ", false);
128 try {
129 callbackHandler.handle(callbacks);
130 } catch (IOException ioe) {
131 throw new LoginException(ioe.getMessage());
132 } catch (UnsupportedCallbackException uce) {
133 throw new LoginException(uce.getMessage() + " not available to obtain information from user");
134 }
135 user = ((NameCallback)callbacks[0]).getName();
136 char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();
137 if (tmpPassword == null) {
138 tmpPassword = new char[0];
139 }
140 String password = users.getProperty(user);
141
142 if (password == null) {
143 throw new FailedLoginException("User does exist");
144 }
145 if (!password.equals(new String(tmpPassword))) {
146 throw new FailedLoginException("Password does not match");
147 }
148 loginSucceeded = true;
149
150 if (debug) {
151 LOG.debug("login " + user);
152 }
153 return loginSucceeded;
154 }
155
156 public boolean commit() throws LoginException {
157 boolean result = loginSucceeded;
158 if (result) {
159 principals.add(new UserPrincipal(user));
160
161 for (Enumeration enumeration = groups.keys(); enumeration.hasMoreElements();) {
162 String name = (String)enumeration.nextElement();
163 String[] userList = ((String)groups.getProperty(name) + "").split(",");
164 for (int i = 0; i < userList.length; i++) {
165 if (user.equals(userList[i])) {
166 principals.add(new GroupPrincipal(name));
167 break;
168 }
169 }
170 }
171
172 subject.getPrincipals().addAll(principals);
173 }
174
175 // will whack loginSucceeded
176 clear();
177
178 if (debug) {
179 LOG.debug("commit, result: " + result);
180 }
181 return result;
182 }
183
184 public boolean abort() throws LoginException {
185 clear();
186
187 if (debug) {
188 LOG.debug("abort");
189 }
190 return true;
191 }
192
193 public boolean logout() throws LoginException {
194 subject.getPrincipals().removeAll(principals);
195 principals.clear();
196 clear();
197 if (debug) {
198 LOG.debug("logout");
199 }
200 return true;
201 }
202
203 private void clear() {
204 user = null;
205 loginSucceeded = false;
206 }
207 }