具有CAS身份验证和自定义授权的Spring Security

时间:2012-11-05 21:28:46

标签: spring-security cas

我是Spring Security和CAS的新手。我让SSO部分工作,但我正在努力让授权部分工作。我按照这个来实现自定义授权

http://www.theserverside.com/tip/-Spring-Security-Customizing-Your-User-and-Authorization-in

什么时候应该调用loadUserDetails。我在这里设置了一个断点,这个方法永远不会被调用。

任何帮助将不胜感激。看起来我缺少一个调用授权的配置。

我想让我的自定义用户对象填充权限并驻留在会话中,以便我可以在任何阶段检查用户角色。

当我登录日志时,这是我登录后发生的步骤

    1. /indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas at position 1 of 8 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'  (FilterChainProxy:329)

No HttpSession currently exists  (HttpSessionSecurityContextRepository:127)

No SecurityContext was available from the HttpSession: null. A new one will be created.  (HttpSessionSecurityContextRepository:85)

2. /indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas at position 2 of 8 in additional filter chain; firing Filter: 'CasAuthenticationFilter'  (FilterChainProxy:329)

3. /indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas at position 3 of 8 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'  (FilterChainProxy:329)

4. /indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas at position 4 of 8 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'  (FilterChainProxy:329)

5. /indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas at position 5 of 8 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'  (FilterChainProxy:329)

Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6faa93c2: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffffe21a: RemoteIpAddress: 192.168.0.124; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'  (AnonymousAuthenticationFilter:102)

6. /indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas at position 6 of 8 in additional filter chain; firing Filter: 'SessionManagementFilter'  (FilterChainProxy:329)

7. /indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas at position 7 of 8 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'  (FilterChainProxy:329)

8. /indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas at position 8 of 8 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'  (FilterChainProxy:329)

Checking match of request : '/indexcasepackoptions'; against '/login/**'  (AntPathRequestMatcher:103)

Secure object: FilterInvocation: URL: /indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas; Attributes: [ROLE_ANONYMOUS]  (FilterSecurityInterceptor:193)

Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@6faa93c2: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffffe21a: RemoteIpAddress: 
192.168.0.124; SessionId: null; Granted Authorities: ROLE_ANONYMOUS  (FilterSecurityInterceptor:298)

Voter: org.springframework.security.access.vote.RoleVoter@7077602d, returned: 1  (AffirmativeBased:65)

Authorization successful  (FilterSecurityInterceptor:214)

RunAsManager did not change Authentication object  (FilterSecurityInterceptor:226)

/indexCasePackOptions?ticket=ST-4295-4eFUHVziBcmVaOd3bifl-cas reached end of additional filter chain; proceeding with original chain  (FilterChainProxy:315)

No Proxy Ticket found for   (ProxyGrantingTicketStorageImpl:77)

SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.  (HttpSessionSecurityContextRepository:269)

Chain processed normally  (ExceptionTranslationFilter:115)

SecurityContextHolder now cleared, as request processing completed  (SecurityContextPersistenceFilter:97)    

我的自定义UserDetails

package com.creata.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class User implements Serializable, UserDetails {

private static final long serialVersionUID = 1L;
private Collection<SimpleGrantedAuthority> authorities;
private final String username;
private String password;

public User(String username) {
    this.username=username;
}

@Override
public Collection<SimpleGrantedAuthority> getAuthorities() {
    return authorities;

}
public void setUserAuthorities(List<String> roles) {
    List<SimpleGrantedAuthority> listOfAuthorities = new ArrayList<SimpleGrantedAuthority>();
    for (String role : roles) {
        listOfAuthorities.add(new SimpleGrantedAuthority(role));
    }
    authorities = listOfAuthorities;
}

@Override
public String getPassword() {
    return this.password;
}

@Override
public String getUsername() {
    return username;
}

@Override
public boolean isAccountNonExpired() {
    return false;
}

@Override
public boolean isAccountNonLocked() {
    return false;
}

@Override
public boolean isCredentialsNonExpired() {
    return false;
}

@Override
public boolean isEnabled() {
    return true;
}

}

我的自定义UserService

package com.creata.security.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.creata.domain.User;

public class CustomUserService implements UserDetailsService, AuthenticationUserDetailsService {

@Override
public UserDetails loadUserByUsername(String username)
        throws UsernameNotFoundException {
    System.out.println("loadUserByUsername called here ");
    User currentUser = new User("Reena");
    //Collection<SimpleGrantedAuthority> authorities  = currentUser.getAuthorities();
    List<String> roles = new ArrayList<String>();
    roles.add("ROLE_Admin");
    roles.add("ROLE_CPAD-Maintenance");
    currentUser.setUserAuthorities(roles);
    //authorities.add(new SimpleGrantedAuthority("PRIVILEGE_HOME"));
    return currentUser;
}

@Override
public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException{
    User currentUser = new User("Reena");
    List<String> roles = new ArrayList<String>();
    roles.add("ROLE_Admin");
    roles.add("ROLE_CPAD-Maintenance");
    currentUser.setUserAuthorities(roles);
    //authorities.add(new SimpleGrantedAuthority("PRIVILEGE_HOME"));
    return currentUser;
}
}

这是我的安全配置:

<beans:beans 
xmlns="http://www.springframework.org/schema/security" 
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:tx="http://www.springframework.org/schema/tx" 
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-3.1.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<http entry-point-ref="casEntryPoint">   
    <custom-filter position="CAS_FILTER" ref="casFilter" />
