I am using zuul proxy for routes and have added JWT authentication for the same. I have specified the APIs for with authorisation is to be skipped for example (/auth) but i am not able to call the same as I am getting 401 for the permitted URLs as well.
Following are the code snippet.
Class implementing WebSecurityConfigurerAdapter
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint(new JwtAuthenticationEntryPoint())
.and()
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/auth/**").permitAll()
.antMatchers("/ping").permitAll()
.antMatchers("/login/**").permitAll()
.antMatchers("/signup/**").permitAll()
.anyRequest().authenticated();
}
And also my application.properties file looks as mentioned below
server.port=8762
spring.application.name=zuul-server
eureka.client.service-url.default-zone=http://localhost:8761/eureka/
# A prefix that can added to beginning of all requests.
zuul.prefix=/api
# Disable accessing services using service name (i.e. gallery-service).
# They should be only accessed through the path defined below.
zuul.ignored-services=*
# Map paths to services
zuul.routes.user-service.path=/users/**
zuul.routes.user-service.service-id=user-service
zuul.routes.user-service.sensitive-headers=Cookie,Set-Cookie
# Map path to auth service
zuul.routes.auth-service.path=/auth/**
zuul.routes.auth-service.service-id=auth-service
zuul.routes.auth-service.strip-prefix=false
# Exclude authorization from sensitive headers
zuul.routes.auth-service.sensitive-headers=Cookie,Set-Cookie
But I am not able to hit /ping or /login or /auth APIs all are giving 401.
Could someone please help me regarding the same.
Thanks in advance !!!
try this
.antMatchers(HttpMethod.POST, "/api/auth/**").permitAll()
Related
When I configure my security like that:
httpSecurity
.anonymous()
.and()
.authorizeRequests()
.antMatchers("/**/mes-actus/**").authenticated()
.anyRequest().permitAll()
.and()
// make sure we use stateless session; session won't be used to
// store user's state.
.addFilterBefore(headerUserRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
it authenticates only routes that contains mes-actus and permit all others, that good!
But when I add this instruction: .cors().and().csrf().disable() then it demands authentication for all without exception.
In other words .antMatchers("/**/mes-actus/**").authenticated() is ignored.
if i remove .cors().and().csrf().disable() i got 403 forbidden
Can you try the code below: it allows all /**/mes-actus/** calls:
http
.authorizeRequests()
.antMatchers("/**/mes-actus/**").permitAll()
.anyRequest().authenticated();
http
.csrf().disable()
.cors().disable();
I have the following code
http.authorizeRequests()
.antMatchers("/users/login","/token/refresh").permitAll()
.anyRequest().authenticated()
.and()
.addFilterAfter(new JWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
And I thought it mean do not filter requests that match /users/login or /token/refresh, but filter any request that doesn't match that.
But it still filters on /users/login.
The way I solved in an old project is requiring auth on every endpoint
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterAfter(new JWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
and ignoring security on the desired endpoints
public void configure(WebSecurity web) {
web.ignoring().antMatchers(HttpMethod.POST, "/users/login");
}
Try this.
.antMatchers("/users/login").permitAll()
.antMatchers("/token/refresh").permitAll()
csrf is enabled by Spring Security automatically. Try disabling it.
http.csrf().disable().authorizeRequests().antMatchers("/users/login","/token/refresh").permitAll().anyRequest().authenticated().and().addFilterAfter(new JWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
I am using Spring security library to secure REST apis in my application, I am trying now to allow access to all URLs (temporarily) but with the below configuration I find that only GET requests are allowed but not the POST requests (where I get 403 forbidden response), I understand that the first antmatcher below should allow both GET & POST but actually the 2 antMatchers couldn't allow POST
Can someone please advise me on what I am missing here?
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// first I have tried only this antMatcher
.antMatchers("/**").permitAll()
// But then it didn't allow POST even when only using the line below
.antMatchers(HttpMethod.POST, "/**").permitAll()
}
After some investigation, it turned out that antMatcher was working as expected & allowing all URLs as intended, but the reason for the forbidden response that I was getting for the POST APIs was that Spring security was waiting for csrf token for these POST requests because CSRF protection is enabled by default in spring security.
So in order to make it work like this, you must provide the csrf token in POST request OR you can temporarily turn CSRF protection off (but you should enable it again before going to production as this is a serious attack)
Example code for that:
protected void configure(HttpSecurity http) throws Exception {
http
// disabling csrf here, you should enable it before using in production
.csrf().disable()
.authorizeRequests()
// this matcher is working for all GET/POST/... , any URL matching the reg expression
.antMatchers("/**").permitAll()
}
As stated by the Questioner in your own reply, the 403 forbidden error could be caused by the CSRF protection. But instead of disable this protection, you can except some AntMatchers like this:
http
(...) // oculted for brevity
.and()
.csrf()
.ignoringAntMatchers("/api/a", "/api/b")
You need to do something similar this and you should mention role
http
.httpBasic().and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/employees").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/employees/**").hasRole("ADMIN")
Hope it will solve your issue.
I created an API that provides User authentication and it's login operation is handled on default '/login' path by Spring Security.
I want to change this path to 'api/v1/login'.
this is my security config :
http.cors().and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/h2-console/**/**").permitAll()
.antMatchers(HttpMethod.POST,"/user/register").permitAll()
.antMatchers("/user/activate").permitAll()
.antMatchers("/user/reset-password").permitAll()
.antMatchers("/user/reset-password").permitAll()
.antMatchers("/admin/user").hasRole("ADMIN")
.antMatchers("/roles").permitAll()
.antMatchers("/user/**").hasRole("USER")
.and()
.formLogin().loginProcessingUrl("/api/v1/login")
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.addFilterBefore(new ExceptionHandlerFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtUserDetailService));
I have added this line to change it :
.formLogin().loginProcessingUrl("/api/v1/login")
But it is still working under '/login' path.
"/api/v1/login" return 404.
Is there any way to change it ?
Spring Boot Version : 2.0.0.RELEASE
The function .loginProcessingUrl("/api/v1/login"), specifies the URL to validate the credentials, the URL to validate username and password.
It will only override url to /api/v1/login of POST type, not GET
It will not pass the request to Spring MVC and your controller
For additional customization you can have a look through FormLoginConfigurer
UPDATE v1
Can you also check if your urls under /api/** are all secured?
If yes then try removing the security from /api/v1/login and add permitAll() configuration to this url
Check this post - https://stackoverflow.com/a/27471722/2600196. if it helps your scenario
UPDATE v2 - this helped in the case here
you were not sending the username and password correctly and for that to work refer the things below, in your it was showing up BadCredentialsException. I enabled debug on the application and was able to figure that out.
you need to post the parameters to the url - http://localhost:8080/api/v1/login as below (have also attached the image, screenshot of postman):-
headers:
Content-Type=application/x-www-form-urlencoded
parameters in key value pairs(not in json format, please refer the image):
username=player3
password=pass3
Above you can the response coming up from the index.html like below:-
test static resource
Which you also need to customize.
For Sending the JSON request for username and password, the changes that will work easily for you will be:-
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/h2-console/**/**").permitAll()
.antMatchers(HttpMethod.POST,"/user/register").permitAll()
.antMatchers("/user/activate").permitAll()
.antMatchers("/user/reset-password").permitAll()
.antMatchers("/user/reset-password").permitAll()
.antMatchers("/admin/user").hasRole("ADMIN")
.antMatchers("/roles").permitAll()
.antMatchers("/user/**").hasRole("USER")
//.and()
//.formLogin().loginProcessingUrl("/api/v1/login") // not required any more
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.addFilterBefore(new ExceptionHandlerFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilter(jwtAuthorizationFilter())
.addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtUserDetailService));
http.headers().frameOptions().disable(); // its required for h2-console
}
public JwtAuthenticationFilter jwtAuthorizationFilter() throws Exception {
JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager());
jwtAuthenticationFilter.setFilterProcessesUrl("/api/v1/login");
return jwtAuthenticationFilter;
}
And the code .formLogin().loginProcessingUrl("/api/v1/login") not required anymore
Further you need to add the success and the failure urls to the application, and to make your login url to fetch json based user credentials, you need to follow up and need to do some more stuff, some useful reference for that - https://stackoverflow.com/a/19501060/2600196
You are extending org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter which itself extendsorg.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter. In this last class, there is a setter called
setFilterProcessesUrl
which is intended to do just this:
setFilterProcessesUrl
public void setFilterProcessesUrl(String filterProcessesUrl)
Sets the URL that determines if authentication is required
Parameters: filterProcessesUrl
This is the link to that javadoc section
So in your WebSecurityConfigurerAdapter you could do just like this:
#Bean
public JWTAuthenticationFilter getJWTAuthenticationFilter() {
final JWTAuthenticationFilter filter = new JWTAuthenticationFilter(authenticationManager());
filter.setFilterProcessesUrl("/api/auth/login");
return filter;
}
And then in your configure method in the same class just reference it instead of creating new instance:
.addFilter(getJWTAuthenticationFilter
I'm trying to implement an Angular app using this tutorial: https://spring.io/guides/tutorials/spring-security-and-angular-js/
Logging in works and performing subsequent HTTP calls works, too. Angular successfully appends the CSRF token and Spring successfully parses it. Assuming the token is foo, the requests will contain these headers:
Cookie: JSESSIONID=...; XSRF-TOKEN=foo
X-XSRF-TOKEN: foo
Now, when trying to log out with
$http.post('logout', {}), Angular will use exactly the same headers. However, Spring answers with a 403:
Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
This is what my security configuration looks like:
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated().and()
.logout().and()
.addFilterBefore(new CsrfHeaderFilter(), CsrfFilter.class);
}
CsrfHeaderFilter is the class explained in the tutorial (which apparently works for every other request).
I realize it's 2 months late, but I was following the exact same guide today and this unanswered post keeps on popping up so here's the solution.
Basically, you were missing the csrfTokenRepository() configuration in the HttpSecurity configurer.
Spring CsrfTokenRepository expects the header "X-CSRF-TOKEN" but Angular sends the token in a header called "X-XSRF-TOKEN" so the guide recommended you setup an instance of CsrfTokenRepository which expects the Angular default header "X-XSRF-TOKEN":
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated().and()
.logout()
.and()
//This is the first part you were missing
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterBefore(new CsrfHeaderFilter(), CsrfFilter.class);
}
#Bean
public CsrfTokenRepository csrfTokenRepository(){
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
// This is the second part you were missing
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}