如何在SAML

时间:2016-07-26 14:15:35

标签: spring spring-security spring-boot saml spring-saml

您好我正在使用spring boot 1.4.0 + spring-security-saml2-core 1.0.2,并在以下链接Spring-Boot-Saml-example的帮助下运行良好。现在我想创建一个具有相同授权权限的内存用户,以便发出SAML用户。请查找以下SAMLUserDetailsS​​erviceImpl代码以供参考。您的帮助应该是值得注意的。

@Service
public class SAMLUserDetailsServiceImpl implements SAMLUserDetailsService {

// Logger
private static final Logger LOG = LoggerFactory.getLogger(SAMLUserDetailsServiceImpl.class);

@Value("${emailSamlAttrName}")
private String emailSamlAttrName;

public Object loadUserBySAML(SAMLCredential credential)
        throws UsernameNotFoundException {

    // The method is supposed to identify local account of user referenced by
    // data in the SAML assertion and return UserDetails object describing the user.

    String userID = credential.getNameID().getValue();
    Attribute emailAttribute = credential.getAttribute(emailSamlAttrName);
    String userEmail = getAttributeValue(credential.getAttribute(emailSamlAttrName).getAttributeValues().get(0));
    LOG.info(userID + " is logged in");
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
    authorities.add(authority);

    // In a real scenario, this implementation has to locate user in a arbitrary
    // dataStore based on information present in the SAMLCredential and
    // returns such a date in a form of application specific UserDetails object.
    return new User(userID, "<abc123>", true, true, true, true, authorities);
}

根据@ blur0224评论,我将以下代码放入:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
      auth.inMemoryAuthentication().withUser("sample").password("sample123").roles("NONE");
      auth.inMemoryAuthentication().withUser("dummy").password("dummy123").roles("USER");
      auth.inMemoryAuthentication().withUser("proxy").password("proxy123").roles("USER");
}

但它会引发以下错误......

11:09:41.345 [http-nio-8040-exec-1] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor [transactionId: ]- Secure object:   FilterInvocation: URL: /api/v1/users/authenticated; Attributes:    [hasRole('ROLE_NONE') or hasRole('ROLE_USER')]
11:09:41.345 [http-nio-8040-exec-1] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor [transactionId: ]- Previously Authenticated:   org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2b    c: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true;   Details:   org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
11:09:41.351 [http-nio-8040-exec-1] DEBUG o.s.s.access.vote.AffirmativeBased [transactionId: ]- Voter: org.springframework.security.web.access.expression.WebExpressionVoter@2809e0b9, returned: -1
11:09:41.352 [http-nio-8040-exec-1] DEBUG o.s.b.f.s.DefaultListableBeanFactory [transactionId: ]- Returning cached instance of singleton bean 'delegatingApplicationListener'
11:09:41.352 [http-nio-8040-exec-1] DEBUG o.s.b.f.s.DefaultListableBeanFactory [transactionId: ]- Returning cached instance of singleton bean 'authorizationAuditListener'
11:09:41.354 [http-nio-8040-exec-1] DEBUG o.s.b.f.s.DefaultListableBeanFactory [transactionId: ]- Returning cached instance of singleton bean 'delegatingApplicationListener'
11:09:41.354 [http-nio-8040-exec-1] DEBUG o.s.b.f.s.DefaultListableBeanFactory [transactionId: ]- Returning cached instance of singleton bean 'auditListener'
11:09:41.354 [http-nio-8040-exec-1] DEBUG o.s.b.a.audit.listener.AuditListener [transactionId: ]- AuditEvent [timestamp=Wed Jul 27 11:09:41 CEST 2016, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]
11:09:41.359 [http-nio-8040-exec-1] DEBUG o.s.s.w.a.ExceptionTranslationFilter [transactionId: ]- Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at  org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:123)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:207)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:103)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:676)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

WebSecurityConfig.java

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .httpBasic()
            .authenticationEntryPoint(samlEntryPoint());
    http
        .csrf()
            .disable();
    http
        .addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class)
        .addFilterAfter(samlFilter(), BasicAuthenticationFilter.class);
    http
        .authorizeRequests()
        .antMatchers("/error").permitAll()
        .antMatchers("/saml/**").permitAll()
        .antMatchers("/api/*/users/authenticated").access(String.format("hasRole('%s') or hasRole('%s')", ROLE_NONE, ROLE_USER))
        .antMatchers("/api/**").access(String.format("hasRole('%s')", ROLE_USER))
        .anyRequest().access(String.format("hasRole('%s')", ROLE_USER));
    http
        .logout()
            .logoutSuccessUrl("/");
}

2 个答案:

答案 0 :(得分:1)

SAMLUserDetailsServiceImpl中,您目前没有在数据库中查找用户以获取有关他们的任何具体信息。在这种情况下,您可以设置本地安全配置,以便在内存中创建具有相同授权权限的用户,这些用户在通过SAML时具有相同的授权。 ROLE_USER您可以使用以下示例作为设置用户的指南,您可以根据本地开发进行登录。

Example of In Memory Users

你错过了吗?

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/info/**").hasAnyRole("ADMIN","USER").
        and().formLogin();
    }

您需要两个单独的安全配置:WebSecurityConfigLocalSecurityConfig在本地运行时,您希望以最快,最简单的方式复制您的saml实现提供给您的内容,即具有授权权限的用户。请注意,您需要在SAML配置文件@Profile("dev","test","prod")

上设置WebSecurityConfig
@Configuration
@ComponentScan("com.whatever.etc")
@EnableWebSecurity
@Profile("local")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").hasAnyRole("ADMIN","USER").
        and().httpBasic();
    }
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
          auth.inMemoryAuthentication().withUser("ram").password("ram123").roles("ADMIN");
          auth.inMemoryAuthentication().withUser("ravan").password("ravan123").roles("USER");
          auth.inMemoryAuthentication().withUser("kans").password("kans123").roles("USER");
    }
}   

您无法简单地将用户添加到SAML配置中,因为它具有不同的入口点。通过创建单独的配置,您可以精确控制应用程序仅在本地运行的行为方式。此外,可以但不必将两种配置组合成单个文件。我建议先让它们分开工作。

答案 1 :(得分:0)

您可以使用此库:spring-boot-security-saml

除了高度简化spring-security-saml和spring-boot的使用之外,它已经开箱即用了内存中的SAMLUserDetails。

您可以扩展该类,以便从您的IDP返回的任何SAML属性返回授予的权限