Monday, 10 July 2017

Spring MVC Java Config : Part 4 Spring Security for Web Application

There are two main areas for application securities :    Authentication: Process of checking the user, who they claim to be.    
Authorization: Process of deciding whether an user is allowed to perform an activity within the application.



Spring security supports more then 20 Models for authentication :     
X.509 client certificate exchange     
LDAP Authentication     
OpenID authentication     
Java Open Source Single Sign On
......



1. TOOLS AND ENV

IDE : Spring Tool Suite 3.7.3 JDK : 
1.8 Tomcat : 8.0.18 
Spring : 4.2.6.RELEASE




2. POM.XML

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.junjun.spring.tutorials</groupId>
<artifactId>spring-mvc-web-security</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
<org.springframework.version>4.2.6.RELEASE</org.springframework.version>
<org.spring.security.version>4.1.0.RELEASE</org.spring.security.version>
<slf4j.version>1.7.10</slf4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- Spring JAXB support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- Spring Security Web -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${org.spring.security.version}</version>
</dependency>
<!-- Spring Security Config -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${org.spring.security.version}</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.2.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
</plugins>
</build>
</project>
view raw pom.xml hosted with ❤ by GitHub

spring-security-web and spring-security-config added



3. SECURITY CONFIG

package org.junjun.spring.tutorials.config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityWebAppInitializer extends AbstractSecurityWebApplicationInitializer {
}

