How to do it...

Let us now implement another security model that uses a custom authentication process instead of the default:

  1. First, create a new security context definition, AppSecurityModelB, which presents the overriding of the http.formLogin().loginProcessingUrl() and the customization of the authentication manager and its providers:
@Configuration 
@EnableWebSecurity 
public class AppSecurityModelB extends  
    WebSecurityConfigurerAdapter{ 
   
  @Autowired 
  private AuthenticationProvider appAdminProvider; 
   
  @Autowired 
  private AuthenticationProvider appHRProvider; 
   
  @Autowired 
  private AuthenticationManager appAuthenticationMgr; 
     
  @Override 
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {  } 
 
   @Override 
   protected void configure(HttpSecurity http) throws Exception { 
          http 
            .authorizeRequests() 
            .antMatchers("/login_form**","/after**") 
            .permitAll() 
            .anyRequest().fullyAuthenticated() 
            .and() 
            .formLogin() 
            .loginPage("/login_form.html") 
            .loginProcessingUrl("/login_process") 
            .defaultSuccessUrl("/deptform.html") 
            .failureUrl("/login_form.html?error=true") 
            .and()  
            .logout().logoutUrl("/logout.html") 
            .logoutSuccessUrl("/after_logout_url.html"); 
             
          http.csrf().disable(); 
      } 
      
   @Override 
   public void configure(WebSecurity web) throws Exception { 
        // refer to sources 
   } 
       
   @Override 
  protected AuthenticationManager authenticationManager()    
     throws Exception { 
     return new ProviderManager(Arrays.asList( 
        appAdminProvider, appHRProvider ),  
      appAuthenticationMgr); 
  } 
}  

In the authenticationManager() method, observe the order of the injected custom providers inside the org.springframework.security.authentication.ProviderManager's constructor. The order of execution starts from the leftmost provider up to the parent authentication manager appAuthenticationMgr. Notice also that all the user credentials and roles are not configured using AuthenticationManagerBuilder anymore.

Be sure to save this class inside org.packt.secured.mvc.core.
  1. Implement the preceding two providers indicated, namely AppAdminProvider and AppHRProvider, and save them in org.packt.secured.mvc.core.manager. The first provider, AppAdminProvider, just checks if the user is admin with a password of "admin". If the credential is correct, it sets its ROLE_ADMIN and passes the authentication chain its Authentication details; otherwise, it throws BadCredentialsException:
@Component 
public class AppAdminProvider implements AuthenticationProvider { 
 
  @Override 
  public Authentication authenticate(Authentication  
      authentication) throws AuthenticationException { 
    String name = authentication.getName(); 
    String password =  
      authentication.getCredentials().toString(); 
    if (name.equalsIgnoreCase("admin") &&  
        password.equalsIgnoreCase("admin")) { 
       Set<SimpleGrantedAuthority> authorities =  
new HashSet<>(); 
       authorities.add(new  
          SimpleGrantedAuthority("ROLE_ADMIN")); 
          return new      
            UsernamePasswordAuthenticationToken(name,  
          password, authorities); 
    } else { 
      throw new BadCredentialsException("Invalid Admin  
         User"); 
    } 
  } 
 
  @Override 
  public boolean supports(Class<?> authentication) { 
       return authentication.equals( 
          UsernamePasswordAuthenticationToken.class); 
  } 
}
  1. The second, AppHRProvider, checks if the user is using the hradmin account, builds its user roles, and returns its Authentication details. The same BadCredentialsException is thrown if it is not the valid user:
@Component 
public class AppHRProvider implements AuthenticationProvider { 
 
  @Override 
  public Authentication authenticate(Authentication  
    authentication) throws AuthenticationException { 
 
    // refer to sources 
    if (name.equalsIgnoreCase("hradmin") &&  
      password.equalsIgnoreCase("hradmin")) { 
      Set<SimpleGrantedAuthority> authorities =  
             new HashSet<>(); 
      authorities.add( 
          new SimpleGrantedAuthority("ROLE_HR")); 
      return new UsernamePasswordAuthenticationToken(name,  
            password,authorities); 
    } else { 
      throw new BadCredentialsException("Invalid HR User"); 
    }   
  } 
 
