I have a Spring Boot application with this mappging:
#GetMapping(value = { "/", })
public String home(Model model) {
}
and
localhot:8080,
localhost:8080/ ,
localhost:8080/.,
localhost:8080/..
redirects to / but not
localhost:8080/...
and in the WebSecurityConfig the only public matcher I have is this one: /.
I would like to restrict the access for localhost:8080/. and localhost:8080/..
here:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserSecurityService userSecurityService;
private final Environment env;
private static final String SALT = "fd&l23j§sfs23#$1*(_)nof";
public WebSecurityConfig(UserSecurityService userSecurityService, Environment env) {
this.userSecurityService = userSecurityService;
this.env = env;
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12, new SecureRandom(SALT.getBytes()));
}
#Override
protected void configure(HttpSecurity http) throws Exception {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceEncoding(true);
http.addFilterBefore(encodingFilter, CsrfFilter.class);
http.csrf().disable();
http
.authorizeRequests()
.antMatchers(publicMatchers()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.defaultSuccessUrl("/advertise.html")
.failureUrl("/login.html?error").permitAll()
.and()
.logout()
.permitAll()
.and()
.rememberMe()
.key("uniqueAndSecret");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userSecurityService)
.passwordEncoder(passwordEncoder());
}
private String[] publicMatchers() {
final String[] PUBLIC_MATCHERS = {
"/webjars/**",
"/css/**",
"/fonts/**",
"/images/**",
"/img/**",
"/js/**",
"/home.html",
"/links/**",
"/links.html",
"/favicon.ico",
"/forgotmypassword.html",
"/directory/**",
"/",
"/error/**/*",
"/h2-console/**",
ForgotMyPasswordController.FORGOT_PASSWORD_URL_MAPPING,
ForgotMyPasswordController.CHANGE_PASSWORD_PATH
};
return PUBLIC_MATCHERS;
}
}
I have made a simple example similar to yours. I am testing with curl (not a web browser) and this is the result:
localhost:8080/. Internal server error.
This exception is thrown in the server: org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL was not normalized.
localhost:8080/.. Bad request
It seems that the embedded tomcat gives you that response. I tried adding a Global error controller and I could get the error in spring
localhost:8080/... Endpoint not found
This is exepcted as I don't have any mapping for such endpoint "/..."
I think that your browser is actually requesting for localhost:8080/ when you type localhost:8080/. or localhost:8080/.. Your spring boot app is not redirecting
Related
I am currently working on a Spring project, where I got the Security already implemented.(University) But I occurred the following problem: If I want to register a new user to the system, I logically do not have a JWT to authenticate the new user. I just get Invalid authorization header or token back from Spring, if I try to register a new user. So, I think the Security is not right configured:
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserService userService;
private final PasswordEncoder passwordEncoder;
private final RequestMatcher whiteListedRequests;
private final SecurityProperties securityProperties;
private final JwtTokenizer jwtTokenizer;
#Autowired
public SecurityConfig(UserService userService,
PasswordEncoder passwordEncoder,
SecurityProperties securityProperties, JwtTokenizer jwtTokenizer) {
this.userService = userService;
this.securityProperties = securityProperties;
this.passwordEncoder = passwordEncoder;
this.jwtTokenizer = jwtTokenizer;
this.whiteListedRequests = new OrRequestMatcher(securityProperties.getWhiteList().stream()
.map(AntPathRequestMatcher::new)
.collect(Collectors.toList()));
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.csrf()
.disable();
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/v1/users/sign-up")
.permitAll();
http.authorizeRequests().anyRequest()
.authenticated();
http.addFilter(new JwtAuthenticationFilter(authenticationManager(), securityProperties, jwtTokenizer));
http.addFilter(new JwtAuthorizationFilter(authenticationManager(), securityProperties));
}
#Override
public void configure(WebSecurity web) {
web.ignoring().requestMatchers(whiteListedRequests);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder);
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final List<String> permitAll = Collections.unmodifiableList(Collections.singletonList("*"));
final List<String> permitMethods = List.of(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.PUT.name(),
HttpMethod.PATCH.name(), HttpMethod.DELETE.name(), HttpMethod.OPTIONS.name(), HttpMethod.HEAD.name(),
HttpMethod.TRACE.name());
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedHeaders(permitAll);
configuration.setAllowedOrigins(permitAll);
configuration.setAllowedMethods(permitMethods);
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Does anyone has a tip, how I can change the securityconfig, that a user can register himself against my Endpoint? (/api/v1/users/sign-up) I am kind of lost at this, and trying for several hours to manage the wanted behavior!
Thanks in Advance!
EDIT:
I just figured that my application.yml holds a whitelist:
security:
auth:
header: Authorization
prefix: "Bearer "
login-uri: /api/v1/authentication
white-list:
# Browser requests
- /
- /favicon.ico
- /csrf
- /v2/api-docs
- /swagger-resources/**
- /webjars/**
- /swagger-ui.html
# H2
- /h2-console/**
# Registration
- /api/v1/registrations/
If I add the URI here, it works properly. But is there a solution to just add it via Code?
the registration uri must not request a token, it must be allowed access from the outside.
it must be enabled at the antMatcher
Here is an exemple
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable();
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/regitration/**")
.permitAll();
http.authorizeRequests().anyRequest()
.authenticated();
http.addFilter(new JWTAuthenticationFilter(authenticationManager(),userRepository,iLdapService,cryptoHelper));
http.addFilterBefore(new JWTAutorizationFilter(),UsernamePasswordAuthenticationFilter.class);
}
Edit :
Thx Thomas Andolf !
It works when i use embended tomcat in springboot 'spring i launched on IntelliJ and the angular part with visual studio code.
But it does not work when i publish the war in provided tomcat on my raspberry pi...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests(authorizeRequests ->
authorizeRequests.antMatchers(HttpMethod.POST, "/rest/gender").permitAll()
.antMatchers(HttpMethod.POST, "/rest/login").permitAll()
.antMatchers(HttpMethod.POST, "/rest/names").permitAll()
.anyRequest().authenticated()
)
.httpBasic()
.authenticationEntryPoint(authEntryPoint)
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
The angular part of the project is published in tomcat/webapps/ROOT.
The war is published in tomcat/webapps/baby-project-api.
I use tomcat/conf/Catalina/localhost/rewrite.config like this :
RewriteRule ^/rest/(.+)$ /baby-project-api/rest/$1
Original Question
I try to use Basic Authentication on an api with spring boot security and i need some path to be not secured.
POST /rest/login is not secured with the config,
GET /rest/gender is secured and that's what i want
Any idea why POST /rest/gender is still secured ?
There is my WebSecurityConfig :
#Configuration
#EnableAutoConfiguration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationEntryPoint authEntryPoint;
#Autowired
private IParentRepository parentRepository;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/rest/gender").permitAll()
.antMatchers(HttpMethod.POST, "/rest/login").permitAll()
.antMatchers(HttpMethod.POST, "/rest/names").permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.authenticationEntryPoint(authEntryPoint);
//.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
final List<Parent> parents = parentRepository.findAll();
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> mngConfig = auth.inMemoryAuthentication();
for (Parent parent : parents) {
mngConfig.withUser(User.withUsername(parent.getUsername()).password(parent.getPassword()).roles("ADMIN").build());
}
}
}```
POST /rest/login is not secured with the config,
GET /rest/gender is secured and that's what i want
Any idea why POST /rest/gender is still secured ?
can you please try doing it the way they actually do it in the documentation and see if it works.
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests(authorizeRequests ->
authorizeRequests.antMatchers(HttpMethod.POST, "/rest/gender").permitAll();
authorizeRequests.antMatchers(HttpMethod.POST, "/rest/login").permitAll();
authorizeRequests.antMatchers(HttpMethod.POST, "/rest/names").permitAll();
authorizeRequests.anyRequest().authenticated();
)
.httpBasic()
.authenticationEntryPoint(authEntryPoint);
}
After all, i did not find a great solution by this way.
i open all the api and restricted some parts with pre-auth :
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest().permitAll()
.and().httpBasic()
.authenticationEntryPoint(authEntryPoint)
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
And on the controller :
#RestController
#PreAuthorize("isAuthenticated()")
#RequestMapping("/rest/gender")
public class GenderController {
[...]
// protected by the # on the class
#GetMapping(value = "")
public List<Gender> listerGender(final SecurityContextHolderAwareRequestWrapper request){
return genderService.listerGender(request);
}
#PreAuthorize("permitAll()")
#PostMapping(value = "", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> creerGender(#Valid #RequestBody Gender gender){
return this.genderService.creerGender(gender);
}
I think we can make it cleaner but at least it works
I am using Spring Boot 1.5.9 and have an application that has an API that uses OAuth2 client credentials, with formlogin for a CMS that uses Thymeleaf in the same Spring Boot application.
For this to work, I have the following bean to configure the form login:
#Configuration
public class WebSecurityGlobalConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// api security is handled elsewhere (See OAuth2ServerConfiguration)
.antMatchers("/api/**", "/oauth/**", "/management/**")
.permitAll()
// end api security
.anyRequest().hasRole(UserRole.ADMIN.name())
.and()
.formLogin().loginPage("/login")
.permitAll()
.and()
.logout().permitAll();
}
}
So for the form login part, I declare everything related to API, Oauth and /management (the custom context-path I have set in application.properties for the actuator endpoints):
management.context-path=/management
management.security.roles=ADMIN
For Oauth2, I have this:
#Configuration
public class OAuth2ServerConfiguration {
private static final String RESOURCE_ID = "my-app-service";
#Configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/api/**")
.permitAll()
.and()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.authorizeRequests()
.antMatchers("/management/health", "/management/info").permitAll()
.antMatchers("/management/**").hasRole(UserRole.ADMIN.name())
.anyRequest().authenticated();
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private TokenStore tokenStore;
#Autowired
private SecurityConfiguration securityConfiguration;
// NOTE: If you set a new validity, you need to clear the 'oauth_access_token' table
// in the database. Only new tokens get the new validity.
#Value("${myapp.security.oauth.access-token-validity-seconds:43200}") // 12 hours by default
private int accessTokenValiditySeconds;
#Value("${myapp.security.oauth.refresh-token-validity-seconds:2592000}") // 30 days by default
private int refreshTokenValiditySeconds;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.passwordEncoder(passwordEncoder);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(securityConfiguration.getMobileAppClientId())
.authorizedGrantTypes("password", "refresh_token")
.scopes("mobile_app")
.resourceIds(RESOURCE_ID)
.accessTokenValiditySeconds(accessTokenValiditySeconds)
.refreshTokenValiditySeconds(refreshTokenValiditySeconds)
.secret(passwordEncoder.encode(securityConfiguration.getMobileAppClientSecret()));
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).
authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
}
I want the following behaviour:
If user has role ADMIN by using an Oauth2 access token, all actuator endpoints must be accessible
If the user does not have this ADMIN role, only /health and /info should be accessible (If ADMIN, /health should show extra info like it is by default)
The current behaviour:
The info and health endpoints can be viewed by everybody, but as ADMIN, you don't get extra info. For the other endpoints, I get a 401 if I try with an access token of an ADMIN user with:
{
"timestamp": "2018-01-30T13:45:26.625+0000",
"status": 401,
"error": "Unauthorized",
"message": "Full authentication is required to access this resource.",
"path": "/management/beans"
}
If I set management.security.enabled=false then the ADMIN user has access, but all non-ADMIN users also have access.
What should I change to get the wanted behaviour?
I managed to make it work with the following in the configure method of ResourceServerConfiguration :
http
.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/api/**")
.permitAll()
.and()
.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.and()
.requestMatchers()
.antMatchers("/management/**")
.and()
.authorizeRequests()
.antMatchers("/management/health", "/management/info").permitAll()
.antMatchers("/management/**").hasRole(UserRole.ADMIN.name())
.anyRequest()
.authenticated()
Using multiple antMatchers directly on the http object does not work, you need to first use requestMatchers
Hi I have implemented Spring security in my spring boot web application with JWT filters. But the default authentication is happening at url http://localhost:8080/login . How to change /login to some url I need like /rest/auth/login?
My WebSecurity class is
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity( UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder )
{
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#Override
protected void configure( HttpSecurity http ) throws Exception
{
http.cors().and().csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, "/rest/auth/**").permitAll()
.antMatchers("/static/*").permitAll().antMatchers("/").permitAll()
/* .anyRequest().authenticated() */.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
#Override
public void configure( AuthenticationManagerBuilder auth ) throws Exception
{
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
public void configure( org.springframework.security.config.annotation.web.builders.WebSecurity web )
throws Exception
{
web.ignoring().antMatchers("/static/**");
}
#Bean
CorsConfigurationSource corsConfigurationSource()
{
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
I have a login page in my resource folder under static directory. The way Spring security works is, when user sends userName and password from the form, client has to send those credentials to /login path in the server, so that spring security verifies those credentials and creates token. But I want to change that default path /login to /rest/auth/login
In your AuthenticationFilter you can call setFilterProcessesUrl during construction, example:
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
setFilterProcessesUrl("/api/v1/tokens"); // <--- like this
}
...
Hope it helps.
You need to tweak the WebSecurityConfig.java and JWTAuthenticationFilter.
#Override
protected void configure( HttpSecurity http ) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/rest/noauth/**").permitAll()
.antMatchers("/rest/login").permitAll()
.antMatchers("/rest/logout").permitAll()
.antMatchers("/src/**").permitAll()
.antMatchers("/v2/api-docs/**", "/configuration/ui/**", "/swagger-resources/**",
"/configuration/security/**", "/swagger-ui.html/**", "/webjars/**")
.permitAll()
.anyRequest().authenticated()
.and()
.logout().addLogoutHandler(logoutHandler).logoutSuccessHandler(logoutSuccessHandler)
.logoutUrl("/rest/logout")
.and()
.addFilterBefore(
new JWTAuthenticationFilter("/rest/login",
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthorizationFilter(authenticationManager(), authTokenModelRepository),
UsernamePasswordAuthenticationFilter.class);
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
and make your JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter which has a constructor which takes the filterProcessingURl and I passed /rest/login as the parameter.
public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
private AuthenticationManager authenticationManager;
private TokenService tokenService;
private UserModel credentials;
private RefreshTokenService refreshTokenService;
private AuthTokenModelRepository authTokenModelRepository;
private UserModelRepository userModelRepository;
public JWTAuthenticationFilter( String loginUrl, AuthenticationManager authenticationManager,
TokenService tokenService, RefreshTokenService refreshTokenService,
AuthTokenModelRepository authTokenModelRepository, UserModelRepository userModelRepository )
{
super(new AntPathRequestMatcher(loginUrl));
}
After the above configuration, the JWTAuthenticationFilter will be executed for the request /rest/login.
Just to complement Jordy Baylac's answer: in Kotlin I was struggling how to set the filter once I'm injecting the dependencies via main constructor. My solution was do something like this:
class AuthenticationFilter(
authenticationManager: AuthenticationManager?,
private var jwtUtilsComponent: JwtUtilsComponent,
) : UsernamePasswordAuthenticationFilter() {
private val authManager: AuthenticationManager? = authenticationManager
init {
setFilterProcessesUrl("/${ApiProperties.BASE_PATH}/login")
}
// more code
}
then it worked very well.
In the configure method try to add loginProcessungUrl() method. You can set the value in the parameter
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.loginProcessingUrl(LOGIN_URL);
You need to provide the url to the login page and the url that would process the authentication. This can be done by overriding the method like this:
#Override
protected void configure( HttpSecurity http ) throws Exception
{
http.cors().and().csrf().disable().
authorizeRequests().
antMatchers(HttpMethod.POST, "/rest/auth/**").
permitAll()
.antMatchers("/static/*").permitAll()
.antMatchers("/").permitAll()
.and().formLogin().
/*This is where the juice is*/
loginPage("/login").loginProcessingUrl("/rest/auth/login")
/* .anyRequest().authenticated() */.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
The loginPage("/login") can be replaced with the route to your static login page while the loginProcessingUrl is the url of the controller that processes your login logic. Ensure that controllers exist for both /login and /loginProcesingUrl.
Modify "HttpSecurity", as follows, example:
#Override
protected void configure( HttpSecurity http ) throws Exception {
http.cors().and().csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, "/rest/auth/**").permitAll()
.antMatchers("/static/*").permitAll().antMatchers("/").permitAll()
/* .anyRequest().authenticated() */
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/rest/auth/login")
.permitAll()
.and()
.logout()
.permitAll();
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
I have a controller to upload a user's avatar that has been working for quite a while. Until recently, after I made a change to my spring security configuration. The change was to have unauthorized calls to API's return 403 forbidden and unauthorized calls to anything else redirect to login. Since making this change the app throws a 403 every time a call is made to upload an avatar. Every other API works as intended.
Here are the snippets I believe are relevant to the issue at hand:
Controller:
#Controller
#RequestMapping("/api/users")
public class UsersController {
#RequestMapping(value = "/upload_avatar", params = { "filename" }, method = RequestMethod.POST)
public #ResponseBody ResponseStatusDTO handleFileUpload(
#RequestParam("file") MultipartFile file,
#RequestParam(value = "filename") String filename) {
if (!file.isEmpty()) {
try {
String newFilename = userUtil.uploadAvatar(file, filename);
return new ResponseStatusDTO(1, newFilename);
} catch (Exception e) {
return new ResponseStatusDTO(1, "Failed to upload " + filename
+ "!");
}
} else {
return new ResponseStatusDTO(1, "Failed to upload " + filename
+ " because the file was empty.");
}
}
}
Ajax Call Performing Request:
uploadAvatar : function(){
var file = this.getSelectedFile();
var data = new FormData();
data.append('file', file);
var name = file.name;
$.ajax({
url: './api/users/upload_avatar?filename='+ name,
data: data,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: _.bind(function(data){
this.avatar = data.message;
}, this),
error: _.bind(function(data){
//TODO
}, this)
});
}
Latest Spring Security Configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration {
#Autowired
private CommonAuthenticationProvider authProvider;
#Autowired
AuthFailureHandler authFailureHandler;
#Autowired
AuthSuccessHandler authSuccessHandler;
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(authProvider);
}
#Configuration
#Order(1)
public static class ApiLoginWebSecurityConfigurationAdapter extends
WebSecurityConfigurerAdapter {
#Autowired
private Http403ForbiddenEntryPoint forbiddenEntryPoint;
#Bean
public Http403ForbiddenEntryPoint forbiddenEntryPoint() {
return new Http403ForbiddenEntryPoint();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.httpBasic()
.authenticationEntryPoint(forbiddenEntryPoint);
// #formatter:on
}
}
#Configuration
public static class FormLoginWebSecurityConfigurationAdapter extends
WebSecurityConfigurerAdapter {
#Autowired
AuthFailureHandler authFailureHandler;
#Autowired
AuthSuccessHandler authSuccessHandler;
#Autowired
private LoginUrlAuthenticationEntryPoint loginEntryPoint;
#Bean
public LoginUrlAuthenticationEntryPoint loginEntryPoint() {
return new LoginUrlAuthenticationEntryPoint("/login");
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/js/**", "/webjars/**",
"/login/**", "/session/**", "/public/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/j_spring_security_check")
.usernameParameter("username")
.passwordParameter("password")
.failureHandler(authFailureHandler)
.successHandler(authSuccessHandler)
.permitAll()
.and()
.logout()
.logoutUrl("/j_spring_security_logout")
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
// .deleteCookies(cookieNamesToClear)
.and()
.httpBasic().authenticationEntryPoint(loginEntryPoint)
.and()
.csrf().disable();
// #formatter:on
}
}
}
Finally found the issue after several hours. In the new api security configuration I didn't disable csrf and wasn't sending a token. Once I disabled csrf it worked as expected.
#Configuration
#Order(1)
public static class ApiLoginWebSecurityConfigurationAdapter extends
WebSecurityConfigurerAdapter {
#Autowired
private Http403ForbiddenEntryPoint forbiddenEntryPoint;
#Bean
public Http403ForbiddenEntryPoint forbiddenEntryPoint() {
return new Http403ForbiddenEntryPoint();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.httpBasic()
.authenticationEntryPoint(forbiddenEntryPoint)
.and()
.csrf().disable();
// #formatter:on
}
}