I am working on a RestAPI endpoint for generating random values with Spring Boot and Bouncy Castle.
I also have basic Spring Security activated.
When i make a GET request with the right credentials, everything works fine and the random value gets returned, but if i change it to PostMapping with the exact same underlying code and make a POST request - i get an unauthorized response, even tho the credentials are right.
I am using Insomnia for making HTTP requests.
Has anyone experienced something similar and knows how to fix it?
Creating a Configuration Class for Spring Security solved the problem.
The following code worked:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.csrf().disable();
return http.build();
}
}
Related
I am developing RESTfull API for BFF(Bridge for front-end) application using Spring boot.
In my application it is not required to do any Authorization/Authentication and the only thing that i should do is to pass the JWT token from Authorization header to the HTTP client that calls another API. My goal was not to grant access to the endpoints of my application for the requests that don't contain Authorization header with token.
I reached my goal using the next config in WebSecurityConfigurerAdapter
#Configuration
#Order(1)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
.requestMatcher(new RequestHeaderRequestMatcher("Authorization"))
.authorizeRequests()
.antMatchers("/**").permitAll();
}
}
This configuration seems like working as needed but I get the empty response body if i don't provide the token in Authorization header:
Response image
Is it possible to configure somehow Spring Security to throw an exception and handle it with #ExceptionHandler in #ControllerAdvice or somewhere else to return the custom JSON object with error?
I am really new with Spring Security so please tell me if my configuration in WebSecurityConfigurerAdapter is not good enough for my purposes.
I'm using Spring Boot 2.2.0.RELEASE to build my REST api.
I've managed to customize the 500/400/404 error pages (if somebody navigates with a browser) with thymeleaf and putting the files in:
src/main/resources/templates/error.html
src/main/resources/templates/errors/400.html
src/main/resources/templates/errors/404.html
All this works fine.
I noticed however, when somebody navigates to say /myrestapi in a browser, they get a 401 error. By default in Spring they would get a 403 error, but I have overridden that behavior to make it all 401s:
#Override
protected void configure(HttpSecurity http) throws Exception {
// return HTTP 401 instead of HTTP 403 for unauthorized requests
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());
}
private AuthenticationEntryPoint authenticationEntryPoint() {
BasicAuthenticationEntryPoint basicAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthenticationEntryPoint.setRealmName("Bearer realm=\"oauth2-resource\"");
return basicAuthenticationEntryPoint;
}
So I added:
src/main/resources/templates/errors/401.html
This doesn't seem to be getting picked up and when I go to the browser, it shows XML:
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
When I go to that URL through Fiddler, it gives me Json, but I want the human to get my custom 401 page. I found some documentation that I need to do this:
WebSecurityConfig.java:
http.exceptionHandling().accessDeniedPage("/resources/templates/errors/401.html")
.authenticationEntryPoint(authenticationEntryPoint());
My ResourceServerConfig.java looks like this:
#Override
public void configure(HttpSecurity http) throws Exception {
// default behavior is to allow anonymous access unless #PreAuthorize is specified
http.exceptionHandling().accessDeniedPage("/resources/templates/errors/401.html").and().authorizeRequests().anyRequest()
.permitAll();
}
But that doesn't work either.
Am I missing something?
NOTE: I am letting all requests through with permitAll() and then control OAuth access at the METHOD LEVEL using #PreAuthorize. But I also tried removing the permitAll() and its still not hitting.
Also tried the accessDeniedHandler and that doesn't work either.
Looks like your path is wrong.
It should be /resources/templates/errors/401.html
I'm creating a new Spring REST application with some basic services and entities.
I added Spring Security and without overriding any class, i just added to application.properties a user and password.
So far so good, i opened Postman to try out a endpoint and it always return 401 to my requests.
I tried in postman set the authorization via "Basic Auth" (is what header WWW-Authenticate asks), tried "Digest auth" using the "Realm" value from the header. But none of it works.
Here is what i have in my application.properties
spring.security.user.name=root
spring.security.user.password=root
This is my request
https://imgur.com/URM3TGD
(Sorry i can't embbed the image because of my reputation)
And here is the endpoint
#PostMapping("saveUsuario")
public Usuario saveUsuario(Usuario usuario) {
return usuarioRepository.save(usuario);
}
(If possible) i don't want to override any Spring Security class, just "use as it".
Thank you!
So here is what i found.
Thanks to #jzheaux we discover that the problem was with the csrf configuration (Using POST request).
So i was forced to override the class WebSecurityConfigurerAdapter to disable it.
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
But then, the endpoints could be called without authentication!
So, this is the final code:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.cors();
http.authorizeRequests().anyRequest().fullyAuthenticated();
http.httpBasic();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
}
}
First disable the CSRF.
Then enable Cors.
I set that i want any request to be fully authenticated
The challenge type is HTTP basic
I disable the creation of cookies so it'll always ask for credentials.
So far so good, it's working!
Per https://docs.spring.io/spring-boot/docs/1.5.0.RELEASE/reference/htmlsingle/#boot-features-security
you should change your password with
security.user.password=root
instead of spring.security.user.password=root
similar security properties that are overridable are in the #ConfigurationProperties class: SecurityProperties.java
See https://github.com/spring-projects/spring-boot/blob/v1.5.0.RELEASE/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java
I'm having trouble upgrading Spring Boot from 1.1.12 to 1.2.5 but have the same issue in all versions of 1.2.x. The /health endpoint provided by Actuator is now returning 401 Unauthorized to an integration test that used to work. No code has changed while upgrading the dependency.
Here's the test case:
#Test
public void testNoUserForStatusEndpoint() throws Exception {
HttpEntity<String> entity = new HttpEntity<>(null, headers);
ResponseEntity<String> response = template
.exchange(base + "/health", HttpMethod.GET, entity, String.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("{\"status\":\"UP\"}", response.getBody());
}
I expect to see the basic "UP" status but no further details as the user is anonymous and not authenticated.
Setting management.security.enabled=false in application.properties causes the endpoint to return the complete health information. This is not desirable.
Setting endpoints.health.sensitive=false does nothing.
The security configuration has not changed. It is based on Apache termination and a certificate whitelist, which also hasn't changed.
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.addFilterBefore(new CustomAuthenticationFilter(authenticationManager(), Environment.getUserWhitelist()), BasicAuthenticationFilter.class);
}
How can I make the test pass?
Updates:
Originally the only relevant setting in application.properties that was defined is endpoints.health.enabled=true.
Adding management.health.status.order=UP,DOWN,OUT_OF_SERVICE,UNKNOWN to application.properties makes no difference.
Using all three properties results in a 401 (doesn't work):
endpoints.health.enabled=true
endpoints.health.sensitive=false
management.health.status.order=UP,DOWN,OUT_OF_SERVICE,UNKNOWN
The main class is just a stripped down Spring Boot application launcher:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I have tried adding http.authorizeRequests().antMatchers("/health**").permitAll(); to the first line of the security configuration method detailed above. It did not make a difference.
According to Spring Boot issue 2120, The endpoints.health.sensitive property is ignored when using custom security. I found no mention of this in the documentation.
Or add management.security.enabled=false
to the application.properties
I have found a solution.
Adding #Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) to my custom authentication filter (referred to as CustomAuthenticationFilter in the question) changes the semantics of defining a security filter bean.
Without the annotation, Spring Boot assumes I want to override all the filters and just use my custom filter in isolation.
With the annotation, Spring Boot adds my filter to the list of predefined filters. This allows the /health endpoint to work again.
See Spring Boot issue 2120 on GitHub for details.
I was getting 404 error with /health url. However its worked with /actuator/health url instead of /health.
Pls try this on the application.properties or application.yml :-
management.health.status.order=UP,DOWN,OUT_OF_SERVICE,UNKNOWN
I am writing an LTI application using Spring boot. LTI applications are basically a plug-in for a learning management system (in this case Canvas) which work by sending an Oauth1 signed POST to my server. The result of this request is displayed to the user inside of an iframe. There is a pre-shared key and secret that the LMS uses to sign the request. If the signature on the POST checks out, I have an authenticated user. I have this part working, partially based on this question.
During the initial request (which comes to the URL "/launch") I can call SecurityContextHolder.getContext().getAuthentication() and use this without problems. My problem is when the user makes another request, say for a picture or by clicking on a link in my content, the SecurityContext object isn't following them. I'm pretty sure I'm not setting up the Spring security filter chain correctly so the SecurityContextPersistenceFilter isn't being hit on subsequent requests. At the end of the day, SecurityContextHolder.getContext().getAuthentication() returns null.
The OAuth signature verification happens in a WebSecurityConfigurerAdapter like so: (again, based on this)
#Configuration
public static class OAuthSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
//spring auto-wiring to set up the
//zeroLeggedOauthProviderProcessingFilter (see linked question)
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/launch")
.addFilterBefore(zeroLeggedOAuthProviderProcessingFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests().anyRequest().hasRole("OAUTH")
.and().csrf().disable();
}
}
So this works and creates an authenticated principal and everything. But due to that antMatcher, it only applies to the /launch path.
It seems like it should be simple to add another security configurer adapter that will ensure that all other paths in the application are protected by an authenticated session and in so doing would cause the SecurityContext associated with this user to become available but I have been unable to come up with the magic sauce. The documentation focuses more on standard login form based authentication setups. I'm also kind of new to Spring in general so I'm clearly missing something. I tried this but it causes all other requests to return a 403:
#Configuration
public static class SessionSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().hasRole("OAUTH")
.and().csrf().disable();
}
}