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
018package org.apache.activemq.jaas;
019
020import java.io.IOException;
021import java.security.Principal;
022import java.util.HashSet;
023import java.util.Map;
024import java.util.Set;
025import javax.security.auth.Subject;
026import javax.security.auth.callback.Callback;
027import javax.security.auth.callback.CallbackHandler;
028import javax.security.auth.callback.PasswordCallback;
029import javax.security.auth.callback.UnsupportedCallbackException;
030import javax.security.auth.login.LoginException;
031import javax.security.auth.spi.LoginModule;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034
035/**
036 * Always login the user with a default 'guest' identity.
037 *
038 * Useful for unauthenticated communication channels being used in the
039 * same broker as authenticated ones.
040 * 
041 */
042public class GuestLoginModule implements LoginModule {
043
044    private static final String GUEST_USER = "org.apache.activemq.jaas.guest.user";
045    private static final String GUEST_GROUP = "org.apache.activemq.jaas.guest.group";
046
047    private static final Logger LOG = LoggerFactory.getLogger(GuestLoginModule.class);
048    
049
050    private String userName = "guest";
051    private String groupName = "guests";
052    private Subject subject;
053    private boolean debug;
054    private boolean credentialsInvalidate;
055    private Set<Principal> principals = new HashSet<Principal>();
056    private CallbackHandler callbackHandler;
057
058    /** the authentication status*/
059    private boolean succeeded = false;
060    private boolean commitSucceeded = false;
061
062    @Override
063    public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
064        this.subject = subject;
065        this.callbackHandler = callbackHandler;
066        debug = "true".equalsIgnoreCase((String)options.get("debug"));
067        credentialsInvalidate = "true".equalsIgnoreCase((String)options.get("credentialsInvalidate"));
068        if (options.get(GUEST_USER) != null) {
069            userName = (String)options.get(GUEST_USER);
070        }
071        if (options.get(GUEST_GROUP) != null) {
072            groupName = (String)options.get(GUEST_GROUP);
073        }
074        principals.add(new UserPrincipal(userName));
075        principals.add(new GroupPrincipal(groupName));
076        
077        if (debug) {
078            LOG.debug("Initialized debug=" + debug + " guestUser=" + userName + " guestGroup=" + groupName);
079        }
080
081    }
082
083    @Override
084    public boolean login() throws LoginException {
085        succeeded = true;
086        if (credentialsInvalidate) {
087            PasswordCallback passwordCallback = new PasswordCallback("Password: ", false);
088            try {
089                 callbackHandler.handle(new Callback[]{passwordCallback});
090                 if (passwordCallback.getPassword() != null) {
091                     if (debug) {
092                        LOG.debug("Guest login failing (credentialsInvalidate=true) on presence of a password");
093                     }
094                     succeeded = false;
095                     passwordCallback.clearPassword();
096                 };
097             } catch (IOException ioe) {
098             } catch (UnsupportedCallbackException uce) {
099             }
100        }
101        if (debug) {
102            LOG.debug("Guest login " + succeeded);
103        }
104        return succeeded;
105    }
106
107    @Override
108    public boolean commit() throws LoginException {
109        if (debug) {
110            LOG.debug("commit");
111        }
112
113        if (!succeeded) {
114            return false;
115        }
116
117        subject.getPrincipals().addAll(principals);
118        commitSucceeded = true;
119        return true;
120    }
121
122    @Override
123    public boolean abort() throws LoginException {
124
125        if (debug) {
126            LOG.debug("abort");
127        }
128        if (!succeeded) {
129            return false;
130        } else if (succeeded && commitSucceeded) {
131            // we succeeded, but another required module failed
132            logout();
133        } else {
134            // our commit failed
135            succeeded = false;
136        }
137        return true;
138    }
139
140    @Override
141    public boolean logout() throws LoginException {
142        subject.getPrincipals().removeAll(principals);
143
144        if (debug) {
145            LOG.debug("logout");
146        }
147
148        succeeded = false;
149        commitSucceeded = false;
150        return true;
151    }
152}