简体   繁体   English

Spring Security 3.1:如何在另一个入口点获得安全性

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM