[英]Spring Security 3.1: How To Get Security To Kick In At An Alternative Entry Point
I'm new to Spring. 我是春天的新手。 I've recently learned to use Spring 3.1 to implement LDAP authentication.
我最近学会了使用Spring 3.1来实现LDAP身份验证。 I was told to customize the authentication such that if a user from an IP address in the database comes to the site that s/he will be automatically logged in( not my idea, I was ordered to do it ).
我被告知要自定义身份验证,以便如果来自数据库中IP地址的用户访问该站点,他/她将自动登录(不是我的想法,我被命令这样做)。 If not, that person will be sent to a login screen to do LDAP authentication
如果没有,该人将被发送到登录屏幕进行LDAP身份验证
I made a skeleton of a custom PreAuthenticationFilter to check such users out, determine if they are from one of the annointed IP addresses and then send them to the rest of the authentication process. 我制作了一个自定义PreAuthenticationFilter的框架来检查这些用户,确定它们是否来自其中一个受控IP地址,然后将它们发送到其余的身份验证过程。
I'm brand spanking new to Spring. 我是Spring的新品牌。 So I cobbled this together from examples and reading over the reference many times.
所以我从例子中拼凑了这些,并多次阅读参考文献。
When I try running it I get an error message that seems to me I am not setting up my tags properly or that I am leaving a big piece out ( do I need a second, custom, AuthenticationEntry point?) 当我尝试运行它时,我收到一条错误消息,在我看来,我没有正确设置我的标签,或者我要留下一大块(我需要第二个,自定义,AuthenticationEntry点吗?)
Any tips in getting past this error would be appreciated: 任何通过此错误的提示将不胜感激:
the excerpt from my log 从我的日志中摘录
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'org.springframework.security.filterChains':
Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#0'
while setting bean property 'sourceList' with key [0];
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'org.springframework.security.web.DefaultSecurityFilterChain#0':
Cannot resolve reference to bean 'customFilter'
while setting constructor argument with key [2];
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'customFilter'
defined in ServletContext resource [/WEB-INF/acme-security.xml]:
Invocation of init method failed; nested exception is java.lang.IllegalArgumentException:
An AuthenticationManager must be set
My customized PreAuthenticatedFilter class for logging in by IP Address: 我定制的PreAuthenticatedFilter类用于通过IP地址登录:
package com.acme.controller.security;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.apache.log4j.Logger;
public class CustomIPAddressAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
private static final Logger logger = Logger.getLogger(CustomIPAddressAuthenticationFilter.class);
private AuthenticationDetailsSource ads = new WebAuthenticationDetailsSource();
private AuthenticationManager authenticationManager;
private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
boolean isAuthenticatedByIP = false;
// Get the IP address of the user tyring to use the site
String userIPAddress = request.getRemoteAddr();
logger.debug("userIPAddress == " + userIPAddress);
// Compare the user's IP Address with the IP address in the database
// stored in the USERS_AUTHENTICATED_BY_IP table & joined to the
// USERS tabe to make sure the IP Address has a current user
//isAuthenticatedByIP = someDataObject.hasIPAddress(userIPAddress);
isAuthenticatedByIP = true;
if(isAuthenticatedByIP){
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken("John.Principal","Password");
token.setDetails(ads.buildDetails(request));
try{
logger.debug("Going to set Authentication");
authentication = authenticationManager.authenticate(token);
// Setup the security context, aka authenticate
SecurityContextHolder.getContext().setAuthentication(authentication);
logger.debug("Authenticated");
}
catch(AuthenticationException e){
logger.debug("Authentication information was rejected by the authentication manager \n",e);
failureHandler.onAuthenticationFailure((HttpServletRequest)request, (HttpServletResponse)response, e);
}
}// end if(isAuthenticatedByIP)
}// end if(authenication == null)
chain.doFilter(request, response);
}// end function doFilter();
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
this.failureHandler = failureHandler;
}
protected String getPreAuthenticatedPrincipal(javax.servlet.http.HttpServletRequest request){
return "Joe.IP.User";
}
protected String getPreAuthenticatedCredentials(javax.servlet.http.HttpServletRequest request){
return "Password2";
}
}
My *-security.xml: 我的* -security.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:s="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<s:http auto-config="true" use-expressions="true">
<s:intercept-url pattern="/login*" access="hasRole('ROLE_ANONYMOUS')"/>
<s:intercept-url pattern="/search*" access="hasRole('ROLE_ANONYMOUS')"/>
<s:intercept-url pattern="/css/**" access="hasRole('ROLE_ANONYMOUS')"/>
<s:intercept-url pattern="/js/**" access="hasRole('ROLE_ANONYMOUS')"/>
<s:intercept-url pattern="/images/**" access="hasRole('ROLE_ANONYMOUS')"/>
<s:intercept-url pattern="/jsp/test*" access="hasRole('ROLE_ANONYMOUS')"/>
<s:intercept-url pattern="/**" access="isAuthenticated()" />
<s:custom-filter position="PRE_AUTH_FILTER" ref="customFilter" />
<s:form-login login-page="/login"
authentication-failure-url="/loginfailed" />
<s:logout logout-success-url="/logout" />
</s:http>
<bean id="customFilter" class="com.acme.controller.security.CustomIPAddressAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<s:ldap-server url = "ldap://ldap-itc.smen.acme.com:636/o=acme.com"/>
<s:authentication-manager alias="authenticationManager">
<s:ldap-authentication-provider user-dn-pattern="uid={0},ou=People"/>
</s:authentication-manager>
</beans>
My web.xml 我的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>Acme</display-name>
<!--welcome-file-list>
<welcome-file>/login</welcome-file>
</welcome-file-list-->
<servlet>
<servlet-name>acme</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>acme</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Help Find The Spring Config Files -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/nsd-servlet.xml,
/WEB-INF/nsd-security.xml
</param-value>
</context-param>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Integrate A Legacy Screen Done With A Servlet -->
<servlet>
<servlet-name>HelloWorldServlet</servlet-name>
<servlet-class>
com.legacy.HelloWorldServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldServlet</servlet-name>
<url-pattern>/helloworldservlet</url-pattern>
</servlet-mapping>
</web-app>
I believe some part of your security configuration is inconsistent in the way you use s:http
in several places in the configuration. 我相信您的安全配置的某些部分与您在配置中的多个位置使用
s:http
的方式不一致。 I suggest trying the following configuration: 我建议尝试以下配置:
<s:http auto-config="true" use-expressions="true">
<s:intercept-url pattern="/login*" access="isAnonymous()" />
<s:intercept-url pattern="/search*" access="isAnonymous()" />
<s:intercept-url pattern="/css/**" access="isAnonymous()" />
<s:intercept-url pattern="/js/**" access="isAnonymous()" />
<s:intercept-url pattern="/images/**" access="isAnonymous()" />
<s:intercept-url pattern="/**" access="isAuthenticated()" />
<s:form-login login-page="/login"
authentication-failure-url="/loginfailed" />
<s:logout logout-success-url="/logout" />
</s:http>
You need to activate the authentication process regardless of hitting /login
; 无论点击
/login
,您都需要激活身份验证过程; so I suggest using an implementation of a pre-authenticated filter AbstractPreAuthenticatedProcessingFilter
. 所以我建议使用预认证过滤器
AbstractPreAuthenticatedProcessingFilter
。 Your filter will do the authentication using IP address and populate the Authentication
object thus not redirecting to the login page anymore. 您的过滤器将使用IP地址进行
Authentication
并填充Authentication
对象,从而不再重定向到登录页面。 The filter should be configured in the position PRE_AUTH_FILTER
. 应将过滤器配置在
PRE_AUTH_FILTER
位置。 You can find a similar use case implementation for GAE here at Spring Source blog . 您可以在Spring Source博客上找到GAE的类似用例实现。
在您的实现中,您需要消除属性authenticationManager
,它由父类管理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.