SEC-234: Allow pluggable AuthenticationDetailsSource strategy interface.
This commit is contained in:
parent
b1becf9277
commit
a47a342ce6
|
@ -19,7 +19,8 @@ import org.acegisecurity.Authentication;
|
||||||
|
|
||||||
import org.acegisecurity.context.SecurityContextHolder;
|
import org.acegisecurity.context.SecurityContextHolder;
|
||||||
|
|
||||||
import org.acegisecurity.ui.WebAuthenticationDetails;
|
import org.acegisecurity.ui.AuthenticationDetailsSource;
|
||||||
|
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
|
||||||
|
|
||||||
import org.acegisecurity.userdetails.memory.UserAttribute;
|
import org.acegisecurity.userdetails.memory.UserAttribute;
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean {
|
||||||
|
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||||
private String key;
|
private String key;
|
||||||
private UserAttribute userAttribute;
|
private UserAttribute userAttribute;
|
||||||
private boolean removeAfterRequest = true;
|
private boolean removeAfterRequest = true;
|
||||||
|
@ -96,8 +98,8 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean {
|
||||||
|
|
||||||
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(key,
|
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(key,
|
||||||
userAttribute.getPassword(), userAttribute.getAuthorities());
|
userAttribute.getPassword(), userAttribute.getAuthorities());
|
||||||
auth.setDetails(new WebAuthenticationDetails(
|
auth.setDetails(authenticationDetailsSource.buildDetails(
|
||||||
(HttpServletRequest) request, false));
|
(HttpServletRequest) request));
|
||||||
|
|
||||||
return auth;
|
return auth;
|
||||||
}
|
}
|
||||||
|
@ -167,6 +169,13 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean {
|
||||||
return removeAfterRequest;
|
return removeAfterRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAuthenticationDetailsSource(
|
||||||
|
AuthenticationDetailsSource authenticationDetailsSource) {
|
||||||
|
Assert.notNull(authenticationDetailsSource,
|
||||||
|
"AuthenticationDetailsSource required");
|
||||||
|
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||||
|
}
|
||||||
|
|
||||||
public void setKey(String key) {
|
public void setKey(String key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,7 @@ public abstract class AbstractProcessingFilter implements Filter,
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
protected ApplicationEventPublisher eventPublisher;
|
protected ApplicationEventPublisher eventPublisher;
|
||||||
|
protected AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||||
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
|
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
|
||||||
|
@ -371,6 +372,13 @@ public abstract class AbstractProcessingFilter implements Filter,
|
||||||
this.eventPublisher = eventPublisher;
|
this.eventPublisher = eventPublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAuthenticationDetailsSource(
|
||||||
|
AuthenticationDetailsSource authenticationDetailsSource) {
|
||||||
|
Assert.notNull(authenticationDetailsSource,
|
||||||
|
"AuthenticationDetailsSource required");
|
||||||
|
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||||
|
}
|
||||||
|
|
||||||
public void setAuthenticationFailureUrl(String authenticationFailureUrl) {
|
public void setAuthenticationFailureUrl(String authenticationFailureUrl) {
|
||||||
this.authenticationFailureUrl = authenticationFailureUrl;
|
this.authenticationFailureUrl = authenticationFailureUrl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.acegisecurity.ui;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a {@link org.acegisecurity.Authentication#getDetails()} object for
|
||||||
|
* a given web request.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public interface AuthenticationDetailsSource {
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by a class when it wishes a new authentication details instance
|
||||||
|
* to be created.
|
||||||
|
*
|
||||||
|
* @param request the request object, which may be used by the
|
||||||
|
* authentication details object
|
||||||
|
*
|
||||||
|
* @return a fully-configured authentication details instance
|
||||||
|
*/
|
||||||
|
public Object buildDetails(HttpServletRequest request);
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.acegisecurity.ui;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base implementation of {@link AuthenticationDetailsSource}.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* By default will create an instance of <code>WebAuthenticationDetails</code>.
|
||||||
|
* Any object that accepts a <code>HttpServletRequest</code> as its sole
|
||||||
|
* constructor can be used instead of this default.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AuthenticationDetailsSourceImpl
|
||||||
|
implements AuthenticationDetailsSource {
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private Class clazz = WebAuthenticationDetails.class;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public Object buildDetails(HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
Constructor constructor = clazz.getConstructor(new Class[] {HttpServletRequest.class});
|
||||||
|
|
||||||
|
return constructor.newInstance(new Object[] {request});
|
||||||
|
} catch (NoSuchMethodException ex) {
|
||||||
|
ReflectionUtils.handleReflectionException(ex);
|
||||||
|
} catch (InvocationTargetException ex) {
|
||||||
|
ReflectionUtils.handleReflectionException(ex);
|
||||||
|
} catch (InstantiationException ex) {
|
||||||
|
ReflectionUtils.handleReflectionException(ex);
|
||||||
|
} catch (IllegalAccessException ex) {
|
||||||
|
ReflectionUtils.handleReflectionException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClazz(Class clazz) {
|
||||||
|
Assert.notNull(clazz, "Class required");
|
||||||
|
this.clazz = clazz;
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,15 +52,8 @@ public class WebAuthenticationDetails implements SessionIdentifierAware,
|
||||||
*/
|
*/
|
||||||
public WebAuthenticationDetails(HttpServletRequest request) {
|
public WebAuthenticationDetails(HttpServletRequest request) {
|
||||||
this.remoteAddress = request.getRemoteAddr();
|
this.remoteAddress = request.getRemoteAddr();
|
||||||
this.sessionId = request.getSession(true).getId();
|
|
||||||
doPopulateAdditionalInformation(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebAuthenticationDetails(HttpServletRequest request,
|
HttpSession session = request.getSession(false);
|
||||||
boolean forceSessionCreation) {
|
|
||||||
this.remoteAddress = request.getRemoteAddr();
|
|
||||||
|
|
||||||
HttpSession session = request.getSession(forceSessionCreation);
|
|
||||||
this.sessionId = (session != null) ? session.getId() : null;
|
this.sessionId = (session != null) ? session.getId() : null;
|
||||||
|
|
||||||
doPopulateAdditionalInformation(request);
|
doPopulateAdditionalInformation(request);
|
||||||
|
|
|
@ -23,8 +23,9 @@ import org.acegisecurity.context.SecurityContextHolder;
|
||||||
|
|
||||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
|
||||||
|
import org.acegisecurity.ui.AuthenticationDetailsSource;
|
||||||
|
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
|
||||||
import org.acegisecurity.ui.AuthenticationEntryPoint;
|
import org.acegisecurity.ui.AuthenticationEntryPoint;
|
||||||
import org.acegisecurity.ui.WebAuthenticationDetails;
|
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -115,9 +116,15 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
|
||||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
private boolean ignoreFailure = false;
|
private boolean ignoreFailure = false;
|
||||||
|
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||||
|
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required");
|
||||||
|
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||||
|
}
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
Assert.notNull(this.authenticationManager,
|
Assert.notNull(this.authenticationManager,
|
||||||
"An AuthenticationManager is required");
|
"An AuthenticationManager is required");
|
||||||
|
@ -168,8 +175,7 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
|
||||||
|| !existingAuth.isAuthenticated()) {
|
|| !existingAuth.isAuthenticated()) {
|
||||||
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,
|
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,
|
||||||
password);
|
password);
|
||||||
authRequest.setDetails(new WebAuthenticationDetails(
|
authRequest.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
|
||||||
httpRequest, false));
|
|
||||||
|
|
||||||
Authentication authResult;
|
Authentication authResult;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.acegisecurity.Authentication;
|
||||||
import org.acegisecurity.AuthenticationException;
|
import org.acegisecurity.AuthenticationException;
|
||||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
import org.acegisecurity.ui.AbstractProcessingFilter;
|
import org.acegisecurity.ui.AbstractProcessingFilter;
|
||||||
import org.acegisecurity.ui.WebAuthenticationDetails;
|
|
||||||
|
|
||||||
import javax.servlet.FilterConfig;
|
import javax.servlet.FilterConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
@ -105,7 +104,7 @@ public class CasProcessingFilter extends AbstractProcessingFilter {
|
||||||
UsernamePasswordAuthenticationToken authRequest =
|
UsernamePasswordAuthenticationToken authRequest =
|
||||||
new UsernamePasswordAuthenticationToken(username, password);
|
new UsernamePasswordAuthenticationToken(username, password);
|
||||||
|
|
||||||
authRequest.setDetails(new WebAuthenticationDetails(request, false));
|
authRequest.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
|
||||||
|
|
||||||
return this.getAuthenticationManager().authenticate(authRequest);
|
return this.getAuthenticationManager().authenticate(authRequest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -15,7 +15,42 @@
|
||||||
|
|
||||||
package org.acegisecurity.ui.digestauth;
|
package org.acegisecurity.ui.digestauth;
|
||||||
|
|
||||||
|
import org.acegisecurity.AcegiMessageSource;
|
||||||
|
import org.acegisecurity.AuthenticationException;
|
||||||
|
import org.acegisecurity.AuthenticationServiceException;
|
||||||
|
import org.acegisecurity.BadCredentialsException;
|
||||||
|
|
||||||
|
import org.acegisecurity.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.acegisecurity.providers.dao.UserCache;
|
||||||
|
import org.acegisecurity.providers.dao.cache.NullUserCache;
|
||||||
|
|
||||||
|
import org.acegisecurity.ui.AuthenticationDetailsSource;
|
||||||
|
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
|
||||||
|
|
||||||
|
import org.acegisecurity.userdetails.UserDetails;
|
||||||
|
import org.acegisecurity.userdetails.UserDetailsService;
|
||||||
|
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
||||||
|
|
||||||
|
import org.acegisecurity.util.StringSplitUtils;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.context.MessageSourceAware;
|
||||||
|
import org.springframework.context.support.MessageSourceAccessor;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.Filter;
|
import javax.servlet.Filter;
|
||||||
|
@ -27,30 +62,6 @@ import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.acegisecurity.AcegiMessageSource;
|
|
||||||
import org.acegisecurity.AuthenticationException;
|
|
||||||
import org.acegisecurity.AuthenticationServiceException;
|
|
||||||
import org.acegisecurity.BadCredentialsException;
|
|
||||||
import org.acegisecurity.context.SecurityContextHolder;
|
|
||||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.acegisecurity.providers.dao.UserCache;
|
|
||||||
import org.acegisecurity.providers.dao.cache.NullUserCache;
|
|
||||||
import org.acegisecurity.ui.WebAuthenticationDetails;
|
|
||||||
import org.acegisecurity.userdetails.UserDetails;
|
|
||||||
import org.acegisecurity.userdetails.UserDetailsService;
|
|
||||||
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
|
||||||
import org.acegisecurity.util.StringSplitUtils;
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.context.MessageSource;
|
|
||||||
import org.springframework.context.MessageSourceAware;
|
|
||||||
import org.springframework.context.support.MessageSourceAccessor;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a HTTP request's Digest authorization headers, putting the result
|
* Processes a HTTP request's Digest authorization headers, putting the result
|
||||||
|
@ -84,9 +95,9 @@ import org.springframework.util.StringUtils;
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If authentication fails, an {@link
|
* If authentication fails, an {@link
|
||||||
* org.acegisecurity.ui.AuthenticationEntryPoint
|
* org.acegisecurity.ui.AuthenticationEntryPoint AuthenticationEntryPoint}
|
||||||
* AuthenticationEntryPoint} implementation is called. This must always be
|
* implementation is called. This must always be {@link
|
||||||
* {@link DigestProcessingFilterEntryPoint}, which will prompt the user to
|
* DigestProcessingFilterEntryPoint}, which will prompt the user to
|
||||||
* authenticate again via Digest authentication.
|
* authenticate again via Digest authentication.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
|
@ -112,10 +123,11 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
|
||||||
|
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
private UserDetailsService userDetailsService;
|
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||||
private DigestProcessingFilterEntryPoint authenticationEntryPoint;
|
private DigestProcessingFilterEntryPoint authenticationEntryPoint;
|
||||||
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
|
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
|
||||||
private UserCache userCache = new NullUserCache();
|
private UserCache userCache = new NullUserCache();
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
private boolean passwordAlreadyEncoded = false;
|
private boolean passwordAlreadyEncoded = false;
|
||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
@ -369,10 +381,11 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
|
||||||
+ "' with response: '" + responseDigest + "'");
|
+ "' with response: '" + responseDigest + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
UsernamePasswordAuthenticationToken authRequest =
|
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(user,
|
||||||
new UsernamePasswordAuthenticationToken(user, user.getPassword());
|
user.getPassword());
|
||||||
|
|
||||||
authRequest.setDetails(new WebAuthenticationDetails(httpRequest, false));
|
authRequest.setDetails(authenticationDetailsSource.buildDetails(
|
||||||
|
(HttpServletRequest) request));
|
||||||
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authRequest);
|
SecurityContextHolder.getContext().setAuthentication(authRequest);
|
||||||
}
|
}
|
||||||
|
@ -405,8 +418,8 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
|
||||||
* <code>response</code> independently. Provided as a static method to
|
* <code>response</code> independently. Provided as a static method to
|
||||||
* simplify the coding of user agents.
|
* simplify the coding of user agents.
|
||||||
*
|
*
|
||||||
* @param passwordAlreadyEncoded true if the password argument is already encoded in
|
* @param passwordAlreadyEncoded true if the password argument is already
|
||||||
* the correct format. False if it is plain text.
|
* encoded in the correct format. False if it is plain text.
|
||||||
* @param username the user's login name.
|
* @param username the user's login name.
|
||||||
* @param realm the name of the realm.
|
* @param realm the name of the realm.
|
||||||
* @param password the user's password in plaintext or ready-encoded.
|
* @param password the user's password in plaintext or ready-encoded.
|
||||||
|
@ -419,7 +432,8 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
|
||||||
*
|
*
|
||||||
* @return the MD5 of the digest authentication response, encoded in hex
|
* @return the MD5 of the digest authentication response, encoded in hex
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if the supplied qop value is unsupported.
|
* @throws IllegalArgumentException if the supplied qop value is
|
||||||
|
* unsupported.
|
||||||
*/
|
*/
|
||||||
public static String generateDigest(boolean passwordAlreadyEncoded,
|
public static String generateDigest(boolean passwordAlreadyEncoded,
|
||||||
String username, String realm, String password, String httpMethod,
|
String username, String realm, String password, String httpMethod,
|
||||||
|
@ -454,10 +468,6 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
|
||||||
return digestMd5;
|
return digestMd5;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserDetailsService getUserDetailsService() {
|
|
||||||
return userDetailsService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DigestProcessingFilterEntryPoint getAuthenticationEntryPoint() {
|
public DigestProcessingFilterEntryPoint getAuthenticationEntryPoint() {
|
||||||
return authenticationEntryPoint;
|
return authenticationEntryPoint;
|
||||||
}
|
}
|
||||||
|
@ -466,10 +476,17 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
|
||||||
return userCache;
|
return userCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UserDetailsService getUserDetailsService() {
|
||||||
|
return userDetailsService;
|
||||||
|
}
|
||||||
|
|
||||||
public void init(FilterConfig ignored) throws ServletException {}
|
public void init(FilterConfig ignored) throws ServletException {}
|
||||||
|
|
||||||
public void setUserDetailsService(UserDetailsService authenticationDao) {
|
public void setAuthenticationDetailsSource(
|
||||||
this.userDetailsService = authenticationDao;
|
AuthenticationDetailsSource authenticationDetailsSource) {
|
||||||
|
Assert.notNull(authenticationDetailsSource,
|
||||||
|
"AuthenticationDetailsSource required");
|
||||||
|
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuthenticationEntryPoint(
|
public void setAuthenticationEntryPoint(
|
||||||
|
@ -488,4 +505,8 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
|
||||||
public void setUserCache(UserCache userCache) {
|
public void setUserCache(UserCache userCache) {
|
||||||
this.userCache = userCache;
|
this.userCache = userCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUserDetailsService(UserDetailsService authenticationDao) {
|
||||||
|
this.userDetailsService = authenticationDao;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ import org.acegisecurity.Authentication;
|
||||||
|
|
||||||
import org.acegisecurity.providers.rememberme.RememberMeAuthenticationToken;
|
import org.acegisecurity.providers.rememberme.RememberMeAuthenticationToken;
|
||||||
|
|
||||||
import org.acegisecurity.ui.WebAuthenticationDetails;
|
import org.acegisecurity.ui.AuthenticationDetailsSource;
|
||||||
|
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
|
||||||
|
|
||||||
import org.acegisecurity.userdetails.UserDetails;
|
import org.acegisecurity.userdetails.UserDetails;
|
||||||
import org.acegisecurity.userdetails.UserDetailsService;
|
import org.acegisecurity.userdetails.UserDetailsService;
|
||||||
|
@ -116,6 +117,7 @@ public class TokenBasedRememberMeServices implements RememberMeServices,
|
||||||
|
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||||
private String key;
|
private String key;
|
||||||
private String parameter = DEFAULT_PARAMETER;
|
private String parameter = DEFAULT_PARAMETER;
|
||||||
private UserDetailsService userDetailsService;
|
private UserDetailsService userDetailsService;
|
||||||
|
@ -232,8 +234,8 @@ public class TokenBasedRememberMeServices implements RememberMeServices,
|
||||||
|
|
||||||
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken(this.key,
|
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken(this.key,
|
||||||
userDetails, userDetails.getAuthorities());
|
userDetails, userDetails.getAuthorities());
|
||||||
auth.setDetails(new WebAuthenticationDetails(request,
|
auth.setDetails(authenticationDetailsSource.buildDetails(
|
||||||
false));
|
(HttpServletRequest) request));
|
||||||
|
|
||||||
return auth;
|
return auth;
|
||||||
} else {
|
} else {
|
||||||
|
@ -347,15 +349,23 @@ public class TokenBasedRememberMeServices implements RememberMeServices,
|
||||||
return cookie;
|
return cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Cookie makeValidCookie(long expiryTime, String tokenValueBase64, HttpServletRequest request) {
|
protected Cookie makeValidCookie(long expiryTime, String tokenValueBase64,
|
||||||
|
HttpServletRequest request) {
|
||||||
Cookie cookie = new Cookie(ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
|
Cookie cookie = new Cookie(ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
|
||||||
tokenValueBase64);
|
tokenValueBase64);
|
||||||
cookie.setMaxAge(60 * 60 * 24 * 365 * 5); // 5 years
|
cookie.setMaxAge(60 * 60 * 24 * 365 * 5); // 5 years
|
||||||
cookie.setPath(request.getContextPath());
|
cookie.setPath(request.getContextPath());
|
||||||
|
|
||||||
return cookie;
|
return cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAuthenticationDetailsSource(
|
||||||
|
AuthenticationDetailsSource authenticationDetailsSource) {
|
||||||
|
Assert.notNull(authenticationDetailsSource,
|
||||||
|
"AuthenticationDetailsSource required");
|
||||||
|
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||||
|
}
|
||||||
|
|
||||||
public void setKey(String key) {
|
public void setKey(String key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -15,7 +15,45 @@
|
||||||
|
|
||||||
package org.acegisecurity.ui.switchuser;
|
package org.acegisecurity.ui.switchuser;
|
||||||
|
|
||||||
|
import org.acegisecurity.AccountExpiredException;
|
||||||
|
import org.acegisecurity.AcegiMessageSource;
|
||||||
|
import org.acegisecurity.Authentication;
|
||||||
|
import org.acegisecurity.AuthenticationCredentialsNotFoundException;
|
||||||
|
import org.acegisecurity.AuthenticationException;
|
||||||
|
import org.acegisecurity.CredentialsExpiredException;
|
||||||
|
import org.acegisecurity.DisabledException;
|
||||||
|
import org.acegisecurity.GrantedAuthority;
|
||||||
|
import org.acegisecurity.LockedException;
|
||||||
|
|
||||||
|
import org.acegisecurity.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
import org.acegisecurity.event.authentication.AuthenticationSwitchUserEvent;
|
||||||
|
|
||||||
|
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
|
||||||
|
import org.acegisecurity.ui.AuthenticationDetailsSource;
|
||||||
|
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
|
||||||
|
|
||||||
|
import org.acegisecurity.userdetails.UserDetails;
|
||||||
|
import org.acegisecurity.userdetails.UserDetailsService;
|
||||||
|
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.ApplicationEventPublisherAware;
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.context.MessageSourceAware;
|
||||||
|
import org.springframework.context.support.MessageSourceAccessor;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -29,33 +67,6 @@ import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.acegisecurity.AccountExpiredException;
|
|
||||||
import org.acegisecurity.AcegiMessageSource;
|
|
||||||
import org.acegisecurity.Authentication;
|
|
||||||
import org.acegisecurity.AuthenticationCredentialsNotFoundException;
|
|
||||||
import org.acegisecurity.AuthenticationException;
|
|
||||||
import org.acegisecurity.CredentialsExpiredException;
|
|
||||||
import org.acegisecurity.DisabledException;
|
|
||||||
import org.acegisecurity.GrantedAuthority;
|
|
||||||
import org.acegisecurity.LockedException;
|
|
||||||
import org.acegisecurity.context.SecurityContextHolder;
|
|
||||||
import org.acegisecurity.event.authentication.AuthenticationSwitchUserEvent;
|
|
||||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.acegisecurity.ui.WebAuthenticationDetails;
|
|
||||||
import org.acegisecurity.userdetails.UserDetails;
|
|
||||||
import org.acegisecurity.userdetails.UserDetailsService;
|
|
||||||
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
|
||||||
import org.springframework.context.ApplicationEventPublisherAware;
|
|
||||||
import org.springframework.context.MessageSource;
|
|
||||||
import org.springframework.context.MessageSourceAware;
|
|
||||||
import org.springframework.context.support.MessageSourceAccessor;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch User processing filter responsible for user context switching.
|
* Switch User processing filter responsible for user context switching.
|
||||||
|
@ -104,7 +115,6 @@ import org.springframework.util.Assert;
|
||||||
* </pre>
|
* </pre>
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @author Mark St.Godard
|
* @author Mark St.Godard
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*
|
*
|
||||||
|
@ -124,15 +134,16 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
private ApplicationEventPublisher eventPublisher;
|
private ApplicationEventPublisher eventPublisher;
|
||||||
|
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||||
// ~ Instance fields
|
|
||||||
// ========================================================
|
|
||||||
private UserDetailsService userDetailsService;
|
|
||||||
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
|
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
|
||||||
private String exitUserUrl = "/j_acegi_exit_user";
|
private String exitUserUrl = "/j_acegi_exit_user";
|
||||||
private String switchUserUrl = "/j_acegi_switch_user";
|
private String switchUserUrl = "/j_acegi_switch_user";
|
||||||
private String targetUrl;
|
private String targetUrl;
|
||||||
|
|
||||||
|
// ~ Instance fields
|
||||||
|
// ========================================================
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
@ -160,369 +171,344 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
|
||||||
Authentication current = SecurityContextHolder.getContext()
|
Authentication current = SecurityContextHolder.getContext()
|
||||||
.getAuthentication();
|
.getAuthentication();
|
||||||
|
|
||||||
if (null == current) {
|
if (null == current) {
|
||||||
throw new AuthenticationCredentialsNotFoundException(messages
|
throw new AuthenticationCredentialsNotFoundException(messages
|
||||||
.getMessage("SwitchUserProcessingFilter.noCurrentUser",
|
.getMessage("SwitchUserProcessingFilter.noCurrentUser",
|
||||||
"No current user associated with this request"));
|
"No current user associated with this request"));
|
||||||
}
|
|
||||||
|
|
||||||
// check to see if the current user did actual switch to another user
|
|
||||||
// if so, get the original source user so we can switch back
|
|
||||||
Authentication original = getSourceAuthentication(current);
|
|
||||||
|
|
||||||
if (original == null) {
|
|
||||||
logger.error(
|
|
||||||
"Could not find original user Authentication object!");
|
|
||||||
throw new AuthenticationCredentialsNotFoundException(messages
|
|
||||||
.getMessage(
|
|
||||||
"SwitchUserProcessingFilter.noOriginalAuthentication",
|
|
||||||
"Could not find original Authentication object"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the source user details
|
|
||||||
UserDetails originalUser = null;
|
|
||||||
Object obj = original.getPrincipal();
|
|
||||||
|
|
||||||
if ((obj != null) && obj instanceof UserDetails) {
|
|
||||||
originalUser = (UserDetails) obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
// publish event
|
|
||||||
if (this.eventPublisher != null) {
|
|
||||||
eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(
|
|
||||||
current, originalUser));
|
|
||||||
}
|
|
||||||
|
|
||||||
return original;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// check to see if the current user did actual switch to another user
|
||||||
* Attempt to switch to another user. If the user does not exist or
|
// if so, get the original source user so we can switch back
|
||||||
* is not active, return null.
|
Authentication original = getSourceAuthentication(current);
|
||||||
*
|
|
||||||
* @param request The http request
|
|
||||||
*
|
|
||||||
* @return The new <code>Authentication</code> request if
|
|
||||||
* successfully switched to another user,
|
|
||||||
* <code>null</code> otherwise.
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
* @throws UsernameNotFoundException If the target user is not
|
|
||||||
* found.
|
|
||||||
* @throws LockedException DOCUMENT ME!
|
|
||||||
* @throws DisabledException If the target user is disabled.
|
|
||||||
* @throws AccountExpiredException If the target user account is
|
|
||||||
* expired.
|
|
||||||
* @throws CredentialsExpiredException If the target user
|
|
||||||
* credentials are expired.
|
|
||||||
*/
|
|
||||||
protected Authentication attemptSwitchUser(
|
|
||||||
HttpServletRequest request) throws AuthenticationException {
|
|
||||||
UsernamePasswordAuthenticationToken targetUserRequest = null;
|
|
||||||
|
|
||||||
String username = request.getParameter(ACEGI_SECURITY_SWITCH_USERNAME_KEY);
|
if (original == null) {
|
||||||
|
logger.error("Could not find original user Authentication object!");
|
||||||
|
throw new AuthenticationCredentialsNotFoundException(messages
|
||||||
|
.getMessage("SwitchUserProcessingFilter.noOriginalAuthentication",
|
||||||
|
"Could not find original Authentication object"));
|
||||||
|
}
|
||||||
|
|
||||||
if (username == null) {
|
// get the source user details
|
||||||
username = "";
|
UserDetails originalUser = null;
|
||||||
|
Object obj = original.getPrincipal();
|
||||||
|
|
||||||
|
if ((obj != null) && obj instanceof UserDetails) {
|
||||||
|
originalUser = (UserDetails) obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish event
|
||||||
|
if (this.eventPublisher != null) {
|
||||||
|
eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(
|
||||||
|
current, originalUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to switch to another user. If the user does not exist or is not
|
||||||
|
* active, return null.
|
||||||
|
*
|
||||||
|
* @param request The http request
|
||||||
|
*
|
||||||
|
* @return The new <code>Authentication</code> request if successfully
|
||||||
|
* switched to another user, <code>null</code> otherwise.
|
||||||
|
*
|
||||||
|
* @throws AuthenticationException
|
||||||
|
* @throws UsernameNotFoundException If the target user is not found.
|
||||||
|
* @throws LockedException DOCUMENT ME!
|
||||||
|
* @throws DisabledException If the target user is disabled.
|
||||||
|
* @throws AccountExpiredException If the target user account is expired.
|
||||||
|
* @throws CredentialsExpiredException If the target user credentials are
|
||||||
|
* expired.
|
||||||
|
*/
|
||||||
|
protected Authentication attemptSwitchUser(HttpServletRequest request)
|
||||||
|
throws AuthenticationException {
|
||||||
|
UsernamePasswordAuthenticationToken targetUserRequest = null;
|
||||||
|
|
||||||
|
String username = request.getParameter(ACEGI_SECURITY_SWITCH_USERNAME_KEY);
|
||||||
|
|
||||||
|
if (username == null) {
|
||||||
|
username = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Attempt to switch to user [" + username + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the user by name
|
||||||
|
UserDetails targetUser = this.userDetailsService.loadUserByUsername(username);
|
||||||
|
|
||||||
|
// user not found
|
||||||
|
if (targetUser == null) {
|
||||||
|
throw new UsernameNotFoundException(messages.getMessage(
|
||||||
|
"SwitchUserProcessingFilter.usernameNotFound",
|
||||||
|
new Object[] {username}, "Username {0} not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// account is expired
|
||||||
|
if (!targetUser.isAccountNonLocked()) {
|
||||||
|
throw new LockedException(messages.getMessage(
|
||||||
|
"SwitchUserProcessingFilter.locked",
|
||||||
|
"User account is locked"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// user is disabled
|
||||||
|
if (!targetUser.isEnabled()) {
|
||||||
|
throw new DisabledException(messages.getMessage(
|
||||||
|
"SwitchUserProcessingFilter.disabled", "User is disabled"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// account is expired
|
||||||
|
if (!targetUser.isAccountNonExpired()) {
|
||||||
|
throw new AccountExpiredException(messages.getMessage(
|
||||||
|
"SwitchUserProcessingFilter.expired",
|
||||||
|
"User account has expired"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// credentials expired
|
||||||
|
if (!targetUser.isCredentialsNonExpired()) {
|
||||||
|
throw new CredentialsExpiredException(messages.getMessage(
|
||||||
|
"SwitchUserProcessingFilter.credentialsExpired",
|
||||||
|
"User credentials have expired"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ok, create the switch user token
|
||||||
|
targetUserRequest = createSwitchUserToken(request, username, targetUser);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Switch User Token [" + targetUserRequest + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish event
|
||||||
|
if (this.eventPublisher != null) {
|
||||||
|
eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(
|
||||||
|
SecurityContextHolder.getContext().getAuthentication(),
|
||||||
|
targetUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetUserRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a switch user token that contains an additional
|
||||||
|
* <tt>GrantedAuthority</tt> that contains the original
|
||||||
|
* <code>Authentication</code> object.
|
||||||
|
*
|
||||||
|
* @param request The http servlet request.
|
||||||
|
* @param username The username of target user
|
||||||
|
* @param targetUser The target user
|
||||||
|
*
|
||||||
|
* @return The authentication token
|
||||||
|
*
|
||||||
|
* @see SwitchUserGrantedAuthority
|
||||||
|
*/
|
||||||
|
private UsernamePasswordAuthenticationToken createSwitchUserToken(
|
||||||
|
HttpServletRequest request, String username, UserDetails targetUser) {
|
||||||
|
UsernamePasswordAuthenticationToken targetUserRequest;
|
||||||
|
|
||||||
|
// grant an additional authority that contains the original Authentication object
|
||||||
|
// which will be used to 'exit' from the current switched user.
|
||||||
|
Authentication currentAuth = SecurityContextHolder.getContext()
|
||||||
|
.getAuthentication();
|
||||||
|
GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(ROLE_PREVIOUS_ADMINISTRATOR,
|
||||||
|
currentAuth);
|
||||||
|
|
||||||
|
// get the original authorities
|
||||||
|
List orig = Arrays.asList(targetUser.getAuthorities());
|
||||||
|
|
||||||
|
// add the new switch user authority
|
||||||
|
List newAuths = new ArrayList(orig);
|
||||||
|
newAuths.add(switchAuthority);
|
||||||
|
|
||||||
|
GrantedAuthority[] authorities = {};
|
||||||
|
authorities = (GrantedAuthority[]) newAuths.toArray(authorities);
|
||||||
|
|
||||||
|
// create the new authentication token
|
||||||
|
targetUserRequest = new UsernamePasswordAuthenticationToken(targetUser,
|
||||||
|
targetUser.getPassword(), authorities);
|
||||||
|
|
||||||
|
// set details
|
||||||
|
targetUserRequest.setDetails(authenticationDetailsSource.buildDetails(
|
||||||
|
(HttpServletRequest) request));
|
||||||
|
|
||||||
|
return targetUserRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see javax.servlet.Filter#doFilter
|
||||||
|
*/
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain) throws IOException, ServletException {
|
||||||
|
Assert.isInstanceOf(HttpServletRequest.class, request);
|
||||||
|
Assert.isInstanceOf(HttpServletResponse.class, response);
|
||||||
|
|
||||||
|
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||||
|
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||||
|
|
||||||
|
// check for switch or exit request
|
||||||
|
if (requiresSwitchUser(httpRequest)) {
|
||||||
|
// if set, attempt switch and store original
|
||||||
|
Authentication targetUser = attemptSwitchUser(httpRequest);
|
||||||
|
|
||||||
|
// update the current context to the new target user
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(targetUser);
|
||||||
|
|
||||||
|
// redirect to target url
|
||||||
|
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(httpRequest
|
||||||
|
.getContextPath() + targetUrl));
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else if (requiresExitUser(httpRequest)) {
|
||||||
|
// get the original authentication object (if exists)
|
||||||
|
Authentication originalUser = attemptExitUser(httpRequest);
|
||||||
|
|
||||||
|
// update the current context back to the original user
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(originalUser);
|
||||||
|
|
||||||
|
// redirect to target url
|
||||||
|
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(httpRequest
|
||||||
|
.getContextPath() + targetUrl));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the original <code>Authentication</code> object from the current
|
||||||
|
* user's granted authorities. A successfully switched user should have a
|
||||||
|
* <code>SwitchUserGrantedAuthority</code> that contains the original
|
||||||
|
* source user <code>Authentication</code> object.
|
||||||
|
*
|
||||||
|
* @param current The current <code>Authentication</code> object
|
||||||
|
*
|
||||||
|
* @return The source user <code>Authentication</code> object or
|
||||||
|
* <code>null</code> otherwise.
|
||||||
|
*/
|
||||||
|
private Authentication getSourceAuthentication(Authentication current) {
|
||||||
|
Authentication original = null;
|
||||||
|
|
||||||
|
// iterate over granted authorities and find the 'switch user' authority
|
||||||
|
GrantedAuthority[] authorities = current.getAuthorities();
|
||||||
|
|
||||||
|
for (int i = 0; i < authorities.length; i++) {
|
||||||
|
// check for switch user type of authority
|
||||||
|
if (authorities[i] instanceof SwitchUserGrantedAuthority) {
|
||||||
|
original = ((SwitchUserGrantedAuthority) authorities[i])
|
||||||
|
.getSource();
|
||||||
|
logger.debug("Found original switch user granted authority ["
|
||||||
|
+ original + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Attempt to switch to user [" + username + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the user by name
|
|
||||||
UserDetails targetUser = this.userDetailsService
|
|
||||||
.loadUserByUsername(username);
|
|
||||||
|
|
||||||
// user not found
|
|
||||||
if (targetUser == null) {
|
|
||||||
throw new UsernameNotFoundException(messages.getMessage(
|
|
||||||
"SwitchUserProcessingFilter.usernameNotFound",
|
|
||||||
new Object[] {username},
|
|
||||||
"Username {0} not found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// account is expired
|
|
||||||
if (!targetUser.isAccountNonLocked()) {
|
|
||||||
throw new LockedException(messages.getMessage(
|
|
||||||
"SwitchUserProcessingFilter.locked",
|
|
||||||
"User account is locked"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// user is disabled
|
|
||||||
if (!targetUser.isEnabled()) {
|
|
||||||
throw new DisabledException(messages.getMessage(
|
|
||||||
"SwitchUserProcessingFilter.disabled",
|
|
||||||
"User is disabled"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// account is expired
|
|
||||||
if (!targetUser.isAccountNonExpired()) {
|
|
||||||
throw new AccountExpiredException(messages.getMessage(
|
|
||||||
"SwitchUserProcessingFilter.expired",
|
|
||||||
"User account has expired"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// credentials expired
|
|
||||||
if (!targetUser.isCredentialsNonExpired()) {
|
|
||||||
throw new CredentialsExpiredException(messages
|
|
||||||
.getMessage(
|
|
||||||
"SwitchUserProcessingFilter.credentialsExpired",
|
|
||||||
"User credentials have expired"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ok, create the switch user token
|
|
||||||
targetUserRequest = createSwitchUserToken(request,
|
|
||||||
username, targetUser);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Switch User Token [" + targetUserRequest + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
// publish event
|
|
||||||
if (this.eventPublisher != null) {
|
|
||||||
eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(
|
|
||||||
SecurityContextHolder.getContext().getAuthentication(),
|
|
||||||
targetUser));
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetUserRequest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return original;
|
||||||
* Create a switch user token that contains an additional
|
}
|
||||||
* <tt>GrantedAuthority</tt> that contains the original
|
|
||||||
* <code>Authentication</code> object.
|
|
||||||
*
|
|
||||||
* @param request The http servlet request.
|
|
||||||
* @param username The username of target user
|
|
||||||
* @param targetUser The target user
|
|
||||||
*
|
|
||||||
* @return The authentication token
|
|
||||||
*
|
|
||||||
* @see SwitchUserGrantedAuthority
|
|
||||||
*/
|
|
||||||
private UsernamePasswordAuthenticationToken createSwitchUserToken(
|
|
||||||
HttpServletRequest request, String username,
|
|
||||||
UserDetails targetUser) {
|
|
||||||
UsernamePasswordAuthenticationToken targetUserRequest;
|
|
||||||
|
|
||||||
// grant an additional authority that contains the original Authentication object
|
public void init(FilterConfig ignored) throws ServletException {}
|
||||||
// which will be used to 'exit' from the current switched user.
|
|
||||||
Authentication currentAuth = SecurityContextHolder.getContext()
|
|
||||||
.getAuthentication();
|
|
||||||
GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(ROLE_PREVIOUS_ADMINISTRATOR,
|
|
||||||
currentAuth);
|
|
||||||
|
|
||||||
// get the original authorities
|
/**
|
||||||
List orig = Arrays.asList(targetUser.getAuthorities());
|
* Checks the request URI for the presence of <tt>exitUserUrl</tt>.
|
||||||
|
*
|
||||||
|
* @param request The http servlet request
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the request requires a exit user,
|
||||||
|
* <code>false</code> otherwise.
|
||||||
|
*
|
||||||
|
* @see SwitchUserProcessingFilter#exitUserUrl
|
||||||
|
*/
|
||||||
|
protected boolean requiresExitUser(HttpServletRequest request) {
|
||||||
|
String uri = stripUri(request);
|
||||||
|
|
||||||
// add the new switch user authority
|
return uri.endsWith(request.getContextPath() + exitUserUrl);
|
||||||
List newAuths = new ArrayList(orig);
|
}
|
||||||
newAuths.add(switchAuthority);
|
|
||||||
|
|
||||||
GrantedAuthority[] authorities = {};
|
/**
|
||||||
authorities = (GrantedAuthority[]) newAuths.toArray(authorities);
|
* Checks the request URI for the presence of <tt>switchUserUrl</tt>.
|
||||||
|
*
|
||||||
|
* @param request The http servlet request
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the request requires a switch,
|
||||||
|
* <code>false</code> otherwise.
|
||||||
|
*
|
||||||
|
* @see SwitchUserProcessingFilter#switchUserUrl
|
||||||
|
*/
|
||||||
|
protected boolean requiresSwitchUser(HttpServletRequest request) {
|
||||||
|
String uri = stripUri(request);
|
||||||
|
|
||||||
// create the new authentication token
|
return uri.endsWith(request.getContextPath() + switchUserUrl);
|
||||||
targetUserRequest = new UsernamePasswordAuthenticationToken(targetUser,
|
}
|
||||||
targetUser.getPassword(), authorities);
|
|
||||||
|
|
||||||
// set details
|
public void setApplicationEventPublisher(
|
||||||
targetUserRequest.setDetails(new WebAuthenticationDetails(
|
ApplicationEventPublisher eventPublisher) throws BeansException {
|
||||||
request, false));
|
this.eventPublisher = eventPublisher;
|
||||||
|
}
|
||||||
|
|
||||||
return targetUserRequest;
|
public void setAuthenticationDetailsSource(
|
||||||
|
AuthenticationDetailsSource authenticationDetailsSource) {
|
||||||
|
Assert.notNull(authenticationDetailsSource,
|
||||||
|
"AuthenticationDetailsSource required");
|
||||||
|
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the URL to respond to exit user processing.
|
||||||
|
*
|
||||||
|
* @param exitUserUrl The exit user URL.
|
||||||
|
*/
|
||||||
|
public void setExitUserUrl(String exitUserUrl) {
|
||||||
|
this.exitUserUrl = exitUserUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageSource(MessageSource messageSource) {
|
||||||
|
this.messages = new MessageSourceAccessor(messageSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the URL to respond to switch user processing.
|
||||||
|
*
|
||||||
|
* @param switchUserUrl The switch user URL.
|
||||||
|
*/
|
||||||
|
public void setSwitchUserUrl(String switchUserUrl) {
|
||||||
|
this.switchUserUrl = switchUserUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL to go to after a successful switch / exit user request.
|
||||||
|
*
|
||||||
|
* @param targetUrl The target url.
|
||||||
|
*/
|
||||||
|
public void setTargetUrl(String targetUrl) {
|
||||||
|
this.targetUrl = targetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the authentication data access object.
|
||||||
|
*
|
||||||
|
* @param authenticationDao The authentication dao
|
||||||
|
*/
|
||||||
|
public void setUserDetailsService(UserDetailsService authenticationDao) {
|
||||||
|
this.userDetailsService = authenticationDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strips any content after the ';' in the request URI
|
||||||
|
*
|
||||||
|
* @param request The http request
|
||||||
|
*
|
||||||
|
* @return The stripped uri
|
||||||
|
*/
|
||||||
|
private static String stripUri(HttpServletRequest request) {
|
||||||
|
String uri = request.getRequestURI();
|
||||||
|
int idx = uri.indexOf(';');
|
||||||
|
|
||||||
|
if (idx > 0) {
|
||||||
|
uri = uri.substring(0, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {}
|
return uri;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* @see javax.servlet.Filter#doFilter
|
|
||||||
*/
|
|
||||||
public void doFilter(ServletRequest request,
|
|
||||||
ServletResponse response, FilterChain chain)
|
|
||||||
throws IOException, ServletException {
|
|
||||||
Assert.isInstanceOf(HttpServletRequest.class, request);
|
|
||||||
Assert.isInstanceOf(HttpServletResponse.class, response);
|
|
||||||
|
|
||||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
|
||||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
|
||||||
|
|
||||||
// check for switch or exit request
|
|
||||||
if (requiresSwitchUser(httpRequest)) {
|
|
||||||
// if set, attempt switch and store original
|
|
||||||
Authentication targetUser = attemptSwitchUser(httpRequest);
|
|
||||||
|
|
||||||
// update the current context to the new target user
|
|
||||||
SecurityContextHolder.getContext()
|
|
||||||
.setAuthentication(targetUser);
|
|
||||||
|
|
||||||
// redirect to target url
|
|
||||||
httpResponse.sendRedirect(httpResponse
|
|
||||||
.encodeRedirectURL(httpRequest
|
|
||||||
.getContextPath() + targetUrl));
|
|
||||||
|
|
||||||
return;
|
|
||||||
} else if (requiresExitUser(httpRequest)) {
|
|
||||||
// get the original authentication object (if exists)
|
|
||||||
Authentication originalUser = attemptExitUser(httpRequest);
|
|
||||||
|
|
||||||
// update the current context back to the original user
|
|
||||||
SecurityContextHolder.getContext()
|
|
||||||
.setAuthentication(originalUser);
|
|
||||||
|
|
||||||
// redirect to target url
|
|
||||||
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(
|
|
||||||
httpRequest.getContextPath() + targetUrl));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
chain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the original <code>Authentication</code> object from
|
|
||||||
* the current user's granted authorities. A successfully switched
|
|
||||||
* user should have a <code>SwitchUserGrantedAuthority</code>
|
|
||||||
* that contains the original source user <code>Authentication</code>
|
|
||||||
* object.
|
|
||||||
*
|
|
||||||
* @param current The current <code>Authentication</code>
|
|
||||||
* object
|
|
||||||
*
|
|
||||||
* @return The source user <code>Authentication</code>
|
|
||||||
* object or <code>null</code> otherwise.
|
|
||||||
*/
|
|
||||||
private Authentication getSourceAuthentication(
|
|
||||||
Authentication current) {
|
|
||||||
Authentication original = null;
|
|
||||||
|
|
||||||
// iterate over granted authorities and find the 'switch user' authority
|
|
||||||
GrantedAuthority[] authorities = current
|
|
||||||
.getAuthorities();
|
|
||||||
|
|
||||||
for (int i = 0; i < authorities.length; i++) {
|
|
||||||
// check for switch user type of authority
|
|
||||||
if (authorities[i] instanceof SwitchUserGrantedAuthority) {
|
|
||||||
original = ((SwitchUserGrantedAuthority) authorities[i])
|
|
||||||
.getSource();
|
|
||||||
logger.debug(
|
|
||||||
"Found original switch user granted authority ["
|
|
||||||
+ original + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(FilterConfig ignored)
|
|
||||||
throws ServletException {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the request URI for the presence
|
|
||||||
* of <tt>exitUserUrl</tt>.
|
|
||||||
*
|
|
||||||
* @param request The http servlet request
|
|
||||||
*
|
|
||||||
* @return <code>true</code> if the request requires a exit user,
|
|
||||||
* <code>false</code> otherwise.
|
|
||||||
*
|
|
||||||
* @see SwitchUserProcessingFilter#exitUserUrl
|
|
||||||
*/
|
|
||||||
protected boolean requiresExitUser(
|
|
||||||
HttpServletRequest request) {
|
|
||||||
String uri = stripUri(request);
|
|
||||||
|
|
||||||
return uri.endsWith(request
|
|
||||||
.getContextPath() + exitUserUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the request URI for the presence of <tt>switchUserUrl</tt>.
|
|
||||||
*
|
|
||||||
* @param request The http servlet request
|
|
||||||
*
|
|
||||||
* @return <code>true</code> if the request requires a switch,
|
|
||||||
* <code>false</code> otherwise.
|
|
||||||
*
|
|
||||||
* @see SwitchUserProcessingFilter#switchUserUrl
|
|
||||||
*/
|
|
||||||
protected boolean requiresSwitchUser(
|
|
||||||
HttpServletRequest request) {
|
|
||||||
String uri = stripUri(request);
|
|
||||||
|
|
||||||
return uri.endsWith(request.getContextPath() + switchUserUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setApplicationEventPublisher(
|
|
||||||
ApplicationEventPublisher eventPublisher)
|
|
||||||
throws BeansException {
|
|
||||||
this.eventPublisher = eventPublisher;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the authentication data access object.
|
|
||||||
*
|
|
||||||
* @param authenticationDao The authentication dao
|
|
||||||
*/
|
|
||||||
public void setUserDetailsService(
|
|
||||||
UserDetailsService authenticationDao) {
|
|
||||||
this.userDetailsService = authenticationDao;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the URL to respond to exit user processing.
|
|
||||||
*
|
|
||||||
* @param exitUserUrl The exit user URL.
|
|
||||||
*/
|
|
||||||
public void setExitUserUrl(
|
|
||||||
String exitUserUrl) {
|
|
||||||
this.exitUserUrl = exitUserUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessageSource(
|
|
||||||
MessageSource messageSource) {
|
|
||||||
this.messages = new MessageSourceAccessor(messageSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the URL to respond to switch user processing.
|
|
||||||
*
|
|
||||||
* @param switchUserUrl The switch user URL.
|
|
||||||
*/
|
|
||||||
public void setSwitchUserUrl(String switchUserUrl) {
|
|
||||||
this.switchUserUrl = switchUserUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the URL to go to after a successful switch / exit user
|
|
||||||
* request.
|
|
||||||
*
|
|
||||||
* @param targetUrl The target url.
|
|
||||||
*/
|
|
||||||
public void setTargetUrl(
|
|
||||||
String targetUrl) {
|
|
||||||
this.targetUrl = targetUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strips any content after the ';' in the request URI
|
|
||||||
*
|
|
||||||
* @param request The http request
|
|
||||||
*
|
|
||||||
* @return The stripped uri
|
|
||||||
*/
|
|
||||||
private static String stripUri(HttpServletRequest request) {
|
|
||||||
String uri = request.getRequestURI();
|
|
||||||
int idx = uri.indexOf(';');
|
|
||||||
|
|
||||||
if (idx > 0) {
|
|
||||||
uri = uri.substring(0,
|
|
||||||
idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,9 +17,10 @@ package org.acegisecurity.ui.webapp;
|
||||||
|
|
||||||
import org.acegisecurity.Authentication;
|
import org.acegisecurity.Authentication;
|
||||||
import org.acegisecurity.AuthenticationException;
|
import org.acegisecurity.AuthenticationException;
|
||||||
|
|
||||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
|
||||||
import org.acegisecurity.ui.AbstractProcessingFilter;
|
import org.acegisecurity.ui.AbstractProcessingFilter;
|
||||||
import org.acegisecurity.ui.WebAuthenticationDetails;
|
|
||||||
|
|
||||||
import javax.servlet.FilterConfig;
|
import javax.servlet.FilterConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
@ -55,15 +56,6 @@ public class AuthenticationProcessingFilter extends AbstractProcessingFilter {
|
||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
/**
|
|
||||||
* This filter by default responds to <code>/j_acegi_security_check</code>.
|
|
||||||
*
|
|
||||||
* @return the default
|
|
||||||
*/
|
|
||||||
public String getDefaultFilterProcessesUrl() {
|
|
||||||
return "/j_acegi_security_check";
|
|
||||||
}
|
|
||||||
|
|
||||||
public Authentication attemptAuthentication(HttpServletRequest request)
|
public Authentication attemptAuthentication(HttpServletRequest request)
|
||||||
throws AuthenticationException {
|
throws AuthenticationException {
|
||||||
String username = obtainUsername(request);
|
String username = obtainUsername(request);
|
||||||
|
@ -84,28 +76,23 @@ public class AuthenticationProcessingFilter extends AbstractProcessingFilter {
|
||||||
setDetails(request, authRequest);
|
setDetails(request, authRequest);
|
||||||
|
|
||||||
// Place the last username attempted into HttpSession for views
|
// Place the last username attempted into HttpSession for views
|
||||||
request.getSession().setAttribute(ACEGI_SECURITY_LAST_USERNAME_KEY,
|
request.getSession()
|
||||||
username);
|
.setAttribute(ACEGI_SECURITY_LAST_USERNAME_KEY, username);
|
||||||
|
|
||||||
return this.getAuthenticationManager().authenticate(authRequest);
|
return this.getAuthenticationManager().authenticate(authRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provided so that subclasses may configure what is put into the
|
* This filter by default responds to <code>/j_acegi_security_check</code>.
|
||||||
* authentication request's details property. The default implementation
|
|
||||||
* simply constructs {@link WebAuthenticationDetails}.
|
|
||||||
*
|
*
|
||||||
* @param request that an authentication request is being created for
|
* @return the default
|
||||||
* @param authRequest the authentication request object that should have
|
|
||||||
* its details set
|
|
||||||
*/
|
*/
|
||||||
protected void setDetails(HttpServletRequest request,
|
public String getDefaultFilterProcessesUrl() {
|
||||||
UsernamePasswordAuthenticationToken authRequest) {
|
return "/j_acegi_security_check";
|
||||||
authRequest.setDetails(new WebAuthenticationDetails(request, false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables subclasses to override the composition of the password, such as
|
* Enables subclasses to override the composition of the password, such as
|
||||||
* by including additional values and a separator.
|
* by including additional values and a separator.
|
||||||
|
@ -141,4 +128,17 @@ public class AuthenticationProcessingFilter extends AbstractProcessingFilter {
|
||||||
protected String obtainUsername(HttpServletRequest request) {
|
protected String obtainUsername(HttpServletRequest request) {
|
||||||
return request.getParameter(ACEGI_SECURITY_FORM_USERNAME_KEY);
|
return request.getParameter(ACEGI_SECURITY_FORM_USERNAME_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provided so that subclasses may configure what is put into the
|
||||||
|
* authentication request's details property.
|
||||||
|
*
|
||||||
|
* @param request that an authentication request is being created for
|
||||||
|
* @param authRequest the authentication request object that should have
|
||||||
|
* its details set
|
||||||
|
*/
|
||||||
|
protected void setDetails(HttpServletRequest request,
|
||||||
|
UsernamePasswordAuthenticationToken authRequest) {
|
||||||
|
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,19 +18,24 @@ package org.acegisecurity.ui.x509;
|
||||||
import org.acegisecurity.Authentication;
|
import org.acegisecurity.Authentication;
|
||||||
import org.acegisecurity.AuthenticationException;
|
import org.acegisecurity.AuthenticationException;
|
||||||
import org.acegisecurity.AuthenticationManager;
|
import org.acegisecurity.AuthenticationManager;
|
||||||
|
|
||||||
import org.acegisecurity.context.SecurityContextHolder;
|
import org.acegisecurity.context.SecurityContextHolder;
|
||||||
|
|
||||||
import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent;
|
import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent;
|
||||||
|
|
||||||
import org.acegisecurity.providers.x509.X509AuthenticationToken;
|
import org.acegisecurity.providers.x509.X509AuthenticationToken;
|
||||||
|
|
||||||
import org.acegisecurity.ui.AbstractProcessingFilter;
|
import org.acegisecurity.ui.AbstractProcessingFilter;
|
||||||
import org.acegisecurity.ui.WebAuthenticationDetails;
|
import org.acegisecurity.ui.AuthenticationDetailsSource;
|
||||||
|
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationEventPublisherAware;
|
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.ApplicationEventPublisherAware;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@ -60,10 +65,11 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If authentication is successful, an {@link
|
* If authentication is successful, an {@link
|
||||||
* org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent} will be
|
* org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent}
|
||||||
* published to the application context. No events will be published if
|
* will be published to the application context. No events will be published
|
||||||
* authentication was unsuccessful, because this would generally be recorded
|
* if authentication was unsuccessful, because this would generally be
|
||||||
* via an <code>AuthenticationManager</code>-specific application event.
|
* recorded via an <code>AuthenticationManager</code>-specific application
|
||||||
|
* event.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -76,7 +82,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public class X509ProcessingFilter implements Filter, InitializingBean,
|
public class X509ProcessingFilter implements Filter, InitializingBean,
|
||||||
ApplicationEventPublisherAware {
|
ApplicationEventPublisherAware {
|
||||||
//~ Static fields/initializers =============================================
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(X509ProcessingFilter.class);
|
private static final Log logger = LogFactory.getLog(X509ProcessingFilter.class);
|
||||||
|
@ -84,19 +90,11 @@ public class X509ProcessingFilter implements Filter, InitializingBean,
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
private ApplicationEventPublisher eventPublisher;
|
private ApplicationEventPublisher eventPublisher;
|
||||||
|
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
public void setApplicationEventPublisher(ApplicationEventPublisher context) {
|
|
||||||
this.eventPublisher = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthenticationManager(
|
|
||||||
AuthenticationManager authenticationManager) {
|
|
||||||
this.authenticationManager = authenticationManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
Assert.notNull(authenticationManager,
|
Assert.notNull(authenticationManager,
|
||||||
"An AuthenticationManager must be set");
|
"An AuthenticationManager must be set");
|
||||||
|
@ -154,7 +152,8 @@ public class X509ProcessingFilter implements Filter, InitializingBean,
|
||||||
try {
|
try {
|
||||||
X509AuthenticationToken authRequest = new X509AuthenticationToken(clientCertificate);
|
X509AuthenticationToken authRequest = new X509AuthenticationToken(clientCertificate);
|
||||||
|
|
||||||
authRequest.setDetails(new WebAuthenticationDetails(httpRequest));
|
authRequest.setDetails(authenticationDetailsSource.buildDetails(
|
||||||
|
(HttpServletRequest) request));
|
||||||
authResult = authenticationManager.authenticate(authRequest);
|
authResult = authenticationManager.authenticate(authRequest);
|
||||||
successfulAuthentication(httpRequest, httpResponse, authResult);
|
successfulAuthentication(httpRequest, httpResponse, authResult);
|
||||||
} catch (AuthenticationException failed) {
|
} catch (AuthenticationException failed) {
|
||||||
|
@ -165,8 +164,39 @@ public class X509ProcessingFilter implements Filter, InitializingBean,
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private X509Certificate extractClientCertificate(HttpServletRequest request) {
|
||||||
|
X509Certificate[] certs = (X509Certificate[]) request.getAttribute(
|
||||||
|
"javax.servlet.request.X509Certificate");
|
||||||
|
|
||||||
|
if ((certs != null) && (certs.length > 0)) {
|
||||||
|
return certs[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("No client certificate found in request.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public void init(FilterConfig ignored) throws ServletException {}
|
public void init(FilterConfig ignored) throws ServletException {}
|
||||||
|
|
||||||
|
public void setApplicationEventPublisher(ApplicationEventPublisher context) {
|
||||||
|
this.eventPublisher = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthenticationDetailsSource(
|
||||||
|
AuthenticationDetailsSource authenticationDetailsSource) {
|
||||||
|
Assert.notNull(authenticationDetailsSource,
|
||||||
|
"AuthenticationDetailsSource required");
|
||||||
|
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthenticationManager(
|
||||||
|
AuthenticationManager authenticationManager) {
|
||||||
|
this.authenticationManager = authenticationManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the <code>Authentication</code> instance returned by the
|
* Puts the <code>Authentication</code> instance returned by the
|
||||||
* authentication manager into the secure context.
|
* authentication manager into the secure context.
|
||||||
|
@ -206,25 +236,12 @@ public class X509ProcessingFilter implements Filter, InitializingBean,
|
||||||
SecurityContextHolder.getContext().setAuthentication(null);
|
SecurityContextHolder.getContext().setAuthentication(null);
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Updated SecurityContextHolder to contain null Authentication");
|
logger.debug(
|
||||||
|
"Updated SecurityContextHolder to contain null Authentication");
|
||||||
}
|
}
|
||||||
|
|
||||||
request.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY,
|
request.getSession()
|
||||||
|
.setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY,
|
||||||
failed);
|
failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private X509Certificate extractClientCertificate(HttpServletRequest request) {
|
|
||||||
X509Certificate[] certs = (X509Certificate[]) request.getAttribute(
|
|
||||||
"javax.servlet.request.X509Certificate");
|
|
||||||
|
|
||||||
if ((certs != null) && (certs.length > 0)) {
|
|
||||||
return certs[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("No client certificate found in request.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,8 +18,11 @@ package org.acegisecurity.concurrent;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.acegisecurity.Authentication;
|
import org.acegisecurity.Authentication;
|
||||||
|
|
||||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
|
||||||
import org.acegisecurity.ui.WebAuthenticationDetails;
|
import org.acegisecurity.ui.WebAuthenticationDetails;
|
||||||
|
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpSession;
|
import org.springframework.mock.web.MockHttpSession;
|
||||||
|
|
||||||
|
@ -33,6 +36,23 @@ import org.springframework.mock.web.MockHttpSession;
|
||||||
public class ConcurrentSessionControllerImplTests extends TestCase {
|
public class ConcurrentSessionControllerImplTests extends TestCase {
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
private Authentication createAuthentication(String user, String password) {
|
||||||
|
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user,
|
||||||
|
password);
|
||||||
|
auth.setDetails(createWebDetails(auth));
|
||||||
|
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WebAuthenticationDetails createWebDetails(Authentication auth) {
|
||||||
|
MockHttpSession session = new MockHttpSession();
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setSession(session);
|
||||||
|
request.setUserPrincipal(auth);
|
||||||
|
|
||||||
|
return new WebAuthenticationDetails(request);
|
||||||
|
}
|
||||||
|
|
||||||
public void testLifecycle() throws Exception {
|
public void testLifecycle() throws Exception {
|
||||||
// Build a test fixture
|
// Build a test fixture
|
||||||
ConcurrentSessionControllerImpl sc = new ConcurrentSessionControllerImpl();
|
ConcurrentSessionControllerImpl sc = new ConcurrentSessionControllerImpl();
|
||||||
|
@ -103,21 +123,4 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
|
||||||
assertTrue(true);
|
assertTrue(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Authentication createAuthentication(String user, String password) {
|
|
||||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user,
|
|
||||||
password);
|
|
||||||
auth.setDetails(createWebDetails(auth));
|
|
||||||
|
|
||||||
return auth;
|
|
||||||
}
|
|
||||||
|
|
||||||
private WebAuthenticationDetails createWebDetails(Authentication auth) {
|
|
||||||
MockHttpSession session = new MockHttpSession();
|
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
|
||||||
request.setSession(session);
|
|
||||||
request.setUserPrincipal(auth);
|
|
||||||
|
|
||||||
return new WebAuthenticationDetails(request, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue