I've read all the questions related with this problem but no solution worked for me...
I have a simple upload form.
The controller, i't a controller i've used a lot of times (never for a file upload though).
#Controller
public class FileUploadController {
#Autowired
private HttpServletRequest request;
#RequestMapping(value={"/upload"}, method= RequestMethod.GET)
public String getUploadForm() {
return "/upload";
}
#RequestMapping(value={"/upload"}, method=RequestMethod.POST)
public #ResponseBody String uploadedFile(#RequestParam("uploadedFile") UploadedFile uploadedFile, BindingResult result, ModelMap model,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "/upload";
}
InputStream is = null;
OutputStream os = null;
MultipartFile file = uploadedFile.getFile();
String fileName = file.getOriginalFilename();
String imagepath = request.getSession().getServletContext().getRealPath("/resources/images");
try {
is = file.getInputStream();
File newFile = new File(imagepath+"/"+fileName);
if(!newFile.exists()){
newFile.createNewFile();
}
os = new FileOutputStream(newFile);
int read=0;
byte[] bytes = new byte[1024];
while((read = is.read(bytes)) != -1){
os.write(bytes, 0, read);
}
redirectAttributes.addFlashAttribute("css", "success");
redirectAttributes.addFlashAttribute("msg", "File "+fileName+ "aggiunto correttamente");
model.addAttribute("fileName", fileName);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "redirect:/floors";
}
}
Then I have the upload form, cleaned form all the css part:
<form:form method="POST" enctype="multipart/form-data" modelAttribute="uploadedFile">
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}" />
<form:errors path="*" cssClass="alert alert-danger alert-dismissible"
element="div" />
<label class="control-label col-sm-2">Carica
immagine</label>
<input type="file" name="file">
<form:errors path="file" class="control-label" />
<button id="singlebutton" name="singlebutton"
class="btn btn-primary" type="submit">Carica</button>
</div>
</form:form>
I don't know if it's useful, but this is UploadedFile.java, really simple
import org.springframework.web.multipart.MultipartFile;
public class UploadedFile{
MultipartFile file;
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
}
The form in HTML has:
<form id="uploadedFile" class="form-horizontal" action="/smartpark/upload" method="POST" enctype="multipart/form-data">
Where is the problem? I cannot even understand at which point che POST request goes wrong...
I'm adding the debug: Spring debug says:
2015-12-22 18:52:13 DEBUG FilterChainProxy:324 - /upload at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-12-22 18:52:13 DEBUG FilterChainProxy:324 - /upload at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-12-22 18:52:13 DEBUG HttpSessionSecurityContextRepository:192 - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#468e6d7e: Authentication: org.springframework.security.authentication.RememberMeAuthenticationToken#468e6d7e: Principal: org.springframework.security.core.userdetails.User#62dd304: Username: mario; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#7798: RemoteIpAddress: 192.168.3.38; SessionId: null; Granted Authorities: ROLE_ADMIN'
2015-12-22 18:52:13 DEBUG FilterChainProxy:324 - /upload at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-12-22 18:52:13 DEBUG HstsHeaderWriter:128 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#26ee04e5
2015-12-22 18:52:13 DEBUG FilterChainProxy:324 - /upload at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2015-12-22 18:52:13 DEBUG CsrfFilter:106 - Invalid CSRF token found for http://192.168.3.240:8080/smartpark/upload
2015-12-22 18:52:13 DEBUG DispatcherServlet:861 - DispatcherServlet with name 'dispatcher' processing POST request for [/smartpark/Access_Denied]
2015-12-22 18:52:13 DEBUG RequestMappingHandlerMapping:306 - Looking up handler method for path /Access_Denied
2015-12-22 18:52:13 DEBUG ExceptionHandlerExceptionResolver:133 - Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
2015-12-22 18:52:13 DEBUG ResponseStatusExceptionResolver:133 - Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
2015-12-22 18:52:13 DEBUG DefaultHandlerExceptionResolver:133 - Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
2015-12-22 18:52:13 WARN PageNotFound:208 - Request method 'POST' not supported
2015-12-22 18:52:13 DEBUG DispatcherServlet:1034 - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
2015-12-22 18:52:13 DEBUG DispatcherServlet:1000 - Successfully completed request
2015-12-22 18:52:13 DEBUG HttpSessionSecurityContextRepository$SaveToSessionResponseWrapper:211 - Skip invoking on
2015-12-22 18:52:13 DEBUG SecurityContextPersistenceFilter:105 - SecurityContextHolder now cleared, as request processing completed
Browser network logs don't say anything, just that the POST resource is not accomplished
Thanks
Things to Consider:
Check your request header and see if it's submitting to floors/upload. if not try to add action="floors/upload" property in your form tag.
Try to change your controller to (without the path)
#RequestMapping(value="upload", method=RequestMethod.POST)
I found the problem.
Following this link I saw that multipart file upload with spring and CSRF must be handled with care.
So I first disabled the CSRF to see if everything went well. After it, I added
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
to my SecurityWebApplicationInitializer.java so to not need the authentication to upload file on the server, but only to move them to their final destination.
Than I had to configure the filterMultipartResolver and everything went good.
Thank you all
Look into spring's PathVariables.
#RequestMapping(value = " /upload/{pathName}", method=RequestMethod.POST)
public String getOrder(#PathVariable String pathName){
// do what you need
}
IntelliJ suggested I use <form:form, which uses gave
<html xmlns:form="http://www.w3.org/1999/xhtml">
at the top of my .html file. I changed to just <form in my body and then my POST request worked.
Related
When I POST to /api/v1/auth/register, I get a 403 response generated by the configured accessDeniedHandler. However, I'm expecting this request to be permitted as it's covered by permitAll() and precedes anyRequest().authenticated().
Requests such as GET /api/v1/reference/countries work just fine. Also, my integration tests that hit these /api/v1/auth/** endpoints also work, which suggests something to do with CORS, although the preflight request is 200.
Any idea what's wrong with this security configuration?
#Configuration
#EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true
)
#Order(1)
#RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsServiceImpl userDetailsService;
private final Config config;
private final ObjectMapper objectMapper;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.authorizeRequests()
.antMatchers(
"/api/v1/auth/register",
"/api/v1/auth/register/check",
"/api/v1/auth/register/activate",
"/api/v1/auth/password/update",
"/api/v1/auth/recover",
"/api/v1/auth/recover/check",
"/api/v1/auth/recover/reset",
"/api/v1/csrf-token",
"/api/v1/reference/**"
)
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.successHandler((request, response, authentication) -> {
response.getWriter().append("OK");
response.setStatus(HttpServletResponse.SC_OK);
})
.failureHandler((request, response, exception) -> {
response.getWriter().append("Invalid credentials or inactive account");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
})
.loginProcessingUrl("/api/v1/auth/login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/api/v1/auth/logout", "POST"))
.permitAll()
.and()
.exceptionHandling()
.accessDeniedHandler((request, response, accessDeniedException) -> {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
objectMapper.writeValue(
response.getWriter(),
ErrorResponseBody
.builder()
.code(ErrorType.ACCESS_DENIED)
.status(HttpServletResponse.SC_FORBIDDEN)
.message("Access denied")
.build()
);
})
.authenticationEntryPoint((request, response, authException) -> {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
objectMapper.writeValue(
response.getWriter(),
ErrorResponseBody
.builder()
.code(ErrorType.LOGIN_REQUIRED)
.status(HttpServletResponse.SC_UNAUTHORIZED)
.message("You are not authorized to access this resource")
.build()
);
})
.and()
.userDetailsService(userDetailsService);
if (config.isCsrfDisabled()) {
http
.csrf()
.disable();
}
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final var configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedOrigins(config.getAllowedOrigins());
configuration.setAllowedMethods(asList("GET", "POST", "PUT", "PATCH", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList(HttpHeaders.AUTHORIZATION, HttpHeaders.CACHE_CONTROL, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT));
final var source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
}
}
Here's my CORS config:
#Configuration
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class WebConfig {
private final Config config;
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
final var allowedOrigins = Optional
.ofNullable(config.getAllowedOrigins())
.map(origins -> origins.toArray(new String[]{}))
.orElse(new String[]{});
System.out.println("Enabling CORS for the following origins:" + Arrays.asList(allowedOrigins).toString());
registry
.addMapping("/api/**")
.allowedOrigins(allowedOrigins)
.allowCredentials(true)
.allowedMethods("*")
.allowedHeaders("*");
}
};
}
}
I'm invoking these endpoints from http://localhost:3000, which is one of the items returned by config.getAllowedOrigins().
Here's the Spring Security debug logging from the request:
2020-11-24 06:51:16.110 INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-11-24 06:51:16.112 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-11-24 06:51:16.158 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 44 ms
2020-11-24 06:51:16.193 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-11-24 06:51:16.200 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-11-24 06:51:16.205 DEBUG 1 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-11-24 06:51:16.206 DEBUG 1 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-11-24 06:51:16.214 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-11-24 06:51:16.217 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 4 of 13 in additional filter chain; firing Filter: 'CorsFilter'
2020-11-24 06:51:16.286 DEBUG 1 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#461bbc94
2020-11-24 06:51:16.290 DEBUG 1 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-11-24 06:51:16.299 DEBUG 1 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-11-24 06:51:16.483 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-11-24 06:51:16.485 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-11-24 06:51:16.486 DEBUG 1 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-11-24 06:51:16.487 DEBUG 1 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-11-24 06:51:16.488 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-11-24 06:51:16.489 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 4 of 13 in additional filter chain; firing Filter: 'CorsFilter'
2020-11-24 06:51:16.494 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 5 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2020-11-24 06:51:16.525 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://dev.api.example.com/api/v1/auth/register
2020-11-24 06:51:16.609 DEBUG 1 --- [nio-8080-exec-2] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#461bbc94
2020-11-24 06:51:16.610 DEBUG 1 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-11-24 06:51:16.615 DEBUG 1 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
Disable CSRF using .csrf().disable() in configure(HttpSecurity http) More deatils are explained here
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
... // other configurations
}
I know that there are many topics with this problem because I've gone over all of them. But still I haven't found any solution.
Basically I have a ResourceHandler that maps a resource but doesn't find the css file while entering the jsp. I'm using Spring 4.3.9.RELEASE.
The project look like this
Web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
com.res.context.MvcConfig
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Configuration file looks like this:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.res"})
public class MvcConfig extends WebMvcConfigurerAdapter {
//I've already tried without this
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
super.configurePathMatch(configurer);
configurer.setUseRegisteredSuffixPatternMatch(false);
configurer.setUseSuffixPatternMatch(false);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// TODO Auto-generated method stub
configurer.enable();
}
#Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
The jsp file
I've already tried many values of href
//Those two give 404 error code
<link rel="stylesheet" href="resources/style.css" type="text/css">
<link rel="stylesheet" href="/resources/style.css" type="text/css">
//Those two give jsp fatal error with NullPointerException
<link rel="stylesheet" href='<c:uri>value="/resources/style.css"</c:uri> 'type="text/css">
<link rel="stylesheet" href='<c:uri>value="resources/style.css"</c:uri> 'type="text/css">
Controller
#Controller
#RequestMapping("/")
public class MyController {
private static final Logger logger = Logger.getLogger(MyController.class);
#RequestMapping("/site")
public ModelAndView site()
{
ModelAndView model = new ModelAndView("site");
model.addObject("txt", "Model");
return model;
}}
And finally most important part
logs
2017-07-18 20:56:35 DEBUG DispatcherServlet:869 - DispatcherServlet with name 'mvc-dispatcher' processing GET request for [/res/site.htm]
2017-07-18 20:56:35 DEBUG RequestMappingHandlerMapping:310 - Looking up handler method for path /site.htm
2017-07-18 20:56:35 DEBUG RequestMappingHandlerMapping:320 - Did not find handler method for [/site.htm]
2017-07-18 20:56:35 DEBUG RequestMappingHandlerMapping:310 - Looking up handler method for path /site.htm
2017-07-18 20:56:35 DEBUG RequestMappingHandlerMapping:317 - Returning handler method [public org.springframework.web.servlet.ModelAndView com.res.controller.MyController.site()]
2017-07-18 20:56:35 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'myController'
2017-07-18 20:56:35 DEBUG DispatcherServlet:955 - Last-Modified value for [/res/site.htm] is: -1
2017-07-18 20:56:35 DEBUG DefaultListableBeanFactory:1670 - Invoking afterPropertiesSet() on bean with name 'site'
2017-07-18 20:56:35 DEBUG DispatcherServlet:1280 - Rendering view [org.springframework.web.servlet.view.JstlView: name 'site'; URL [/WEB-INF/views/site.jsp]] in DispatcherServlet with name 'mvc-dispatcher'
2017-07-18 20:56:35 DEBUG JstlView:432 - Added model object 'txt' of type [java.lang.String] to request in view with name 'site'
2017-07-18 20:56:35 DEBUG JstlView:166 - Forwarding to resource [/WEB-INF/views/site.jsp] in InternalResourceView 'site'
2017-07-18 20:56:36 DEBUG DispatcherServlet:1000 - Successfully completed request
2017-07-18 20:56:36 DEBUG DispatcherServlet:869 - DispatcherServlet with name 'mvc-dispatcher' processing GET request for [/res/resources/style.css]
2017-07-18 20:56:36 DEBUG RequestMappingHandlerMapping:310 - Looking up handler method for path /resources/style.css
2017-07-18 20:56:36 DEBUG RequestMappingHandlerMapping:320 - Did not find handler method for [/resources/style.css]
2017-07-18 20:56:36 DEBUG RequestMappingHandlerMapping:310 - Looking up handler method for path /resources/style.css
2017-07-18 20:56:36 DEBUG RequestMappingHandlerMapping:320 - Did not find handler method for [/resources/style.css]
2017-07-18 20:56:36 DEBUG SimpleUrlHandlerMapping:192 - Matching patterns for request [/resources/style.css] are [/resources/**]
2017-07-18 20:56:36 DEBUG SimpleUrlHandlerMapping:226 - URI Template variables for request [/resources/style.css] are {}
2017-07-18 20:56:36 DEBUG SimpleUrlHandlerMapping:140 - Mapping [/resources/style.css] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[ServletContext resource [/resources/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver#4c531172]]] and 1 interceptor
2017-07-18 20:56:36 DEBUG DispatcherServlet:955 - Last-Modified value for [/res/resources/style.css] is: -1
2017-07-18 20:56:36 DEBUG DispatcherServlet:1048 - Null ModelAndView returned to DispatcherServlet with name 'mvc-dispatcher': assuming HandlerAdapter completed request handling
2017-07-18 20:56:36 DEBUG DispatcherServlet:1000 - Successfully completed request
I hope that someone knows what is wrong here because after few hours I can't think of anything more.
The problem is because you have the folder resources out of webapp and your servlet is looking at webapp as /.
First way:
Move your resources folder under webapp and then into your applicationContext.xml add the next line:
<mvc:resources mapping="/css/**" location="/resources/" />
then you can import your style.css file like this:
<link href="<c:url value="/resources/style.css" />" rel="stylesheet">
Second way:
you can create another Servlet for static content:
First add the next few lines in your web.xml
<servlet>
<servlet-name>resources</servlet-name>
<servlet-class>com.res.servlets.DefaultServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>resources</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
next step, create the package com.res.servlet the under that package create the class DefaultServlet like this:
public class DefaultServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
// Tomcat, Jetty, JBoss, and GlassFish
private static final String COMMON_DEFAULT_SERVLET_NAME = "default";
// Resin
private static final String RESIN_DEFAULT_SERVLET_NAME = "resin-file";
// WebLogic
private static final String WEBLOGIC_DEFAULT_SERVLET_NAME = "FileServlet";
// WebSphere
private static final String WEBSPHERE_DEFAULT_SERVLET_NAME = "SimpleFileServlet";
public String scanDefaultServlet(){
if(this.getServletContext().getNamedDispatcher(COMMON_DEFAULT_SERVLET_NAME) != null) {
return COMMON_DEFAULT_SERVLET_NAME;
} else if(this.getServletContext().getNamedDispatcher(RESIN_DEFAULT_SERVLET_NAME) != null) {
return RESIN_DEFAULT_SERVLET_NAME;
} else if(this.getServletContext().getNamedDispatcher(WEBLOGIC_DEFAULT_SERVLET_NAME) != null){
return WEBLOGIC_DEFAULT_SERVLET_NAME;
} else if(this.getServletContext().getNamedDispatcher(WEBSPHERE_DEFAULT_SERVLET_NAME) != null){
return WEBSPHERE_DEFAULT_SERVLET_NAME;
} else {
throw new IllegalStateException("Cannot determine what Server you currently use");
}
}
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
RequestDispatcher rd = getServletContext().getNamedDispatcher(this.scanDefaultServlet());
HttpServletRequest wrapped = new HttpServletRequestWrapper(req) {
public String getServletPath() {return "";}
};
rd.forward(wrapped, resp);
}
}
now you can call your resources like this:
<link rel="stylesheet" type="text/css" href="<c:url value="/resources/resources/style.css"/>">
Make sure you has imported the tag libs like this at the top of your view:
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Regards,
A Spring MVC controller needs to redirect the control flow of an app to a different url endpoint within the same app. But the current code is returning a blank page along with response headers that include the intended destination url as the forward header. When the contents of the forward header is pasted into the web browser, the intended endpoint is successfully called. What specific changes need to be made to the code below in order for the POST controller to successfully redirect the control flow to the intended destination endpoint instead of returning a blank page?
Here is the code for the Controller method:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.OK)
public ResponseEntity<?> auth(FormData formData, HttpServletRequest req, HttpServletResponse resp) {
System.out.println("11111111111111 inside POST");
HttpHeaders responseHeaders = new HttpHeaders();
boolean passedTheTest = true;//ACTUAL LOGIC IS OMITTED HERE FOR SIMPLICITY
if (passedTheTest) {
//SOME OFF TOPIC LOGIC HERE IS OMITTED
CsrfToken csrf = (CsrfToken) req.getAttribute(CsrfToken.class.getName());
String updateCsrf = csrf.getToken();
responseHeaders.set("XSRF-TOKEN", updateCsrf);
if(resp.getHeaders("Cache-Control")!=null){responseHeaders.put("Cache-Control" , new ArrayList<String>(resp.getHeaders("Cache-Control")));}
if(resp.getHeader("Content-Language")!=null){responseHeaders.set("Content-Language" , resp.getHeader("Content-Language"));}
if(resp.getHeader("Content-Length")!=null){responseHeaders.set("Content-Length" , resp.getHeader("Content-Length"));}
if(resp.getHeader("Date")!=null){responseHeaders.set("Date" , resp.getHeader("Date"));}
if(resp.getHeader("Expires")!=null){responseHeaders.set("Expires" , resp.getHeader("Expires"));}
if(resp.getHeader("Pragma")!=null){responseHeaders.set("Pragma" , resp.getHeader("Pragma"));}
if(resp.getHeader("Server")!=null){responseHeaders.set("Server" , resp.getHeader("Server"));}
if(resp.getHeader("X-Application-Context")!=null){responseHeaders.set("X-Application-Context" , resp.getHeader("X-Application-Context"));}
if(resp.getHeader("X-Frame-Options")!=null){responseHeaders.set("X-Frame-Options" , resp.getHeader("X-Frame-Options"));}
if(resp.getHeader("X-XSS-Protection")!=null){responseHeaders.set("X-XSS-Protection" , resp.getHeader("X-XSS-Protection"));}
if(resp.getHeader("x-content-type-options")!=null){responseHeaders.set("x-content-type-options" , resp.getHeader("x-content-type-options"));}
if(req.getSession().getAttribute("forwardTo")!=null){
String redirectTo = getValidUriFromAnotherFunction();
try {
URI location = new URI(redirectTo);
responseHeaders.setLocation(location);
} catch (URISyntaxException e) {e.printStackTrace();}
ResponseEntity<Void> forwardResponseEntity = new ResponseEntity<Void>(responseHeaders, HttpStatus.CREATED);
return forwardResponseEntity;
}
};
return new ResponseEntity<String>("aDifferentViewTemplateName", responseHeaders, HttpStatus.CREATED);
}
The request headers in the browser's developer tools are:
Host: localhost:7777
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:7777/path/to/controller_method
Cookie: JSESSIONID=911B34457B69F7729091DD97A160AD79; JSESSIONID=95AA730306330CF15E3776C495807354; XSRF-TOKEN=04ae2a0c-3c58-4e85-88bd-3818bb10402a
Connection: keep-alive
The response headers for the same POST are:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate, no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Sun, 29 May 2016 21:48:24 GMT
Expires: 0, 0
Location: http://localhost:7777/path/to/forward_destination?long_querystring
Pragma: no-cache, no-cache
Server: Apache-Coyote/1.1
X-Application-Context: application:7777, application:7777
X-Content-Type-Options: nosniff, nosniff
X-Frame-Options: DENY, DENY
X-XSS-Protection: 1; mode=block, 1; mode=block
XSRF-TOKEN: 04ae2a0c-3c58-4e85-88bd-3818bb10402a
The Spring Boot debug log for the same POST includes three sections, which have been separated as follows for improved readability:
Section of debug log that shows the SYSO inside the controller:
11111111111111 inside POST
redirectTo is: http://localhost:7777/path/to/forward_destination?long_querystring
Section of debug log AFTER the controller (most important?):
2016-05-29 14:48:24.489 DEBUG 5533 --- [io-7777-exec-10] o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
2016-05-29 14:48:24.489 DEBUG 5533 --- [io-7777-exec-10] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl#42259e42: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#42259e42: Principal: org.springframework.security.core.userdetails.User#40fecce: Username: SomeUser; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ONE,ROLE_TWO; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#fffe3f86: RemoteIpAddress: 127.0.0.1; SessionId: 02A95844E8A829868542290D471503F5; Granted Authorities: ROLE_ONE, ROLE_TWO, ROLE_THREE' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade#64307ead
2016-05-29 14:48:24.489 DEBUG 5533 --- [io-7777-exec-10] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
Instead of returning the 201 Created status code you should return a 3XX status code to ask the user agent to load a different web page. Otherwise the Location header has no "special" meaning.
So for example you can write:
ResponseEntity<Void> forwardResponseEntity = new ResponseEntity<Void>(responseHeaders, HttpStatus.MOVED_PERMANENTLY);
I have an API REST Controller on my Spring 4 application that returns JSON values but somehow, looking at the logs, the dispatcher redirect the request to '/'.
2016-04-01 11:30:35 DEBUG RequestResponseBodyMethodProcessor:221 - Written [{"type":"groupmatch"}] as "application/json;charset=UTF-8" using [org.springframework.http.converter.StringHttpMessageConverter#4617ede3]
2016-04-01 11:30:35 DEBUG DispatcherServlet:1034 - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
2016-04-01 11:30:35 DEBUG DispatcherServlet:1000 - Successfully completed request
2016-04-01 11:30:35 DEBUG ExceptionTranslationFilter:115 - Chain processed normally
2016-04-01 11:30:35 DEBUG SecurityContextPersistenceFilter:97 - SecurityContextHolder now cleared, as request processing completed
2016-04-01 11:30:35 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/'; against '/'
2016-04-01 11:30:35 DEBUG FilterChainProxy:180 - / has an empty filter list
2016-04-01 11:30:35 DEBUG DispatcherServlet:861 - DispatcherServlet with name 'dispatcher' processing GET request for [/]
2016-04-01 11:30:35 DEBUG RequestMappingHandlerMapping:319 - Looking up handler method for path /
2016-04-01 11:30:35 DEBUG RequestMappingHandlerMapping:326 - Returning handler method [public java.lang.String com.thebetcafe.controllers.HomeController.home(org.springframework.web.context.request.WebRequest)]
2016-04-01 11:30:35 DEBUG DefaultListableBeanFactory:248 - Returning cached instance of singleton bean 'homeController'
2016-04-01 11:30:35 DEBUG DispatcherServlet:947 - Last-Modified value for [/] is: -1
2016-04-01 11:30:35 DEBUG DispatcherServlet:1241 - Rendering view [org.springframework.web.servlet.view.JstlView: name 'static/home.html'; URL [static/home.html]] in DispatcherServlet with name 'dispatcher'
2016-04-01 11:30:35 DEBUG JstlView:166 - Forwarding to resource [static/home.html] in InternalResourceView 'static/home.html'
2016-04-01 11:30:35 DEBUG DispatcherServlet:861 - DispatcherServlet with name 'dispatcher' processing GET request for [/static/home.html]
2016-04-01 11:30:35 DEBUG RequestMappingHandlerMapping:319 - Looking up handler method for path /static/home.html
2016-04-01 11:30:35 DEBUG RequestMappingHandlerMapping:329 - Did not find handler method for [/static/home.html]
2016-04-01 11:30:35 DEBUG SimpleUrlHandlerMapping:191 - Matching patterns for request [/static/home.html] are [/static/**]
2016-04-01 11:30:35 DEBUG SimpleUrlHandlerMapping:220 - URI Template variables for request [/static/home.html] are {}
2016-04-01 11:30:35 DEBUG SimpleUrlHandlerMapping:141 - Mapping [/static/home.html] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[ServletContext resource [/static/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver#6a23a6d6]]] and 1 interceptor
2016-04-01 11:30:35 DEBUG DispatcherServlet:947 - Last-Modified value for [/static/home.html] is: -1
2016-04-01 11:30:35 DEBUG DispatcherServlet:1034 - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
2016-04-01 11:30:35 DEBUG DispatcherServlet:1000 - Successfully completed request
2016-04-01 11:30:35 DEBUG DispatcherServlet:1000 - Successfully completed request
I have a specific filtering to authenticate the user via a token in the header but I am not sure how it can be generated by that. Here is the code:
#RestController
#RequestMapping("/api")
public class APIController {
...
#RequestMapping(value="/groups",method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
public #ResponseBody String getAllGroups(){
List<CompetitionGroup> groups = groupService.findAllGroups();
return groupListToJSONObject(groups);
}
...
}
dispatcher-servlet.xml
<!-- SCANNING THE COMPONENT -->
<context:component-scan base-package="com.myapp"/>
<context:annotation-config/>
<context:property-placeholder/>
<mvc:annotation-driven/>
<mvc:resources mapping="/static/**" location="/static/"/>
pom.xml
<!-- Jackson (JSON) -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${jackson.version}</version>
</dependency>
I have implemented a specific filter for JWT token authentication below:
public class JWTTokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
#Autowired
private JWTUtil jwtUtil;
private static final Logger logger = Logger.getLogger(JWTTokenAuthenticationFilter.class);
public JWTTokenAuthenticationFilter(){
this("/api/");
}
public JWTTokenAuthenticationFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
setAuthenticationManager(new NoOpAuthenticationManager());
setAuthenticationSuccessHandler(new JWTSuccessAuthenticationHandler());
}
public final String HEADER_SECURITY_TOKEN = "Authorization";
#Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
return true;
}
/**
* Attempt to authenticate request - basically just pass over to another method to authenticate request headers
*/
#Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String header = request.getHeader(HEADER_SECURITY_TOKEN);
if (header == null || !header.startsWith("Bearer ")) {
throw new JwtTokenMissingException("No JWT token found in request headers");
}
/* Try to parse the token */
AppUser userDetails = jwtUtil.parseToken(header.substring(7));
Collection<SimpleGrantedAuthority> auth = new ArrayList<>();
auth.add(new SimpleGrantedAuthority(userDetails.getRole().name()));
JWTAuthenticationToken token = new JWTAuthenticationToken(userDetails.getEmail(), userDetails, auth);
token.setAuthenticated(true);
return token;
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
// As this authentication is in HTTP header, after success we need to continue the request normally
// and return the response as if the resource was not secured at all
chain.doFilter(request, response);
}
}
The trick is that the AuthenticationSuccessHandler was redirecting the request to '/' when authenticating.
So I created a new JWTSuccessAuthenticationHandler who does nothing after the authentication.
public class JWTSuccessAuthenticationHandler implements AuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
// We do not need to do anything extra on REST authentication success, because there is no page to redirect to
}
}
Hope that helps someone :)
I am trying to set up a java configurated spring environment including spring security. The application starts without any error, but I am not able to login succeffully.
WebAppInitializer
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
#Order(value = 1)
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { HibernateConfig.class, SecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
SecurityInitializer
import org.springframework.core.annotation.Order;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
#Order(value = 2)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
SecurityConfig
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/webjars/**","/css/**","/img/**");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(getUserQuery())
.authoritiesByUsernameQuery(getAuthoritiesQuery());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasAnyAuthority("EMPLOYEE", "TEAM_LEADER", "ADMIN")
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/success-login", true)
.loginProcessingUrl("/process-login")
.failureUrl("/error-login")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login")
.permitAll()
.and()
.rememberMe()
.and()
.csrf()
.disable();
}
private String getUserQuery() {
return "SELECT e_mail as username, password as password, active as enabled "
+ "FROM employee "
+ "WHERE e_mail = ?";
}
private String getAuthoritiesQuery() {
return "SELECT DISTINCT employee.e_mail as username, role.name as authority "
+ "FROM employee, employee_role, role "
+ "WHERE employee.id = employee_role.employee_id "
+ "AND role.id = employee_role.role_id "
+ "AND employee.e_mail = ? "
+ "AND employee.active = 1";
}
}
login.jsp
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div class="login-container">
<form class="form-signin" method="POST" action="<c:url value='/process-login'/>">
<h2 class="form-signin-heading">Anmelden</h2>
<c:if test="${error == true}">
<div class="alert alert-danger">
<a class="close" data-dismiss="alert" href="#">×</a>
<p>Login fehlgeschlagen: Eingegebener Nutzername oder Passwort ist falsch.</p>
</div>
</c:if>
<input type="text" name="j_username" id="j_username"
class="form-control" placeholder="eMail Adresse" required autofocus>
<input type="password" name="j_password" id="j_password"
class="form-control" placeholder="Passwort" required> <label
class="checkbox"> <input type="checkbox" value="remember-me">
Angemeldet bleiben
</label>
<button class="btn btn-lg btn-primary btn-block" type="submit">Anmelden</button>
</form>
</div>
LoginController
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class LoginController {
#RequestMapping(value={"/login"}, method=RequestMethod.GET)
public ModelAndView showLoginPage() {
return new ModelAndView("login/login");
}
#RequestMapping(value="/success-login", method=RequestMethod.POST)
public ModelAndView successLogin() {
return new ModelAndView("/dashboard");
}
#RequestMapping(value="/process-login", method=RequestMethod.POST)
public ModelAndView processLogin() {
return new ModelAndView("/dashboard");
}
#RequestMapping(value="/error-login", method=RequestMethod.GET)
public ModelAndView invalidLogin() {
ModelAndView modelAndView = new ModelAndView("login/login");
modelAndView.addObject("error", true);
return modelAndView;
}
#RequestMapping(value="/logout", method=RequestMethod.POST)
public ModelAndView logout() {
return new ModelAndView("login/login");
}
}
Database:
Content of Role Table: "EMPLOYEE", "TEAM_LEADER", "ADMIN",
I am looking for a solution a long time, but unfortunately I can not find the error. I appreciate all your advices.
Update 1 - Log4J Log after one login
2013-11-19 11:17:47,223 [DEBUG] [AbstractSecurityInterceptor.java : 310] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: 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: 45D43FE758F35164E5FE7BC9D08F81B8; Granted Authorities: ROLE_ANONYMOUS
2013-11-19 11:17:47,231 [DEBUG] [AffirmativeBased.java : 65] org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#2f7b1445, returned: -1
2013-11-19 11:17:47,237 [DEBUG] [ExceptionTranslationFilter.java : 165] org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Zugriff verweigert
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
2013-11-19 11:17:47,239 [DEBUG] [AndRequestMatcher.java : 66] org.springframework.security.web.util.matcher.AndRequestMatcher - Trying to match using Ant [pattern='/**', GET]
2013-11-19 11:17:47,239 [DEBUG] [AntPathRequestMatcher.java : 127] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'POST /j_spring_security_check' doesn't match 'GET /**
2013-11-19 11:17:47,240 [DEBUG] [AndRequestMatcher.java : 69] org.springframework.security.web.util.matcher.AndRequestMatcher - Did not match
2013-11-19 11:17:47,240 [DEBUG] [HttpSessionRequestCache.java : 44] org.springframework.security.web.savedrequest.HttpSessionRequestCache - Request not saved as configured RequestMatcher did not match
2013-11-19 11:17:47,240 [DEBUG] [ExceptionTranslationFilter.java : 185] org.springframework.security.web.access.ExceptionTranslationFilter - Calling Authentication entry point.
2013-11-19 11:17:47,241 [DEBUG] [DefaultRedirectStrategy.java : 36] org.springframework.security.web.DefaultRedirectStrategy - Redirecting to 'http://localhost:8080/holidayplanner/login'
2013-11-19 11:17:47,241 [DEBUG] [HttpSessionSecurityContextRepository.java : 300] org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2013-11-19 11:17:47,242 [DEBUG] [SecurityContextPersistenceFilter.java : 97] org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
2013-11-19 11:17:47,246 [DEBUG] [AntPathRequestMatcher.java : 145] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/webjars/**'
2013-11-19 11:17:47,246 [DEBUG] [AntPathRequestMatcher.java : 145] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/css/**'
2013-11-19 11:17:47,246 [DEBUG] [AntPathRequestMatcher.java : 145] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/img/**'
2013-11-19 11:17:47,247 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2013-11-19 11:17:47,247 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2013-11-19 11:17:47,247 [DEBUG] [HttpSessionSecurityContextRepository.java : 148] org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
2013-11-19 11:17:47,247 [DEBUG] [HttpSessionSecurityContextRepository.java : 90] org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#2664e105. A new one will be created.
2013-11-19 11:17:47,247 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2013-11-19 11:17:47,247 [DEBUG] [HstsHeaderWriter.java : 129] 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#2f389f24
2013-11-19 11:17:47,247 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2013-11-19 11:17:47,247 [DEBUG] [AntPathRequestMatcher.java : 145] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/logout'
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 5 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2013-11-19 11:17:47,248 [DEBUG] [AntPathRequestMatcher.java : 127] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /login' doesn't match 'POST /success-login
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 6 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 7 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 8 of 12 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2013-11-19 11:17:47,248 [DEBUG] [AnonymousAuthenticationFilter.java : 102] 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: 45D43FE758F35164E5FE7BC9D08F81B8; Granted Authorities: ROLE_ANONYMOUS'
2013-11-19 11:17:47,249 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2013-11-19 11:17:47,249 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2013-11-19 11:17:47,249 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2013-11-19 11:17:47,249 [DEBUG] [AbstractSecurityInterceptor.java : 194] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /login; Attributes: [permitAll]
2013-11-19 11:17:47,249 [DEBUG] [AbstractSecurityInterceptor.java : 310] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: 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: 45D43FE758F35164E5FE7BC9D08F81B8; Granted Authorities: ROLE_ANONYMOUS
2013-11-19 11:17:47,249 [DEBUG] [AffirmativeBased.java : 65] org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#2f7b1445, returned: 1
2013-11-19 11:17:47,249 [DEBUG] [AbstractSecurityInterceptor.java : 215] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorization successful
2013-11-19 11:17:47,250 [DEBUG] [AbstractSecurityInterceptor.java : 227] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - RunAsManager did not change Authentication object
2013-11-19 11:17:47,250 [DEBUG] [FilterChainProxy.java : 323] org.springframework.security.web.FilterChainProxy - /login reached end of additional filter chain; proceeding with original chain
2013-11-19 11:17:47,254 [DEBUG] [ExceptionTranslationFilter.java : 115] org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
2013-11-19 11:17:47,254 [DEBUG] [HttpSessionSecurityContextRepository.java : 300] org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2013-11-19 11:17:47,254 [DEBUG] [SecurityContextPersistenceFilter.java : 97] org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
Working Solution:
Finally I found a working solution with your help. Thanks for this. Following all needed Files if someone other is interested in a java configured spring security:
Login JSP:
<div class="login-container">
<form class="form-signin navbar navbar-default" method="POST" action="<c:url value='/login/process-login'/>">
<div class="form-signin-img">
<span class="form-signin-img-helper"></span>
<img src="<c:url value='/img/itensis_logo.gif'/>" />
</div>
<h2 class="form-signin-heading">${msg_heading}</h2>
<c:if test="${error == true}">
<div class="alert alert-danger">
<button type="button" class="close close-box">×</button>
<p>${msg_error}</p>
</div>
</c:if>
<input type="text" name="security_username" id="security_username" class="form-control" placeholder="${msg_username}" required autofocus>
<input type="password" name="security_password" id="security_password" class="form-control" placeholder="${msg_password}" required>
<label class="checkbox">
<input type="checkbox" name="remember_me_checkbox"> ${msg_rememberMe}
</label>
<button class="btn btn-lg btn-primary btn-block" type="submit">
<i class="fa fa-sign-in fa-lg"></i>
<span>${msg_login}</span>
</button>
</form>
SecurityConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired private UserDetailsService userDetailService;
#Autowired private DataSource dataSource;
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/js/**","/css/**","/img/**","/webjars/**","/pages/**");
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
ShaPasswordEncoder shaPasswordEncoder = new ShaPasswordEncoder(256);
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(getUserQuery())
.authoritiesByUsernameQuery(getAuthoritiesQuery())
.passwordEncoder(shaPasswordEncoder);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasAuthority("BASIC_PERMISSION")
.and()
.formLogin()
.loginPage("/login/login")
.defaultSuccessUrl("/login/success-login", true)
.failureUrl("/login/error-login")
.loginProcessingUrl("/login/process-login")
.usernameParameter("security_username")
.passwordParameter("security_password")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login/login")
.logoutUrl("/login/logout")
.permitAll()
.and()
.rememberMe()
.key("your_key")
.rememberMeServices(rememberMeServices())
.and()
.csrf()
.disable();
}
#Bean
public RememberMeServices rememberMeServices() {
// Key must be equal to rememberMe().key()
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("your_key", userDetailService);
rememberMeServices.setCookieName("remember_me_cookie");
rememberMeServices.setParameter("remember_me_checkbox");
rememberMeServices.setTokenValiditySeconds(2678400); // 1month
return rememberMeServices;
}
#Bean
public UserDetailsService userDetailService() {
return new SecurityUserDetailService();
}
private String getUserQuery() {
return "SELECT username as username, password as password, active as enabled "
+ "FROM employee "
+ "WHERE username = ?";
}
private String getAuthoritiesQuery() {
return "SELECT DISTINCT employee.username as username, permission.name as authority "
+ "FROM employee, employee_role, role, role_permission, permission "
+ "WHERE employee.id = employee_role.employee_id "
+ "AND role.id = employee_role.role_id "
+ "AND role.id = role_permission.role_id "
+ "AND permission.id = role_permission.permission_id "
+ "AND employee.username = ? "
+ "AND employee.active = 1";
}
}
LoginController.java
#Controller
#RequestMapping("/login")
public class LoginController {
#RequestMapping(value={"/login"}, method=RequestMethod.GET)
public ModelAndView showLoginPage() {
return new ModelAndView("loginForm");
}
#RequestMapping(value="/success-login", method=RequestMethod.GET)
public String successLogin() {
return "forward:/dashboard/dashboard";
}
#RequestMapping(value="/error-login", method=RequestMethod.GET)
public ModelAndView invalidLogin() {
ModelAndView modelAndView = new ModelAndView("loginForm");
modelAndView.addObject("error", true);
return modelAndView;
}
#RequestMapping(value="/logout", method=RequestMethod.POST)
public ModelAndView logout() {
return new ModelAndView("dashboardForm");
}
}
Update 1: SecurityUserDetailService
#Service
#Transactional
public class SecurityUserDetailService implements UserDetailsService {
#Autowired private EmployeeService employeeService;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
Employee loggedInEmployee = employeeService.findEmployeeByUsername(username);
List<GrantedAuthority> authorities = getAuthorities(loggedInEmployee);
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(
loggedInEmployee.getUsername(),
loggedInEmployee.getPassword().toLowerCase(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
authorities);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static List<GrantedAuthority> getAuthorities(Employee employee) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (Role role : employee.getRoles()) {
for (Permission permission : role.getPermissions()) {
authorities.add(new SimpleGrantedAuthority(permission.getName()));
}
}
return authorities;
}
}