How to create an in memory user in SAML

≯℡__Kan透↙ 提交于 2019-12-12 03:42:23

问题


Hi I am using spring boot 1.4.0+spring-security-saml2-core 1.0.2 with the help of following link Spring-Boot-Saml-example it is working great. Now i would like to create an in memory user with the same granted authorities that the SAML user is issued.Kindly find the below code of SAMLUserDetailsServiceImpl for reference.Your help should be appreciable.

@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);
}

As per the @blur0224 comment i put the following code in:

@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");
}

But it throws the following error....

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("/");
}

回答1:


In your SAMLUserDetailsServiceImpl you are currently not looking up the user in a DB to get any specific information about them. This being the case, you can setup your local security configuration to create in memory users with the same granted authority they have when they go through SAML. ROLE_USER You can use the example below as a guide for setting up a user that you can log in as for your local development.

Example of In Memory Users

Are you missing this?

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

You need two separate security configurations: WebSecurityConfig and LocalSecurityConfig When running locally you want the quickest, easiest way to replicate what your implementation of saml provides you with, which is a user with granted authorities. Note that you will need to have @Profile("dev","test","prod") on your SAML Configuration files 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");
    }
}   

You can't simply add users to the SAML configuration because the it has a different entry point. By creating a separate configuration, you have granular control of how you want the application to behave running locally only. Also, it is possible but not necessary to combine the two configurations into a single file. I would recommend getting them working separately first.




回答2:


You can use this library: spring-boot-security-saml

That besides highly simplifying the use of spring-security-saml and spring-boot it already has an in-memory SAMLUserDetails out of the box.

You could extend that class to return the granted authorities from whichever SAML attribute is returned by your IDP



来源:https://stackoverflow.com/questions/38592343/how-to-create-an-in-memory-user-in-saml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!