Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpringSecurity - Custom automatic authentication

This is my scenario:

  • a web-app perform a sort-of SSO for many applications
  • logged-in user than click on a link and the app makes a post with user informations (name, pwd [useless], roles) toward the proper application
  • I am implementing SpringSecurity on one of these application to benefit from its power (authorities in session, methods provided by its classes, etc)

So, I need to develop a custom filter - I guess - that is able to retrieve user informations from request, retrieve from database, through a custom DetailsUserService, further information about the user (email, etc...) and then perform authentication of that user, according to the role retrieved from the request.

I was looking at Pre-Authentication filters, but I'm not sure that it is the right choice. It seems that those object are expected to be used when the principal is already in session, put by some previous authentication machanism (is it right?).

I think that, once identified the correct filter, I should need to perform within something like:

GrantedAuthority[] ga= new GrantedAuthority[1];
ga[0] = new GrantedAuthorityImpl(myUser.getRole());

SecurityContext sc = SecurityContextHolder.getContext();
Authentication a = new UsernamePasswordAuthenticationToken(userName, userPwd, ga);
a = authenticationManager.authenticate(a);
sc.setAuthentication(a);

Is it the proper direction to solve my problem? Do you have suggestions to help me find what's missing?

Thank you all,

Luca

ADDITION:

Hi Xearxess! Sorry to bother you again but it seems that the translation of your code according to SpringSecurity 2.0.4 is more difficult than I thought :S The problem is the XML... I tried different configuration but I ran always into namespace problems, missing attributes, etc...

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:security="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-2.0.xsd
              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">  

    <security:http>
        <security:intercept-url pattern="/**" access="isAuthenticated()" />
        <security:logout logout-url="/logout" logout-success-url="http://milan-ias-vs.usersad.everis.int/DMTest/" invalidate-session="true" />
        <security:custom-filter position="PRE_AUTH_FILTER" ref="preAuthenticatedProcessingFilter" />
    </security:http>

    <bean id="preAuthenticatedProcessingFilter" class="it.novartis.ram.authentication.PreAuthenticatedProcessingFilter">
        <custom-filter position="PRE_AUTH_FILTER"/>
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>

    <bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <property name="preAuthenticatedUserDetailsService">
            <bean class="it.novartis.ram.authentication.PreAuthenticatedUserDetailsService" />
        </property>
    </bean>

    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="preauthAuthProvider" />
    </security:authentication-manager>

</beans>

The 2 rows referencing CUSTOM-FILTER element are two different tries, both of them signed as error. How can I specify the position of my filter as a property?

Also the authentication provider reference on auth manager definition is marked as error. I think that I need to specify it like a property too, right?

Hope you can give me the last push ;) Thank you again,

Luca

like image 461
Dolfiz Avatar asked Sep 18 '12 14:09

Dolfiz


People also ask

How do I authenticate using Spring Security?

A common way to authenticate users is by requiring the user to enter a username and password. Once authentication is performed we know the identity and can perform authorization. Spring Security provides built in support for authenticating users.

What is difference between AuthenticationManager and Authenticationprovider?

The Authentication Manager is only a interface and actual implementation of the authenticate method is provided by the ProviderManager. The ProviderManager has a list of AuthenticationProviders. From it's authenticate method it calls the authenticate method of the appropriate AuthenticateProvider.

Is WebSecurityConfigurerAdapter deprecated?

From Spring Boot 2.7, WebSecurityConfigurerAdapter is deprecated.

What does formLogin () do in Spring Security?

Form-based login is one form of Username/password authentication that Spring Security provides support for. This is provided through an Html form. Whenever a user requests a protected resource, Spring Security checks for the authentication of the request.


2 Answers

For sake of completeness, in Spring Security 4 things are slightly changed. For example, the Java configuration is highly recommended. In this way, it's easier to integrate with Spring Boot.

