I am trying to set up the rules for spring boot to allow/deny access for specific paths. I looked up various examples and stack overflow question, but none was helpful. I created the configuration file as follows:
package xyz.blackmonster.window.configs;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
#EnableWebSecurity
#Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${admin.console.username:admin}")
private String username;
#Value("${admin.console.password:admin}")
private String password;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(username)
.password(passwordEncoder().encode(password)).roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/assets/**", "/api/order/calculate", "/api/order/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/login.html")
.defaultSuccessUrl("/admin/orders.html")
.failureUrl("/login.html?error=true")
.and()
.logout().logoutSuccessUrl("/");
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I can access the "/" without a problem. The page is loaded and show with the help of the MVC controller. But the paths that I defined as REST end points, I am not able to access them. I keep getting a 403 response:
{"timestamp":"2018-10-08T19:22:04.963+0000","status":403,"error":"Forbidden","message":"Forbidden","path":"/api/order/calculate"}
What is wrong with my configuration? As you can see from the class, I even went one further and specifically set the calculate end point as oppose to having the ** to include all subpaths.
If "/" is working and "/api/order/calculate" is not, it means that they have different HTTP verbs.
"/" - is a GET request
"/api/order/calculate" - is a POST request
By default, spring security will enable csrf protection (only for POST because GET is considered safe). If you are getting 403, it means that you are not sending csrf header => your access is forbidden.
You said that this is a REST endpoint, so you should disable csrf for this endpoints. To do that, please update your configuration with:
1.disable csrf in general (not recommended if you have web forms)
http.csrf()
.disable();
2.if you need to ignore csrf only for specific endpoints, you can add:
http.csrf()
.ignoringAntMatchers("/api/order/calculate")
Related
I got the task to implement jwks on the project. On our project, we have implemented a token validation check with oauth2. We use a jks format certificate to obtain a public key. the private key is not used in our project, since we need to check the validity of the token. Our goal is to get rid of the .jks file.
There are too few resources for jwks and therefore some points are not clear.
If I understand correctly, then jwks mean that there is a jwks.json file in the resources with keys inside, which we select by kid from the token header. Based on the documentation, it is not clear what kind of file it is and how it is loaded for checking by kid, that is, at what moment it happens.Does anyone have a project that can be used as an example? thanks in advance
https://docs.spring.io/spring-security-oauth2-boot/docs/2.2.x-SNAPSHOT/reference/html/boot-features-security-oauth2-authorization-server.html
You can use spring-boot resource server implementation.
First, what you need is to add the following dependency to your project
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
Second, you need to add an authentication server configuration. The JSON file that you mentioned has to be located on the authentication server or you can use JWKs URL of the authentication server.
You should have a configuration in your properties file like this.
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https:/example.com/.well-known/openid-configuration/jwks
spring.security.oauth2.resourceserver.jwt.issuer-uri=https:/example.com
Finally, you need to follow the natural spring-security API configuration. What you need is like the following.
#Configuration
#EnableWebSecurity
public class SecureSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
private String jwtSetUri;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requiresChannel().anyRequest().requiresInsecure().and().cors()
.and().csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "some path1").permitAll()
.antMatchers(HttpMethod.POST, "some path2").permitAll()
.antMatchers(HttpMethod.GET, "some path3").permitAll()
.antMatchers("/**").hasAuthority("some scope") // if you need this scope.
.anyRequest()
.authenticated()
.and()
.oauth2ResourceServer()
.jwt().decoder(jwtDecoder());
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
config.addAllowedMethod("PUT");
config.addAllowedMethod("DELETE");
source.registerCorsConfiguration("/**", config);
return source;
}
private JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withJwkSetUri(jwtSetUri)
.jwtProcessorCustomizer(p -> p.setJWSTypeVerifier(
new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("at+jwt")))).build();
}
}
After this, each request to your APIs should be verified automatically by the Spring by using the authentication server.
I made a project like this sample. So the controllers are like this
package mypackagename.controller;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
#RestController
#RequestMapping("/")
public class StoresRestController {
#RequestMapping(method = RequestMethod.GET)
public String stores() {
return ...
}
}
I like to handle all throwables and make my customized unified response. The problem is I cannot find a guide or a sample to do this correctly.
First of all, I tried ExceptionHandler, with Throwable, but it didn't work, so I decided to move on. Then, the most close approach that I found is this, so I tried jersey, by adding something like this. But it's not working for all throwables. Also, it's ignoring my controllers, by complaining
o.g.jersey.internal.inject.Providers : A provider mypackagename.controller.StoresRestController registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider mypackagename.controller.StoresRestController will be ignored.
I searched for this error and found this, which I'm not using ContainerResponseFilter in my project as I provided the sample above. So I'm clueless. The main problem is how to handle all throwables, but if you can give me some suggestions about how to solve Providers problem, I'll be so appreciated.
In my project I use #ControllerAdvice to handle my exceptions. Here's an example. Hope this helps. Just make sure this class is on your component scan so it gets picked up.
#RestController
#ControllerAdvice
public class StoresExceptionHandler {
#ExceptionHandler(Throwable.class)
public ResponseEntity<Object> handleThrowable(final Throwable ex) {
return new ResponseEntity<Object>("Unable to process request.", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Finally this post helped me to handle all Throwables, except authentication exceptions. The important part was to use #EnableWebMvc and ResponseEntityExceptionHandler. To handle authentication exceptions I used this answer. Hope it's helping someone.
as #carlos-cook said, you could use a #ControllerAdvice and, ProblemDetail defined in RFC 7807 which could look like:
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
#ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(RuntimeException.class)
public ProblemDetail handleUnexpectedException(RuntimeException rte, WebRequest wr) {
ProblemDetail pd = this.createProblemDetail(HttpStatus.INTERNAL_SERVER_ERROR, rte);
pd.setType(URI.create("http://your-site.com/internal-server-error"));
pd.setTitle("Internal server error");
return pd;
}
#ExceptionHandler(YourCustomeException.class)
public ProblemDetail handleUnexpectedException(YourCustomException rte, WebRequest wr) {
ProblemDetail pd = this.createProblemDetail(HttpStatus.INTERNAL_SERVER_ERROR, rte);
pd.setType(URI.create("http://your-site.com/custom-error-page"));
pd.setTitle("Internal server error");
return pd;
}
}
Then in your controller you could simply throw YourCustomException
This controller advice will handle every exception and YourCustomException separately.
when I config spring security like this
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Bean
public UserDetailsService userDetailsService(){
return new MyUserDetailsService();
}
#Bean
public MyAuthenticationProvider myAuthenticationProvider(){
MyAuthenticationProvider provider = new MyAuthenticationProvider();
provider.setUserDetailsService(userDetailsService());
return provider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll();
}
}
and then I config my controller like this
#GetMapping("/login")
public String showLoginPage(){
System.out.println("GetMapping");
return "login";
}
#PostMapping("/login")
public void authUser(#RequestParam String username,#RequestParam String password){
// just for testing
System.out.println("PostMapping");
}
and then I visit my login page and enter my username and password, but the console doesn't print "PostMapping", which means the program doesn't go into my method "authUser" with #PostMapping.
Though my program runs successfully, but it makes me quite confuse.I suppose spring security doing some work automatically, but now I have no idea where to add my Authentications to the SecurityContextHolder.
I hope somebody can help and thanks very much
It has done by UsernamePasswordAuthenticationFilter, and the default processing path is Post /login, and the Authentication already exist in SecurityContextHolder, you can get it in controller.
If you want to disable form login, change to this.
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated().and()
.formLogin().disable();
Normally, POST mappings are filtered by CSRFfilters. Although it is not recommended in the production environment, you can disable CSRF filter simply using for learning cases:
http.authorizeRequests().anyRequest().authenticated().and().httpBasic()
.and().logout()
.and().csrf().disable();
I look spring web site and want to prevent my website form xss and xframe attack
But My english is not well enough to figure out what to set
Please guide me what else should I setting??
I just add a WebSecurityConfig.java under src/com/test/web/security
Here is my code :
package com.test.web.security;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#EnableWebSecurity
#Configuration
#ComponentScan
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.headers();
}
}
If you just specify the same code that you have above, Spring Security should automatically add all of the relevant security headers. Per the docs:
If you are using Spring Security’s Java configuration, all of the
default security headers are added by default.
Also:
As soon as you specify any headers that should be included, then only
those headers will be include
See details and code samples in this section:
http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/reference/htmlsingle/#default-security-headers
I need to set up global basic HTTP authentication for a staging server. Nothing fancy. I just want to require username/password to access anything. I also would like to use only Java config. I've experimented with a lot of different solutions, but none of them working. I'm always able to access all resources on the server. This is what I'm doing now:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("Configuring HttpSecurity");
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("Configuring global AuthenticationManagerBuilder");
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
I can see in the logs that these snippets are being executed. As you can see, in the first method, I am requiring that all requests are authenticated. In the second method, I am specifying in memory authentication.
Your SOP statements are getting printed (while container instantiation) because of #Configuration (which is again not required as it is also declared by #EnableWebSecurity). You still need to register the spring security filter chain in your web.xml or MVC initializer class that extends WebMvcConfigurerAdapter or implements WebApplicationInitializer if you wish to use it with the application filter chain. For example (java config as you are looking for the same):
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(
DispatcherType.REQUEST, DispatcherType.ERROR);
container.addFilter("springSecurityFilterChain",
DelegatingFilterProxy.class).addMappingForUrlPatterns(
dispatcherTypes, false, "/*");
where container is an instance of ServletContext.