001 /**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.geronimo.jetty;
019
020 import java.security.AccessControlContext;
021 import java.security.AccessControlException;
022 import java.security.Principal;
023 import java.security.cert.X509Certificate;
024 import java.util.HashMap;
025
026 import javax.security.auth.Subject;
027 import javax.security.auth.login.LoginContext;
028 import javax.security.auth.login.LoginException;
029 import javax.security.jacc.WebRoleRefPermission;
030
031 import org.apache.commons.logging.Log;
032 import org.apache.commons.logging.LogFactory;
033 import org.apache.geronimo.security.ContextManager;
034 import org.apache.geronimo.security.realm.providers.CertificateCallbackHandler;
035 import org.apache.geronimo.security.realm.providers.ClearableCallbackHandler;
036 import org.apache.geronimo.security.realm.providers.PasswordCallbackHandler;
037 import org.mortbay.http.HttpRequest;
038
039
040 /**
041 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
042 */
043 public class InternalJAASJettyRealm {
044 private static Log log = LogFactory.getLog(InternalJAASJettyRealm.class);
045
046 private final String securityRealmName;
047 private final HashMap userMap = new HashMap();
048 private int count = 1;
049
050 public InternalJAASJettyRealm(String geronimoRealmName) {
051 this.securityRealmName = geronimoRealmName;
052 }
053
054 public String getSecurityRealmName() {
055 return securityRealmName;
056 }
057
058 public Principal getPrincipal(String username) {
059 return (Principal) userMap.get(username);
060 }
061
062 public Principal authenticate(String username, Object credentials, HttpRequest request) {
063 try {
064 if ((username != null) && (!username.equals(""))) {
065
066 JAASJettyPrincipal userPrincipal = (JAASJettyPrincipal) userMap.get(username);
067
068 //user has been previously authenticated, but
069 //re-authentication has been requested, so remove them
070 if (userPrincipal != null) {
071 userMap.remove(username);
072 }
073
074 ClearableCallbackHandler callbackHandler;
075 if (credentials instanceof char[]) {
076 char[] password = (char[]) credentials;
077 callbackHandler = new PasswordCallbackHandler(username, password);
078 } else if (credentials instanceof String) {
079 char[] password = ((String) credentials).toCharArray();
080 callbackHandler = new PasswordCallbackHandler(username, password);
081 } else if (credentials instanceof X509Certificate[]) {
082 X509Certificate[] certs = (X509Certificate[]) credentials;
083 if (certs.length < 1) {
084 throw new LoginException("no certificates supplied");
085 }
086 callbackHandler = new CertificateCallbackHandler(certs[0]);
087 } else {
088 throw new LoginException("Cannot extract credentials from class: " + credentials.getClass().getName());
089 }
090
091 //set up the login context
092 LoginContext loginContext = new LoginContext(securityRealmName, callbackHandler);
093 loginContext.login();
094 callbackHandler.clear();
095
096 Subject subject = ContextManager.getServerSideSubject(loginContext.getSubject());
097 //TODO use the run-as subject as nextCaller
098 ContextManager.setCallers(subject, subject);
099 ContextManager.setNextCaller(subject);
100
101 //login success
102 userPrincipal = new JAASJettyPrincipal(username);
103 userPrincipal.setSubject(subject);
104
105 userMap.put(username, userPrincipal);
106
107 return userPrincipal;
108 } else {
109 log.debug("Login Failed - null userID");
110 return null;
111 }
112
113 } catch (LoginException e) {
114 // log.warn("Login Failed", e);
115 log.debug("Login Failed", e);
116 return null;
117 }
118 }
119
120 public void logout(Principal user) {
121 JAASJettyPrincipal principal = (JAASJettyPrincipal) user;
122
123 userMap.remove(principal.getName());
124 ContextManager.unregisterSubject(principal.getSubject());
125 }
126
127 public boolean reauthenticate(Principal user) {
128 // TODO This is not correct if auth can expire! We need to
129
130 Subject subject = ((JAASJettyPrincipal) user).getSubject();
131 ContextManager.setCallers(subject, subject);
132
133 // get the user out of the cache
134 return (userMap.get(user.getName()) != null);
135 }
136
137 public void disassociate(Principal user) {
138 // do nothing
139 }
140
141 public boolean isUserInRole(Principal user, String role) {
142 if (user == null || role == null) {
143 return false;
144 }
145
146 AccessControlContext acc = ContextManager.getCurrentContext();
147 try {
148 // JACC v1.0 secion B.19
149 String servletName = JettyServletHolder.getCurrentServletName();
150 if (servletName.equals("jsp")) {
151 servletName = "";
152 }
153 acc.checkPermission(new WebRoleRefPermission(servletName, role));
154 } catch (AccessControlException e) {
155 return false;
156 }
157 return true;
158 }
159
160 public Principal pushRole(Principal user, String role) {
161 //handled by JettyServletHolder and its runAsSubject
162 return user;
163 }
164
165 public Principal popRole(Principal user) {
166 return user;
167 }
168
169 public void addUse() {
170 count++;
171 }
172
173 public int removeUse() {
174 return count--;
175 }
176
177 }