Upload File Denied by Spring Security - spring

I recently implemented a file upload function within my spring mvc application, but unfortunately it doesn't work as it constantly gets blocked by Spring Security. If i disable CSRF in Security Configuration it works, so it leads me to believe something is wrong there.
Spring config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/test/**").permitAll()
.antMatchers("/admin/**","/user/secure").hasRole("ADMIN")
.antMatchers("/**").permitAll()
.anyRequest().anonymous()
.and()
.exceptionHandling().accessDeniedPage("/denied")
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/error-login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/")
.and()
.rememberMe()
.userDetailsService(userAccessDetails)
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(16000)
;
}
file upload form:
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="UTF-8"/>
<title></title>
</head>
<body>
<h4>Single File</h4>
<form method="POST" th:action="#{/test/uploadFile}" enctype="multipart/form-data">
File to upload: <input type="file" name="file"/><br />
Name: <input type="text" name="name"/><br /> <br />
<input type="submit" value="Upload"/> Press here to upload the file!
</form>
</body>
</html>
Any assistance would be appreciated guys.
NOTE: I've had to recreate the question as original i deleted by mistake

You can do three things.
1) Implement Multipart filter as mention in Spring CSRF documentation (See below link for more detail example)
-- http://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/csrf.html#csrf-multipartfilter
along with multipart resolver bean
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-multipart
--- Pretty much this should work unless there are more customize code involve during upload. if it has some customization then option 2 is better
2) Implement SpringSecurityFilterchain in config. add Multipart filter before security filter start executed. implement multipart resolver.
3) nothing works then try to convert file in Json at client side and post it as a binary data to the server. (its a workaround and try to avoid as its not a good design to do that). -- for example pdf2json you can use this js file
Let me know if any of the option helps.

Related

Getting 403 Forbidden error in Spring Boot security despite CSRF being disabled

For some reason I'm getting a 403 Forbidden error from Spring Boot when I try to do anything with it. I currently have the following in my configure method of my SecurityConfiguration class:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/*", "/console").permitAll()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.anyRequest().authenticated()
.and().addFilterBefore(new LoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
I'm new to this part of Spring boot so not sure if this is what's causing it.
Turns out... I'm an idiot. This isn't caused by CSRF at all... It was caused by the fact I'm British and I spell what should be Authorization as Authorisation in my AuthenticationFilter which was choking up everything else.

Spring Boot Security WebFlux functional, cannot created configuration for two authentication methods

I would like to have two ways of authentication in Spring Boot application. App is written with WebFlux and with functional approach. For some of my endpoints I'd like to have authentication with basicHttp and for some endpoints I would like to have JWT authentication using custom HTTP header. However I cannot merge two WebFilterChains or make it work as one. Only one of the methods works at the time, cannot make them both work. Code for JWT is not finished, but I would like to see 401 when I send request with httpBasic auth method. Paths in examples are fake.
My atttemps:
1)
First bean:
http
.securityMatcher(ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/api/1/**"))
.csrf().disable()
.formLogin().disable()
.logout().disable()
.httpBasic().and()
.authenticationManager(authenticationManager(userService))
.build();
Second bean:
http
.securityMatcher(ServerWebExchangeMatchers.pathMatchers("/api/2/**"))
.httpBasic().disable()
.csrf().disable()
.formLogin().disable()
.logout().disable()
.authenticationManager(tokenAuthManager)
.authorizeExchange()
.anyExchange().authenticated()
.and()
.build();
2)
http
.securityMatcher(ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/api/1/**"))
.csrf().disable()
.formLogin().disable()
.logout().disable()
.httpBasic().and()
.authenticationManager(authenticationManager(userService))
.securityMatcher(ServerWebExchangeMatchers.pathMatchers("/api/2/**"))
.httpBasic().disable()
.csrf().disable()
.formLogin().disable()
.logout().disable()
.authenticationManager(tokenAuthManager)
.authorizeExchange()
.anyExchange().authenticated()
.and()
.build();

SpringBoot app - server context Path

I've generated a Spring Boot web application using Spring Initializer, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file.
Technologies used:
Spring Boot 2.0.0.M6 , Java 8, maven
Here my security config
#Override
protected void configure(HttpSecurity http) throws Exception {
final List<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
if (activeProfiles.contains("dev")) {
http.csrf().disable();
http.headers().frameOptions().disable();
}
http
.authorizeRequests()
.antMatchers(publicMatchers()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").defaultSuccessUrl("/iberia/list")
.failureUrl("/login?error").permitAll()
.and()
.logout().permitAll();
}
in my application.properties
server.contextPath=/iberiaWebUtils
server.port=1234
But when I run the app at http://localhost:1234/iberiaWebUtils, instead of going to http://localhost:1234/iberiaWebUtils/login, the app. redirects to http://localhost:1234/login
I also tried with
server.context-path=/iberiaWebUtils
with the same result
Starting from Spring Boot 2.0.0 M1 servlet-specific server properties were moved to server.servlet:
Spring Boot 2.0.0 M1 Release Notes
Therefore, you should use the server.servlet.context-path property.
Try adding .loginProcessingUrl("/iberiaWebUtils/login") after loginPage("/login")
http
.authorizeRequests()
.antMatchers(publicMatchers()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login")
.loginProcessingUrl("/iberiaWebUtils/login")
.defaultSuccessUrl("/iberia/list")
.failureUrl("/login?error").permitAll()
.and()
.logout().permitAll();

How to configure AuthenticationSuccessHandler etc. only for /api/**

We are developing a standard Spring Boot web application with Thymeleaf templating, but have an API at /api/** which is called through AJAX.
We're using Spring Security's standard cookie based form authentication both for the application and the API. Whereas for the application we want Spring Security to behave in the default way, for the API, we want to provide custom AuthenticationSuccessHandler etc. for returning 200 OK etc., instead of redirecting to success or failure urls.
I am unable to figure out how to configure this, using Java configuration. In the configure method, I tried to configure http two times, as below, but it doesn't seem to work:
// For the API
http.antMatcher("/api/**")
.formLogin()
.successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler())
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler)
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and()
.rememberMe()
.key(properties.getRememberMeKey())
.rememberMeServices(rememberMeServices())
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(new LemonCsrfFilter(), CsrfFilter.class)
.addFilterAfter(switchUserFilter(), FilterSecurityInterceptor.class)
.authorizeRequests()
.antMatchers("/login/impersonate*").hasRole(GOOD_ADMIN)
.antMatchers("/logout/impersonate*").authenticated()
.antMatchers("/**").permitAll();
// For the application pages
http
.authorizeRequests()
.antMatchers("/login/impersonate*").hasRole(GOOD_ADMIN)
.antMatchers("/logout/impersonate*").authenticated()
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login").permitAll()
.and()
.logout().permitAll()
.and()
.rememberMe()
.key(properties.getRememberMeKey())
.rememberMeServices(rememberMeServices())
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(new LemonCsrfFilter(), CsrfFilter.class)
.addFilterAfter(switchUserFilter(), FilterSecurityInterceptor.class);

Spring webflow overwrite Spring security request rules?

Project use SWF 2.4.1 and SSec 4. I specified a failUrl on spring security for errors on login and a transition on webflow if evaluate expression fail. In this case SWF redirection is priority to SSec redirection. I wonder if there is some way to omit/change this behavior because I would follow spring security rules automatically without to create rules on spring webflow.
security rules
http
.antMatcher("/spring/**/*.xhtml")
.exceptionHandling().authenticationEntryPoint(new AccessDenyEntryPoint())
.and()
.requestCache().requestCache(requestCache())
.and()
.authorizeRequests()
.antMatchers("/spring/resources/**","/spring/login","/spring/signup",
"/spring/main","/spring/error","/spring/group").permitAll()
.antMatchers("/spring/myprofile").hasRole("USER")
.antMatchers("/spring/profilegroup").hasRole("MEMBER")
.antMatchers("/spring/admin").hasRole("ADMIN")
.antMatchers("/spring/**/*.xhtml").denyAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/spring/login")
.defaultSuccessUrl("/spring/main",true)
.failureUrl("/spring/login?login_error=1")
.and()
.logout()
.logoutSuccessUrl("/spring/home")
.deleteCookies("JSESSIONID")
.and()
.rememberMe().userDetailsService(customDetailsService)
.and()
.exceptionHandling().accessDeniedPage("/spring/error?error_code=1")
.and()
// Disable CSRF (won't work with JSF) but ensure last HTTP POST request is saved
// See https://jira.springsource.org/browse/SEC-2498
.csrf().disable()
.requestCache()
.requestCache(new HttpSessionRequestCache())
.and()
.sessionManagement()
.sessionFixation().changeSessionId()
.invalidSessionUrl("/spring/main")
.sessionAuthenticationErrorUrl("/spring/error?error_code=4")
.maximumSessions(1)
.expiredUrl("/spring/error?error_code=2")
.maxSessionsPreventsLogin(true);
Webflow rules
<view-state id="login" view="login.xhtml">
<transition on="entry" to="connect"/>
<transition on="recoveryPass" to="recovery" />
</view-state>
<action-state id="connect">
<evaluate expression="login.connect()" />
<transition on="yes" to="connected" />
<transition on="no" to="recovery" />
</action-state>
<view-state id="recovery" view="recovery.xhtml">
<transition on="sendPass" to="login" />
<transition on="return" to="login" />
<transition on="error" />
</view-state>
<end-state id="finish" />
validation code
public String connect(){
logger.entry("Login.connect()");
try{
Authentication request=new UsernamePasswordAuthenticationToken(getEmail(), getPassword());
Authentication result=daoProvider.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
}catch (BadCredentialsException e) {
//MessageRedirect.addFlashMesage("usuario.no.registrado","msg");
return "no";
}catch (LockedException e) {
//MessageRedirect.addFlashMesage("usuario.bloqueado","msg");
return "no";
}catch (DisabledException e) {
//MessageRedirect.addFlashMesage("usuario.desactivado","msg");
return "no";
}
return "yes";
}
Real problem was I was setting secured control on spring security configuration and I should set their on flow definition. Create a custom form page/controller wasn't the problem and works properly and it's not necessary to set loginProccess if you are using a bean. So, configuration would be some like this
Security config
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling().authenticationEntryPoint(new AccessDenyEntryPoint())
.and()
.exceptionHandling().accessDeniedHandler(new AccessDenyHandlerPoint())
.and()
.authorizeRequests()
.antMatchers("/spring/**/*.xhtml").denyAll()
.and()
.formLogin()
.loginPage("/spring/login")
.loginProcessingUrl("/spring/loginProcess")
.defaultSuccessUrl("/spring/main",true)
.failureUrl("/spring/login?login_error=1")
.and()
.logout()
.logoutUrl("/spring/logout")
.logoutSuccessUrl("/spring/main")
.deleteCookies("JSESSIONID")
// Disable CSRF (won't work with JSF) but ensure last HTTP POST request is saved
// See https://jira.springsource.org/browse/SEC-2498
.and()
.csrf().disable()
.sessionManagement()
.sessionFixation().changeSessionId()
.invalidSessionUrl("/spring/error?error_code=1")
.sessionAuthenticationErrorUrl("/spring/error?error_code=2")
.maximumSessions(1)
.expiredUrl("/spring/error?error_code=3")
.maxSessionsPreventsLogin(true);
}
Flow definition
<secured attributes="ROLE_USER" />
<on-start>
<evaluate expression="spaceBO.dao.getAll()" result="flowScope.spaces"/>
</on-start>
<view-state id="inicio" view="main.xhtml">
</view-state>

Resources