Showing posts with label Spring Security. Show all posts
Showing posts with label Spring Security. Show all posts

Points To Remember

You need to change the UserDetailsService, User Object of the spring security to achieve this.

Add Custom User Details to Spring Security Authentication Object

First of all we nee to create a new User Object that will override the User class of the spring security in package org.springframework.security.core.userdetails.User After this, you need to tell  UserDetailsService to use this object as the principal for the authentication token. For this you will have to override the UserDetailsService of the spring security.

You can have the custom User object like.
Custom User Class -> MyUser.groovy
package com.ekiras

import org.springframework.security.core.GrantedAuthority

/**
* Created by ekansh on 24/1/15.
*/
class MyUser extends org.springframework.security.core.userdetails.User {

// Declare all custom attributes here
private final Object id;
private String name;

public MyUser(String username, String password, boolean enabled, boolean accountNonExpired,
boolean credentialsNonExpired, boolean accountNonLocked,
Collection<GrantedAuthority> authorities, Object id, String name) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired,
accountNonLocked, authorities);

// Initialize all the custom attributes here like the following.
this.id = id;
this.name = name;
}

/**
* Get the id.
* @return the id
*/
public Object getId() {
return id;
}
}

So now our User object will also contain a field name that is the concatenation of first name and last name.
Custom UserDertailService -> MyUserDetailsService.groovy
package com.ekiras

import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.userdetails.NoStackUsernameNotFoundException
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException

/**
* Created by ekansh on 23/1/15.
*/
class MyUserDetailsService implements UserDetailsService {

static final GrantedAuthority NO_ROLE = new SimpleGrantedAuthority(SpringSecurityUtils.NO_ROLE)

@Override
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

User user = User.findByUsername(username)
if(!user)
throw new NoStackUsernameNotFoundException();

Collection<GrantedAuthority> authorities;

user.authorities.each {authority->
authorities.collect(new SimpleGrantedAuthority(authority))
}

authorities = authorities ?: [NO_ROLE]

// Return the Custom User object
return new MyUser(username, user.password, user.enabled, !user.accountExpired, !user.passwordExpired,!user.accountLocked, authorities, user.id, user.firstName+ user.lastName);
}
}

So now we have a custom UserDetailsService that will load our MyUser  object in spring security authentication principal, instead of conventional GromUser object. You need to do one last thing to make things work. You need to override the UserDetailsService and tell spring security to use your custom UserDetailsService and you can do it like the following.
Add this in resources.groovy
userDetailsService(MyUserDetailsService)

Thats it, now you have can add any number of custom attributes of the User object to spring security authentication.

Points To Remember

You may need to create an AuthenticatioFilter when you want to create a custom logic for handling the authentication filter. You may also want to create your own Authentication Provider, Entry Point, Authentication Token etc to customize the authentication process to a new level.

Step 1 : Create a Filter

Let us first create a class named MyAuthenticationFilter and then register it as a bean in resources.groovy. After we have created the class and registered the it as a bean, we can use this class as a filter for our custom spring security authentication.

Class : MyAuthenticationFilter.groovy
package com.ekiras

import org.springframework.context.ApplicationEventPublisher
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent
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.AbstractAuthenticationProcessingFilter
import org.springframework.security.web.authentication.AuthenticationFailureHandler
import org.springframework.security.web.authentication.AuthenticationSuccessHandler

import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

/**
* Created by ekansh on 19/1/15.
*/
class MyAuthenticationFilter extends AbstractAuthenticationProcessingFilter{

public static final String USERNAME = 'j_username';
public static final String PASSWORD = 'j_password';


AuthenticationSuccessHandler authenticationSuccessHandler
AuthenticationFailureHandler authenticationFailureHandler
ApplicationEventPublisher applicationEventPublisher



protected MyAuthenticationFilter() {
super('/mylogin') // Register the url that will be intercepted by this filter.
}

@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req
HttpServletResponse response = (HttpServletResponse) resp
  //Check if the url contains the filterProcessUrl and required authentication is false, if not then pass the request to the next filter.
if (!request.getRequestURI().contains(filterProcessesUrl) && !requiresAuthentication(request, response)) {
chain.doFilter(request, response)
return
}

// Create an authentication token that will be returned.
Authentication authentication;
try{ // If the credentials to not match then an AuthenticationException is thrown.
authentication = attemptAuthentication(request, response)
// If successfully authenticated then pass the request to the success handler
if(authentication.authenticated)
successfulAuthentication(request,response,authentication)
}
catch(AuthenticationException exception){
// Pass the request to authentication failure handler.
unsuccessfulAuthentication(request,response,exception)
return
}
}

@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
return true;
}


@Override
Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {

String username = getUsername(httpServletRequest);
String password = getPassword(httpServletRequest);

Authentication authentication = new UsernamePasswordAuthenticationToken(username, password);

return this.authenticationManager.authenticate(authentication);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException{
SecurityContextHolder.getContext().setAuthentication(authentication)
applicationEventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authentication, this.class))
authenticationSuccessHandler.onAuthenticationSuccess(request,response,authentication)
}

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException{
authenticationFailureHandler.onAuthenticationFailure(request,response, exception)
}

// Get the username from the request object
String getUsername(HttpServletRequest request){
return request.getParameter(USERNAME);
}

// get the password from the request object
String getPassword(HttpServletRequest request){
return request.getParameter(PASSWORD);
}
}

Now we register the class as a spring bean in resources.groovy like this.
    myAuthenticationFilter(MyAuthenticationFilter){
authenticationManager = ref('authenticationManager')
sessionAuthenticationStrategy = ref('sessionAuthenticationStrategy')
authenticationSuccessHandler = ref('authenticationSuccessHandler')
authenticationFailureHandler = ref('authenticationFailureHandler')
rememberMeServices = ref('rememberMeServices')
authenticationDetailsSource = ref('authenticationDetailsSource')
filterProcessesUrl = '/mylogin'
}

Now you need to register this filter in the deployment descriptor so that the these effects take place. There are two ways of doing this

  1. You can declare your filter using a filter chain in Config.groovy. See the documentation how to do this.
  2.  You can declare the filter in bootsrap as following
    SpringSecurityUtils.clientRegisterFilter('myAuthenticationFilter', SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order + 10)

Points To Remember

Go to the Grails Spring Security Plugin and add the dependency in the BuildConfig.

Integrate Spring Security in Grails

Add the latest grails spring security plugin in the build config of the project. This will add spring security jars and classes that will be used to configure spring security in the project.
http://grails.org/plugin/spring-security-core
Now run the following command from the terminal.
grails s2-quickstart com.ekiras User Role
Here the syntax of the above command is
grails s2-quickstart {package} {user domain} {authority domain}
The above command will create three Domains in the project User, Role and UserRole. user domain will contain the user info, role domain will contain Authorities and UserRole will contain the user authority mappings.
It will also add the following settings to the Config.groovy

// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.ekiras.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.ekiras.UserRole'
grails.plugin.springsecurity.authority.className = 'com.ekiras.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
'/': ['permitAll'],
'/index': ['permitAll'],
'/index.gsp': ['permitAll'],
'/assets/**': ['permitAll'],
'/**/js/**': ['permitAll'],
'/**/css/**': ['permitAll'],
'/**/images/**': ['permitAll'],
'/**/favicon.ico': ['permitAll']
]
It tells that the userDomain class authority class and user-authority join class. For other settings of the Spring security you can open the file DefaultSecurityConfig.groovy .

See the Default Password Encoders and Custom Password Encoders in Grails Spring Security.