  @Override 
  public boolean supports(Class<?> authentication) { 
    // refer to sources  
  } 
} 

If a diamond operator (<>) that is used to simplify the instantiation of generic classes does not work, configure Maven Compiler Plugin in pom.xml to contain:

<configuration> 
     <source>1.8</source> 
     <target>1.8</target> 
</configuration>

Or, add the following POM properties:

<properties> 
   <maven.compiler.source>1.8</maven.compiler.source> 
   <maven.compiler.target>1.8</maven.compiler.target> 
</properties>
  1. The security model will not be complete without the custom implementation of the parent provider, the AppAuthenticationManager. This authentication manager builds the whole user and their corresponding user account just as AuthenticationManagerBuilder did previously, with the in-memory user credentials:
@Component 
public class AppAuthenticationMgr  
   implements AuthenticationManager { 
   
  @Override 
  public Authentication authenticate(Authentication  
    authentication) throws AuthenticationException { 
 
    System.out.println(AppAuthenticationMgr.class); 
    String name = authentication.getName(); 
    String password =  
      authentication.getCredentials().toString(); 
     
    if (name.equalsIgnoreCase("sjctrags") &&  
      password.equalsIgnoreCase("sjctrags")) { 
      Set<SimpleGrantedAuthority> authorities =  
              new HashSet<>(); 
      authorities.add(new  
          SimpleGrantedAuthority("ROLE_USER")); 
      return new UsernamePasswordAuthenticationToken(name,  
        password, authorities); 
    } else if (name.equalsIgnoreCase("admin") &&  
        password.equalsIgnoreCase("admin")) { 
      Set<SimpleGrantedAuthority> authorities =  
        new HashSet<>(); 
      authorities.add(new  
        SimpleGrantedAuthority("ROLE_ADMIN")); 
      return new UsernamePasswordAuthenticationToken(name,  
        password, authorities); 
    } else if (name.equalsIgnoreCase("hradmin") &&  
        password.equalsIgnoreCase("hradmin")) { 
      Set<SimpleGrantedAuthority> authorities =  
        new HashSet<>(); 
      authorities.add(new      
        SimpleGrantedAuthority("ROLE_HR")); 
      return new UsernamePasswordAuthenticationToken(name,  
        password, authorities); 
    } else if(name.equalsIgnoreCase("guest")){ 
      Set<SimpleGrantedAuthority> authorities =  
        new HashSet<>(); 
      authorities.add(new  
          SimpleGrantedAuthority("ROLE_ANONYMOUS")); 
      return new AnonymousAuthenticationToken(name,  
          "ANONYMOUS", authorities); 
    } else{ 
      throw new BadCredentialsException("Not Valid User");   
    } 
  } 
} 
The custom AuthenticationManager includes guest as its anonymous user to be used, in the later recipes.
  1. Update the SpringConfigContext to accommodate this security model. Also add the package of the provider in its @ComponentScan annotation:
@Import(value = { AppSecurityModelB.class }) 
@Configuration 
@EnableWebMvc 
@ComponentScan(basePackages = {"org.packt.secured.mvc",  
    "org.packt.secured.mvc.core.manager" } 
public class SpringContextConfig {   } 
Comment on all the class-level annotations of the previous security model classes to avoid conflict or use @Order to establish a series of security model hierarchies.
  1. Create a separate login view (/login_form.html) that will highlight the overridden /login URL for login processing:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> 
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> 
<!DOCTYPE html> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html;  
charset=ISO-8859-1"> 
<title>Just Another Login Form</title> 
</head> 
<body> 
  <c:if test="${ not empty errorMsg }"> 
      <em><c:out value='${ errorMsg }'/></em><br/> 
  </c:if> 
   <form action="/ch04/login_process" method='POST'> 
    <table> 
      <tr> 
        <td>User:</td> 
        <td><input type='text' name='username' value=''> 
        </td> 
      </tr> 
      <tr> 
        <td>Password:</td> 
        <td><input type='password' name='password' /> 
        </td> 
      </tr> 
      <tr> 
        <td colspan='2'><input name="submit" type="submit" 
          value="submit" /> 
        </td> 
      </tr> 
      <tr> 
        <td colspan='2'><input name="reset" type="reset" /> 
        </td> 
      </tr> 
    </table> 
  </form> 
</body> 
</html> 
  1. Save this file inside src/main/webapp/login_process.
  2. Update the LoginController by implementing a GET request method for the /login_form.html view page:
@RequestMapping(value = {"/login_form.html"},  
   method = RequestMethod.GET) 
public String login_form(@RequestParam(name="error",  
   required=false) String error, Model model) { 
    try { 
      if (error.equalsIgnoreCase("true")) { 
        String errorMsg = "Login Error"; 
        model.addAttribute("errorMsg", errorMsg); 
      }else{ 
        model.addAttribute("errorMsg", error); 
      } 
    } catch (NullPointerException e) { 
      return "login_form_url"; 
    } 
    return "login_form_url"; 
} 
  1. Create a separate after-logout view page (srcmainwebapplogin_processafter_logout_form.html) to redirect the user to /login_form.html. Also, implement a typical @Controller of this new view page. Make the previous controllers as reference.
  2. Update views.properties and messages_en_US.properties for the new view.
  3. Save all files. clean, build, and deploy. Run https://localhost:8443/ch04/login_form.html to test the custom AuthenticationProvider and the overridden login-processing-url. Try logging in using all the user credentials indicated in the AuthenticationManagerBuilder and observe what happens.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.22.164