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.geronimo.jetty6;
018    
019    import java.security.AccessControlContext;
020    import java.security.AccessControlException;
021    import java.security.Principal;
022    import java.security.cert.X509Certificate;
023    import java.util.HashMap;
024    
025    import javax.security.auth.Subject;
026    import javax.security.auth.login.LoginContext;
027    import javax.security.auth.login.LoginException;
028    import javax.security.jacc.WebRoleRefPermission;
029    
030    import org.apache.commons.logging.Log;
031    import org.apache.commons.logging.LogFactory;
032    import org.apache.geronimo.security.ContextManager;
033    import org.apache.geronimo.security.realm.providers.CertificateCallbackHandler;
034    import org.apache.geronimo.security.realm.providers.ClearableCallbackHandler;
035    import org.apache.geronimo.security.realm.providers.PasswordCallbackHandler;
036    import org.mortbay.jetty.Request;
037    
038    
039    /**
040     * @version $Rev: 565912 $ $Date: 2007-08-14 17:03:11 -0400 (Tue, 14 Aug 2007) $
041     */
042    public class InternalJAASJettyRealm {
043        private static Log log = LogFactory.getLog(InternalJAASJettyRealm.class);
044    
045        private final String securityRealmName;
046        private final HashMap<String, Principal> userMap = new HashMap<String, Principal>();
047        private int count = 1;
048    
049        public InternalJAASJettyRealm(String geronimoRealmName) {
050            this.securityRealmName = geronimoRealmName;
051        }
052    
053        public String getSecurityRealmName() {
054            return securityRealmName;
055        }
056    
057        public Principal getPrincipal(String username) {
058            return userMap.get(username);
059        }
060    
061        public Principal authenticate(String username, Object credentials, Request request) {
062            try {
063                if ((username != null) && (!username.equals(""))) {
064    
065                    JAASJettyPrincipal userPrincipal = (JAASJettyPrincipal) userMap.get(username);
066    
067                    //user has been previously authenticated, but
068                    //re-authentication has been requested, so remove them
069                    if (userPrincipal != null) {
070                        userMap.remove(username);
071                    }
072    
073                    ClearableCallbackHandler callbackHandler;
074                    if (credentials instanceof char[]) {
075                        char[] password = (char[]) credentials;
076                        callbackHandler = new PasswordCallbackHandler(username, password);
077                    } else if (credentials instanceof String) {
078                        char[] password = ((String) credentials).toCharArray();
079                        callbackHandler = new PasswordCallbackHandler(username, password);
080                    } else if (credentials instanceof X509Certificate[]) {
081                        X509Certificate[] certs = (X509Certificate[]) credentials;
082                        if (certs.length < 1) {
083                            throw new LoginException("no certificates supplied");
084                        }
085                        callbackHandler = new CertificateCallbackHandler(certs[0]);
086                    } else {
087                        throw new LoginException("Cannot extract credentials from class: " + credentials.getClass().getName());
088                    }
089    
090                    //set up the login context
091                    LoginContext loginContext = ContextManager.login(securityRealmName, callbackHandler);
092                    callbackHandler.clear();
093    
094                    Subject subject = ContextManager.getServerSideSubject(loginContext.getSubject());
095                    ContextManager.setCallers(subject, subject);
096    
097                    //login success
098                    userPrincipal = new JAASJettyPrincipal(username);
099                    userPrincipal.setSubject(subject);
100    
101                    userMap.put(username, userPrincipal);
102    
103                    return userPrincipal;
104                } else {
105                    log.debug("Login Failed - null userID");
106                    return null;
107                }
108    
109            } catch (LoginException e) {
110                log.debug("Login Failed", e);
111                return null;
112            }
113        }
114    
115        public void logout(Principal user) {
116            JAASJettyPrincipal principal = (JAASJettyPrincipal) user;
117    
118            userMap.remove(principal.getName());
119            ContextManager.unregisterSubject(principal.getSubject());
120        }
121    
122        public boolean reauthenticate(Principal user) {
123            // TODO This is not correct if auth can expire! We need to
124    
125            Subject subject = ((JAASJettyPrincipal) user).getSubject();
126            ContextManager.setCallers(subject, subject);
127    
128            // get the user out of the cache
129            return (userMap.get(user.getName()) != null);
130        }
131    
132        public void disassociate(Principal user) {
133            // do nothing
134        }
135    
136        public boolean isUserInRole(Principal user, String role) {
137            if (user == null || role == null) {
138                return false;
139            }
140    
141            AccessControlContext acc = ContextManager.getCurrentContext();
142            try {
143                // JACC v1.0 secion B.19
144                String servletName = InternalJettyServletHolder.getCurrentServletName();
145                if (servletName == null || servletName.equals("jsp")) {
146                    servletName = "";
147                }
148                acc.checkPermission(new WebRoleRefPermission(servletName, role));
149            } catch (AccessControlException e) {
150                return false;
151            }
152            return true;
153        }
154    
155        public Principal pushRole(Principal user, String role) {
156            //handled by JettyServletHolder and its runAsSubject
157            return user;
158        }
159    
160        public Principal popRole(Principal user) {
161            return user;
162        }
163    
164        public void addUse() {
165            count++;
166        }
167    
168        public int removeUse() {
169            return count--;
170        }
171    
172    }