</http>

<authentication-manager alias="authenticationManager">
    <authentication-provider ref="casAuthenticationProvider" />
</authentication-manager>   

<beans:bean id="casFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
    <beans:property name="authenticationManager" ref="authenticationManager"/>
</beans:bean>  

<beans:bean id="casEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
    <beans:property name="loginUrl" value="https://abc.com/cas/login"/>
    <beans:property name="serviceProperties" ref="serviceProperties"/>
</beans:bean>

<beans:bean id="casAuthenticationProvider"  class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
    <beans:property name="authenticationUserDetailsService" ref="customUserService"/>
    <beans:property name="serviceProperties" ref="serviceProperties" />
    <beans:property name="ticketValidator">
    <beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
        <beans:constructor-arg index="0" value="https://portal.creata.com/cas" />
    </beans:bean>
    </beans:property>
    <beans:property name="key" value="an_id_for_this_auth_provider_only"/>
</beans:bean>

<beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
    <beans:property name="service"  value="https://mypc.abc.com/Spring_CPAD2/"/>
</beans:bean>

<beans:bean id="customUserService" class="com.creata.security.service.CustomUserService"/>  
</beans:beans>      

这是我的web.xml

 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
metadata-complete="true">
<display-name />

 <context-param>
    <param-name>serverName</param-name>
    <param-value>https://cpaus-rsingh2.creata.com</param-value>
</context-param>
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>    
<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>    
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>    
<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
    <listener-class>
        org.springframework.web.context.request.RequestContextListener
    </listener-class>
</listener>
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener> 
<filter>
    <filter-name>CAS Single Sign Out Filter</filter-name>
    <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter>
    <filter-name>CAS Authentication Filter</filter-name>
    <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
    <init-param>
        <param-name>casServerLoginUrl</param-name>
        <param-value>https://abc.com/cas/login?AppName=app1</param-value>
    </init-param>
</filter>
<filter>
    <filter-name>CAS Validation Filter</filter-name>
    <filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
    <init-param>
        <param-name>casServerUrlPrefix</param-name>
        <param-value>https://abc.com/cas</param-value>
    </init-param>
</filter>
<filter>
    <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CAS Single Sign Out Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>CAS Authentication Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>CAS Validation Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
    <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<filter>
    <filter-name>ResponseOverrideFilter</filter-name>
    <filter-class>org.displaytag.filter.ResponseOverrideFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ResponseOverrideFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
<filter>
    <description>generated-persistence-filter</description>
    <filter-name>com_ibm_db2_jcc_DB2DriverFilter</filter-name>
    <filter-class>
        org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>com_ibm_db2_jcc_DB2Driver</param-value>
    </init-param>
</filter>
<filter>
    <description>generated-sitemesh-filter</description>
    <filter-name>Sitemesh Filter</filter-name>
    <filter-class>
        com.opensymphony.module.sitemesh.filter.PageFilter
    </filter-class>
</filter>
<!-- <filter>
    <description>generated-persistence-filter</description>
    <filter-name>MyEclipse_DerbyFilter</filter-name>
    <filter-class>
        org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>MyEclipse_Derby</param-value>
    </init-param>
</filter> -->
<filter-mapping>
    <filter-name>com_ibm_db2_jcc_DB2DriverFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>Sitemesh Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- <filter-mapping>
    <filter-name>MyEclipse_DerbyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping> -->
<servlet>
    <description>generated-servlet</description>
    <servlet-name>Spring_CPAD2 Servlet</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:Spring_CPAD2-web-context.xml
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet>
    <description>generated-resources-servlet</description>
    <servlet-name>Resource Servlet</servlet-name>
    <servlet-class>
        org.springframework.js.resource.ResourceServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet>
    <description>generated-webflow-servlet</description>
    <servlet-name>webflow</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/config/Spring_CPAD2-webflow-config.xml
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>  
<servlet-mapping>
    <servlet-name>Resource Servlet</servlet-name>
    <url-pattern>/resources/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Spring_CPAD2 Servlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>webflow</servlet-name>
    <url-pattern>*.flow</url-pattern> 
</servlet-mapping>
<welcome-file-list>
    <welcome-file>jsp/intro.jsp</welcome-file>
</welcome-file-list>
    <jsp-config>
        <taglib>
            <taglib-uri>MyCustomTags</taglib-uri>
            <taglib-location>/WEB-INF/tlds/MyCustomTags.tld</taglib-location>
        </taglib>
    </jsp-config>

1 个答案:

答案 0 :(得分:2)

仅当身份验证为空时,

CasAuthenticationProvider才会调用userDetailsS​​ervice

我建议在CasAuthenticationProvider.java中放一个调试点(参考下面代码中的注释)

 public class CasAuthenticationProvider {
 public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    CasAuthenticationToken result = null;

    if (stateless) {
        // Try to obtain from cache
        result = statelessTicketCache.getByTicketId(authentication.getCredentials().toString());
    }

    if (result == null) {
        //following line calls userDetailsService. I would recommend to put a debug point here 
        ///if it is not calling userDetailsService, that means result is not null

        result = this.authenticateNow(authentication);
        result.setDetails(authentication.getDetails());
    }

    if (stateless) {
        // Add to cache
        statelessTicketCache.putTicketInCache(result);
    }

    return result;
}

您可以从http://mvnrepository.com/artifact/org.springframework.security/spring-security-cas-client下载源代码并将其附加到eclipse。