It follows the Java Configuration that is equivalent to the XML configuration given in the above answers.

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(customAuthFilter(), AbstractPreAuthenticatedProcessingFilter.class)
            .authenticationProvider(preauthAuthProvider())
            .authorizeRequests()
            .anyRequest().authenticated();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(preauthAuthProvider());
    }

    @Bean
    public PreAuthenticatedAuthenticationProvider preauthAuthProvider() {
        PreAuthenticatedAuthenticationProvider preauthAuthProvider =
            new PreAuthenticatedAuthenticationProvider();
                preauthAuthProvider.setPreAuthenticatedUserDetailsService(
                    userDetailsServiceWrapper());
        return preauthAuthProvider;
    }

    @Bean
    public OnlyRolesPreAuthenticatedUserDetailsService userDetailsServiceWrapper() {
        OnlyRolesPreAuthenticatedUserDetailsService service =
            new MyPreAuthenticatedUserDetailsService();
        return service;
    }

    @Bean
    public MyPreAuthenticatedProcessingFilter customAuthFilter() throws Exception {
        MyPreAuthenticatedProcessingFilter filter = new MyPreAuthenticatedProcessingFilter();
        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }
}

I think that the above code is worth, because examples in internet are very basic and the Spring documentation lacks of such details.

like image 197
riccardo.cardin Avatar answered Sep 28 '22 19:09

riccardo.cardin


Yes, Pre-Authentication Scenarios are exactly what you are looking for.

It seems that those object are expected to be used when the principal is already in session, put by some previous authentication machanism (is it right?).

Not really, you can use Pre-Authentication to create PreAuthenticatedAuthenticationToken from request, as you want. Just do few things I described in another question.

First extend AbstractPreAuthenticatedProcessingFilter to obtain username and roles from request:

public class MyPreAuthenticatedProcessingFilter
    extends AbstractPreAuthenticatedProcessingFilter {

  public MyPreAuthenticatedProcessingFilter(
      AuthenticationManager authenticationManager) {
    setAuthenticationDetailsSource(new MyAuthenticationDetailsSource());
  }

  @Override
  protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
    return "Anonymous";
  }

  @Override
  protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
    return "N/A";
  }

  public static class MyAuthenticationDetailsSource implements 
      AuthenticationDetailsSource<HttpServletRequest, MySessionUserDetails> {
    // roles probably should be encrypted somehow
    static final String ROLES_PARAMETER = "pre_auth_roles";

    @Override
    public MySessionUserDetails buildDetails(HttpServletRequest req) {
      // create container for pre-auth data
      return new MySessionUserDetails(req.getParameter(ROLES_PARAMETER));
    }
  }
}

MySessionUserDetails class will split spring with roles to List of SimpleGrantedAuthority or any other GrantedAuthority implementation. Also, List is recommended and superior to GrantedAuthority[].

Second, implement AuthenticationUserDetailsService:

public class MyPreAuthenticatedUserDetailsService implements 
    AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {

  @Override
  public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token)
      throws UsernameNotFoundException {
    MySessionUserDetails sessionUserDetails =
        (MySessionUserDetails) token.getDetails();
    List<GrantedAuthority> authorities = sessionUserDetails.getAuthorities();
    return new User(token.getName(), "N/A", true, true, true, true, authorities);
  }
}

Then in your XML connect blocks together:

<security:http use-expressions="true">
  <security:intercept-url pattern="/**" access="isAuthenticated()" />
  <security:custom-filter position="PRE_AUTH_FILTER"
      ref="myPreAuthenticationFilter" />
</security:http>

<bean id="myPreAuthenticationFilter"
    class="com.example.MyPreAuthenticatedProcessingFilter">
  <property name="authenticationManager" ref="authenticationManager" />
</bean>

<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
  <property name="preAuthenticatedUserDetailsService">
    <bean class="com.example.MyPreAuthenticatedUserDetailsService" />
  </property>
</bean>

<security:authentication-manager alias="authenticationManager">
  <security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>

And voila! You should have authenticated User principal to use in your application.

Code I written here requires Spring Security 3.1 which I strongly recommend if you're about to using it (it does requrire Spring 3.0.7+). Also, Spring Security reference manual is your friend!

like image 27
Xaerxess Avatar answered Sep 28 '22 18:09

Xaerxess