package org.junjun.spring.tutorials.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("springUserDetailService")
UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
// set below if your password is encoded
// authenticationProvider.setPasswordEncoder(passwordEncoder);
return authenticationProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/todo/**").access("hasRole('ROLE_WEB')");
http.formLogin().loginPage("/login");
// to custom parameter name :
// http.formLogin().usernameParameter("user_name");
http.logout().logoutUrl("/logout");
}
}

package org.junjun.spring.tutorials.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class, SecurityConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
}


1. SecurityWebAppInitializer equals below line in web.xml
<filter>
     <filter-name>springSecurityFilterChain</filter-name>
     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
     <filter-name>springSecurityFilterChain</filter-name>
     <url-pattern>/*</url-pattern>
</filter-mapping>
2. SecurityConfig contains all the security related configurations
3. ServletInitializer to add SecurityConfig to root configuration



 4. USER DETAILS SERVICE

package org.junjun.spring.tutorials.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service("springUserDetailService")
public class UserDetailsServiceImpl implements UserDetailsService {
private Map<String, String> users = new HashMap<>();
public UserDetailsServiceImpl() {
users.put("springuser", "springpassword");
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = null;
if (users.keySet().contains(username)) {
user = new User(username, users.get(username), getGrantedAuthorities(username));
} else {
throw new UsernameNotFoundException("username [" + username + "] not found");
}
return user;
}
private List<GrantedAuthority> getGrantedAuthorities(String username) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
// here ROLE_USER is hard coded , but system can load user role from DB
// by user name and add to the list
authorities.add(new SimpleGrantedAuthority("ROLE_WEB"));
return authorities;
}
}


DaoAuthenticationProvider would use user details service to load user account and match with given password.




5. AUTHORIZATION CONTROLLER

package com.cn.junjun.spring.sample.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class AuthController {
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String displayLoginPage() {
return "login";
}
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login() {
return "forward:/rest/todo/list";
}
@RequestMapping(value = "/logout", method = RequestMethod.POST)
public String logout() {
return "/login";
}
}


logout must be POST then it would be registered to spring security to clear authorization context.





6. JSP AND JAVASCRIPT

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ 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 lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="spring">
<meta name="keywords" content="spring">
<meta name="_csrf" content="${_csrf.token}" />
<meta name="_csrf_header" content="${_csrf.headerName}" />
<title></title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body>
<header class="navbar navbar-default navbar-fixed-top bs-docs-nav"
role="banner">
<div class="container">
<nav class="collapse navbar-collapse bs-navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><a id="link-logout" href="javascript:;"> Logout </a></li>
</ul>
</nav>
</div>
</header>
<div class="container" style="padding-top: 10%">
<div class="row">
<form:form id="form-todo" class="form-horizontal"
modelAttribute="newToDo" action="">
<input name="${_csrf.parameterName}" type="hidden"
value="${_csrf.token}">
<div class="form-group">
<div class="col-md-offset-2 col-md-6">
<form:input id="todoContent" class="form-control" path="content"
placeholder="" />
</div>
<div class="col-md-2">
<button id="rest-create-btn" class="btn btn-success btn-block">Create</button>
</div>
<label for="todoContent" class="col-md-4 control-label"
style="text-align: left;"><spring:bind path="content">
<c:if test="${status.error}">
<form:errors path="content" class="text-danger" />
</c:if>
</spring:bind></label>
</div>
</form:form>
</div>
<div class="row">
<div class="col-md-offset-2 col-md-10">
<ul id="ul-todo-list">
<c:forEach items="${toDoList}" var="toDo">
<li>${toDo.createdDateDisplay}&nbsp;:&nbsp;${toDo.content}</li>
</c:forEach>
</ul>
</div>
</div>
<input type="hidden" id="rest-url-create"
value="${pageContext.request.contextPath}/api/todo/create" />
</div>
<form id="form-logout"
action="${pageContext.request.contextPath}/logout" method="post">
<input name="${_csrf.parameterName}" type="hidden"
value="${_csrf.token}">
</form>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="${pageContext.request.contextPath}/js/todo/rest/list.js"></script>
</body>
</html>
view raw list.jsp hosted with ❤ by GitHub

(function() {
$(document).ready(function() {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || "");
} else {
o[this.name] = this.value || "";
}
});
return o;
};
$(document).on("#form-todo").submit(function(event) {
event.preventDefault();
return false;
});
$(document).on("click", "#link-logout", function(event) {
event.preventDefault()
$("#form-logout")[0].submit();
});
$(document).on("click", "#rest-create-btn", function() {
var form = $("#form-todo");
var url = $("#rest-url-create").val();
var data = JSON.stringify(form.serialize());
data = JSON.stringify(form.serializeObject());
$.ajax({
type : "POST",
url : url,
data : data,
contentType: "application/json; charset=utf-8",
dataType: "json",
success : function(response) {
var output="<li>" + response.date + " : " +response.content + "</li>";
$("#ul-todo-list").append(output);
$("#todoContent").val("");
}
});
});
});
})();
view raw list.js hosted with ❤ by GitHub

CSRF token is per session.








7. RUN THE APPLICATION

DEBUG: org.springframework.security.web.FilterChainProxy - / at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No HttpSession currently exists
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /' doesn't match 'POST /logout
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /' doesn't match 'POST /login
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: 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'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/todo/**'
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Public object - authentication not attempted
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'delegatingApplicationListener'
DEBUG: org.springframework.security.web.FilterChainProxy - / reached end of additional filter chain; proceeding with original chain
DEBUG: org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'dispatcher' processing GET request for [/04-spring-mvc-web-security/]
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public java.lang.String org.junjun.spring.tutorials.web.controller.HomeController.loadHomePage()]
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'homeController'
DEBUG: org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/04-spring-mvc-web-security/] is: -1
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'redirect:/todo/list'
DEBUG: org.springframework.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.RedirectView: name 'redirect:/todo/list'; URL [/todo/list]] in DispatcherServlet with name 'dispatcher'
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'requestDataValueProcessor'
DEBUG: org.springframework.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@67c9cf6f
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG: org.springframework.web.servlet.DispatcherServlet - Successfully completed request
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'delegatingApplicationListener'
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No HttpSession currently exists
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /todo/list' doesn't match 'POST /logout
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /todo/list' doesn't match 'POST /login
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: 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'
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /todo/list at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/todo/list'; against '/todo/**'
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /todo/list; Attributes: [hasRole('ROLE_WEB')]
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: 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
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@7a5dbcff, returned: -1
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'delegatingApplicationListener'
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - 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:84)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:112)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:206)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:106)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
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.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.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
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)
DEBUG: org.springframework.security.web.util.matcher.AndRequestMatcher - Trying to match using Ant [pattern='/**', GET]
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request '/todo/list' matched by universal pattern '/**'
DEBUG: org.springframework.security.web.util.matcher.AndRequestMatcher - Trying to match using NegatedRequestMatcher [requestMatcher=Ant [pattern='/**/favicon.ico']]
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/todo/list'; against '/**/favicon.ico'
DEBUG: org.springframework.security.web.util.matcher.NegatedRequestMatcher - matches = true
DEBUG: org.springframework.security.web.util.matcher.AndRequestMatcher - Trying to match using NegatedRequestMatcher [requestMatcher=MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.HeaderContentNegotiationStrategy@1d6ca2f, matchingMediaTypes=[application/json], useEquals=false, ignoredMediaTypes=[*/*]]]
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - httpRequestMediaTypes=[text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8]
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - Processing text/html
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - application/json .isCompatibleWith text/html = false
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - Processing application/xhtml+xml
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - application/json .isCompatibleWith application/xhtml+xml = false
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - Processing application/xml;q=0.9
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - application/json .isCompatibleWith application/xml;q=0.9 = false
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - Processing */*;q=0.8
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - Ignoring
DEBUG: org.springframework.security.web.util.matcher.MediaTypeRequestMatcher - Did not match any media types
DEBUG: org.springframework.security.web.util.matcher.NegatedRequestMatcher - matches = true
DEBUG: org.springframework.security.web.util.matcher.AndRequestMatcher - Trying to match using NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]]
DEBUG: org.springframework.security.web.util.matcher.NegatedRequestMatcher - matches = true
DEBUG: org.springframework.security.web.util.matcher.AndRequestMatcher - All requestMatchers returned true
DEBUG: org.springframework.security.web.savedrequest.HttpSessionRequestCache - DefaultSavedRequest added to Session: DefaultSavedRequest[http://localhost:8080/04-spring-mvc-web-security/todo/list]
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Calling Authentication entry point.
DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to 'http://localhost:8080/04-spring-mvc-web-security/login'
DEBUG: org.springframework.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@67c9cf6f
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@2ae61e6. A new one will be created.
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /login' doesn't match 'POST /logout
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /login' doesn't match 'POST /login
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG: org.springframework.security.web.savedrequest.DefaultSavedRequest - pathInfo: both null (property equals)
DEBUG: org.springframework.security.web.savedrequest.DefaultSavedRequest - queryString: both null (property equals)
DEBUG: org.springframework.security.web.savedrequest.DefaultSavedRequest - requestURI: arg1=/04-spring-mvc-web-security/todo/list; arg2=/04-spring-mvc-web-security/login (property not equals)
DEBUG: org.springframework.security.web.savedrequest.HttpSessionRequestCache - saved request doesn't match
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9056f12c: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@380f4: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 9A7277AD4A11B571CDE48B9AC371F279; Granted Authorities: ROLE_ANONYMOUS'
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /login at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/todo/**'
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Public object - authentication not attempted
DEBUG: org.springframework.security.web.FilterChainProxy - /login reached end of additional filter chain; proceeding with original chain
DEBUG: org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'dispatcher' processing GET request for [/04-spring-mvc-web-security/login]
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /login
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public java.lang.String org.junjun.spring.tutorials.web.controller.AuthController.displayLoginPage()]
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'authController'
DEBUG: org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/04-spring-mvc-web-security/login] is: -1
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'login'
DEBUG: org.springframework.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.JstlView: name 'login'; URL [/WEB-INF/jsp/login.jsp]] in DispatcherServlet with name 'dispatcher'
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'requestDataValueProcessor'
DEBUG: org.springframework.web.servlet.view.JstlView - Forwarding to resource [/WEB-INF/jsp/login.jsp] in InternalResourceView 'login'
DEBUG: org.springframework.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@67c9cf6f
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG: org.springframework.web.servlet.DispatcherServlet - Successfully completed request
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
view raw console log hosted with ❤ by GitHub
Based on the log , when http://localhost:8080/04-spring-mvc-web-security/ is requested , no user has proper role detected , so system route user to http://localhost:8080/04-spring-mvc-web-security/login as configured in "SecurityConfig" class.







8. LOGIN SUCCESS





9. SOURCE CODE

https://github.com/junjun-dachi/spring-tutorials/tree/master/04-spring-mvc-web-security





Reference :

1. http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html
2. https://spring.io/blog/2013/07/04/spring-security-java-config-preview-method-security/
3. https://spring.io/blog/2013/07/03/spring-security-java-config-preview-web-security/
4. http://stackoverflow.com/questions/25276152/spring-security-java-config-custom-authenticationprovider-and-userdetailsservi
5. http://stackoverflow.com/questions/22453550/custom-authentication-provider-not-being-called







No comments:

Post a Comment

Flag Counter