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    }