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 */ 017package org.apache.activemq.jaas; 018 019import java.io.File; 020import java.io.IOException; 021import java.security.Principal; 022import java.util.Enumeration; 023import java.util.HashSet; 024import java.util.Map; 025import java.util.Properties; 026import java.util.Set; 027 028import javax.security.auth.Subject; 029import javax.security.auth.callback.Callback; 030import javax.security.auth.callback.CallbackHandler; 031import javax.security.auth.callback.NameCallback; 032import javax.security.auth.callback.PasswordCallback; 033import javax.security.auth.callback.UnsupportedCallbackException; 034import javax.security.auth.login.FailedLoginException; 035import javax.security.auth.login.LoginException; 036import javax.security.auth.spi.LoginModule; 037 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041/** 042 * @version $Rev: $ $Date: $ 043 */ 044public 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}