Friday, October 19, 2012

Enabling spring security in your spring application


Enabling spring security in your spring application

In your roo application you will have to run following command which will generate all the security related pages and needed configuration for you.

Roo> Security Setup

The above command will create everything needed for spring security , now go to your “applicationContext-security.xml” file under your project’s  resources/META-INF/spring  folder.
If you want Spring to show login screen whenever your user want’s to access any URL then include following interceptors  in your applicationContext-security.xml  file under http tage

    <http auto-config="true" use-expressions="true">
        <!--
   
            <form-login />
         -->
       
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" />
       
       

        <logout logout-url="/resources/j_spring_security_logout" />
        <!-- Configure these elements to secure URIs in your application -->
        <intercept-url pattern="/login**" access="permitAll" />
        <intercept-url pattern="/**" access="isAuthenticated()" />
    </http>
 
Note the  bold lines in above code , the first line will tell spring to allow access to /login URL only , while the second line will restrict all the other URLS in your application and will allow access only if the user is authenticated and has required roles.
Note that if you don’t want to have your own login page and want spring to handle security (login page based) then comment the below line
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" />
       
And uncomment below line
        <!--
   
            <form-login />
         -->

Try to run your spring application now and spring will still show you a login page and notice that you don’t need to create a login.jsp page in this case.


Customizing Spring Security
We can even customize the spring security to use our own class where we can put the code to authenticate the user against our database , please follow the steps mentioned below

Writing custom AuthenticationProvider
We will write a custom Authentication provider by extending a classcalled AbstractUserDetailsAuthenticationProvider, which works with username/password like authentication. The classes that extend AbstractUserDetailsAuthenticationProvider have to provide implementation for its two abstract methods:
·         additionalAuthenticationChecks and
·          retrieveUser.
The provider calls the retrieveUser method to authenticate user , this is where you can authenticate the user in your application against your own database , below is the class

package mypackage;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;

public class DrillingBestPracticesAuthenticationProvider extends
              AbstractUserDetailsAuthenticationProvider {

       @Override
       protected void additionalAuthenticationChecks(UserDetails arg0,
                     UsernamePasswordAuthenticationToken arg1)
                     throws AuthenticationException {
              // TODO Auto-generated method stub

       }

       @Override
       protected UserDetails retrieveUser(String username,
                     UsernamePasswordAuthenticationToken authentication)
                     throws AuthenticationException {
              String password = (String) authentication.getCredentials();
              if (!StringUtils.hasText(password))
              {
                     throw new BadCredentialsException("Please enter password");
             
              }
              List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
              try
              {
                    
                     //TODO here I should be trying to get the database connection using user name and password if connection successfully made then it means user is authenticated to use our system
                    
                    
              }
              catch (EmptyResultDataAccessException e)
              {
                     throw new BadCredentialsException("Invalid username or password");
                    
              } catch (EntityNotFoundException e) {
                     throw new BadCredentialsException("Invalid user");
                    
              } catch (NonUniqueResultException e) {
                     throw new BadCredentialsException("Non-unique user, contact administrator");
                    
              }
              return new User(username, password,
                           true, // enabled
                           true, // account not expired
                           true, // credentials not expired
                           true, // account not locked
                           authorities);       
       }

}

And you will have to add AuthenticationManager in your applicationContext-security.xml file as below


<beans:bean name="drillingBestPracticesAuthenticationProvider" class="mypackage.DrillingBestPracticesAuthenticationProvider">
    
    </beans:bean>
    <authentication-manager alias="authenticationManager">
    <authentication-provider ref="drillingBestPracticesAuthenticationProvider"></authentication-provider>
    </authentication-manager>    


Now once the user has been authenticated and User object being returned by the retrieveUser method , Spring will allow you to get user detail from anywhere in your application using any of the three approaches mentioned in the blogpost at following link
I am copy pasting the three methods mentioned in above blog
 three ways to get current logged in username in Spring Security

First Method
      Authentication auth = SecurityContextHolder.getContext().getAuthentication();
      String name = auth.getName(); //get logged in username
Second Method
     User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
      String name = user.getUsername(); //get logged in username
Third Method
  @RequestMapping(value="/login", method = RequestMethod.GET)
  public String printWelcome(ModelMap model, Principal principal ) {
 
      String name = principal.getName(); //get logged in username
      model.addAttribute("username", name);
      return "hello";
 
  }

2 comments:

  1. If you want to store user password in SecurityContext then you will have to define a property in the configuration of your custom AuthenticationManager Like below

    erase-credentials="false"







    and after successfull login you can get the user name password for a user as mentioned below


    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    //**Get Logedin User's user name
    String username = auth.getName(); //get logged in username
    //**Get Login User's password
    String password = (String)auth.getCredentials();
    UserCredentialsDataSourceAdapter userAdapter=new UserCredentialsDataSourceAdapter();
    userAdapter.setCredentialsForCurrentThread(username, password);

    ReplyDelete
  2. Basit bhai , spring secrity ko chorain , trip planing karain :)

    ReplyDelete