Our application is using spring security to secure the application,i just added one rest controller which supporting spring oauth security, for oauth token validation, will be called by some other application following are my controller code
#RestController
#EnableResourceServer
public class Controller extends BaseRestController{
#RequestMapping(value="/api/v1/public/insertData", method=RequestMethod.POST)
ResponseEntity<?> insertTPQueueData(TitleProcurementQueue queue,Authentication authentication) {
return null;
}
}
after adding spring oauth security i am getting following error for my other controller using spring security
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
Please help
When you put security in your project spring implement some filters, like Cors, basic auth etc..
So you need to tell spring how apply security in your resources.
enter link description here
need to create a class with #EnableWebSecurity
and configure like this:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.csrf().disable();
http.headers().frameOptions().sameOrigin();
}
Related
I am trying to debug a spring boot application secured behind AWS cognito.
I have set up the user pools and app config according to these tutorials:
https://www.baeldung.com/spring-security-oauth-cognito
https://www.czetsuyatech.com/2021/01/aws-generate-cognito-access-token.html
https://betterjavacode.com/programming/example-of-spring-boot-application-authentication-with-aws-cognito
I am only interested in programmatic REST access, not spring mvc.
Demo Controller:
#GetMapping(path = "/hello")
public ResponseEntity<String> hello() {
System.out.println("Hello");
return new ResponseEntity<>("Hello", HttpStatus.OK);
}
application.yml
spring:
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
security:
oauth2:
client:
registration:
cognito:
clientId: xxxxxx
clientSecret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
scope: openid
redirect-uri: http://localhost:8080/login/oauth2/code/cognito
clientName: w3p-app-client
provider:
cognito:
issuerUri: https://cognito-idp.us-east-1.amazonaws.com/us-east-1_zcZ0Enk0d
user-name-attribute: cognito:username
Security Config:
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.and()
.logout()
.logoutSuccessUrl("/");
}
}
And this works in a browser localhost:8080/hello. I get the cognito login page where I can sign in with a demo user created in the user pool. After that I get the text "Hello" in my browser as expected.
Now I wanted to setup a postman collection for testing my API:
"Get New Access Token" opens the cognito login where I can successfully sign in and obtain the token. However if I now try to acces my /hello, with inherited auth from the parent, I still get redirected to the cognito login every time, even though the token is sent along.
I have saved the collection and request, I have tried with and without bearer, enabled all options in cognito and whatnot. At this point I am out of ideas. Any hints would be appreciated. For some reason cognito does not redirect to my api as in the browser, but send the login page instead. It seems like any auth setting is completely ignored, same behavior with "no auth" selected.
In your case your service is in the role of a resource server. In the context of OAuth2 a resource server is an application, which endpoints are secured via OAuth tokens.
The basic configuration to make this work would be:
Add the following dependencies in your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
In your application.yml:
spring:
security:
oauth2:
resourceserver:
jwt:
https://cognito-idp.us-east-1.amazonaws.com/us-east-1_zcZ0Enk0d
Your resource server will use this property to validate the incoming JWT tokens.
This is all you need in order to secure all your endpoints.
If you need to add any custom security configuration here is an example:
#Configuration
#EnableWebSecurity
public class CustomSecurityConfiguration {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(authorize -> authorize
.mvcMatchers("/my-public-endpoint").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.build();
}
}
You can find further information in the spring-security documentation
Here is also one tutorial
Your problem is in your SecurityConfiguration. You defined everything for anyRequest. You can use antMatchers to define authentication only for some request based on URL-path. Or you can give free access with permitAll to limited URLs by path with antMatchers. Here is an example how antMatchers can be used and how you can deal with all remaining (anyRequest) URL-paths.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/needToken").authenticated()
.anyRequest().permitAll();
}
I have a spring restful application, backend - Spring 2.4.3, frontend - Angular, when I trying to restrict access to individual pages, I get 401 code. I've tried all variations of hasRole () and hasAuthority () nothing helps. What am I doing wrong?
SecurityConfig.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/login", "/registration").permitAll()
.antMatchers("/profile","/profile/*").hasAnyAuthority("USER","ADMIN","INTERVIEWER")
.antMatchers("/getAllUsers").permitAll()
.anyRequest().authenticated();
http
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
/*.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class)*/
.cors();
}
Role.java
#XmlType
#XmlEnum
public enum Role implements GrantedAuthority {
ADMIN,
USER,
INTERVIEWER;
#Override
public String getAuthority() {
return this.name();
}
}
Result:
something wrong :(
Based on your provided code, the line .addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class) is commented out. I can't speak to what happens when you un-comment that line (since it is a custom filter), but without that line, you have no means of authenticating. This results in your entry point (which is not provided in your example) being invoked, and seems to be returning your 401 status code.
You can test this by commenting out the lines:
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
and adding .formLogin().and() instead. Form Login will provide a default authentication entry point, default authentication filter, and (if using spring boot) default user details service with a randomly generated password printed to your console, which you can use to test logging in. See the docs for more info on this.
A note on testing with hello world (out of the box) configuration: It is a very useful technique to use formLogin() for testing authorization rules (e.g. .antMatchers("/profile","/profile/*").hasAnyAuthority("USER","ADMIN","INTERVIEWER")) in Spring Security. It allows you to eliminate your authentication mechanism from being the problem. Once you are confident your authorization rules are working, you can move on to configuring your own authentication scheme. When possible, seek to utilize an existing scheme provided by Spring Security, and only create a custom filter when you cannot use an out of the box scheme. You can read about JWT authentication in the docs.
I know there is a lot of questions like this, but I could not find an answer which solves my case.
Here is my config:
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.POST, "/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.logout().permitAll();
}
}
And here is my endpoint I want users to have access without logging in:
#Slf4j
#RestController
public class MyController {
#PostMapping(value = "/", consumes = MediaType.TEXT_PLAIN_VALUE)
public void acceptAnonymously(HttpEntity<String> requestEntity) {
log.debug("body: {}", requestEntity.getBody());
}
}
So basically, I want to allow making unauthenticated POST requests to localhost:8080. Everything else should be authenticated. But when I hit localhost:8080 with postman, this is what I get:
So, CSRF stands for Cross-Site Request Forgery and I believe is enabled by default with Spring Web/Security. When it is enabled, you need to properly pass the correct csrf token to your app in order to access your application otherwise you will get thrown a 403 forbidden type error. Alternatively, there are other means of authenticating users if you so desired.
.csrf().disable()
Actually disabling CSRF is not a good idea for all situations. CSRF is enabled by default and as a result, the CSRF token is added to the HttpServletRequest attribute named _csrf. So you only need to add it to your requests.
If you are using Thymeleaf for your html templates you could add something like this to your forms:
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
I have been trying to configure Spring Boot security in order to allow some urls without requiring an authentication and not allowing any other requests without an authentication. I am having trouble achieving this.
As per my understanding, anyRequest().authenticated() requires previously declared antMatchers to require authentication.
How is it possible to achieve my requirement.
My Http Security configuration
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.antMatchers(HttpMethod.POST,SIGN_UP_URL).permitAll()
.antMatchers(HttpMethod.GET,banner_top_url).permitAll()
.antMatchers(HttpMethod.GET,banner_bottom_url).permitAll()
.antMatchers(HttpMethod.GET,javascript_url).permitAll()
.antMatchers(HttpMethod.GET,stylesheet_url).permitAll()
.antMatchers(HttpMethod.GET,photos_url).permitAll()
.antMatchers(HttpMethod.GET,transformed_photos_url).permitAll()
.antMatchers(HttpMethod.GET,preview_url).permitAll()
.antMatchers(HttpMethod.GET, "/", "/**/*.html", "/static/favicon.ico", "/**/*.js", "/**/*.js.map", "/**/*.css", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/**/*.ttf", "/**/*.json", "/**/*.woff", "/**/*.woff2", "/**/*.eot", "/**/*.svg").permitAll()// allows static content from resource folder
.antMatchers("/error").permitAll() // By default Security framework disables error pages (Unauthrorized)
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and().addFilterBefore(jwtExceptionHandler,CorsFilter.class)
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().formLogin().disable();
}
I assume that the below urls must be granted access without authentication.
SIGN_UP_URL
banner_top_url
banner_bottom_url
javascript_url
stylesheet_url
photos_url
transformed_photos_url
preview_url
The problem is this line : .anyRequest().authenticated()
If I remove it, then all the endpoints within the REST interface becomes available without authentication which I do not want.
Why aren't you excluding the static resource files globally via web.ignoring?
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
By default, Spring-security allows to pass everything. You have to tell Spring what can pass and what cannot pass. By removing anyRequest().authenticated you are telling to spring that everything that matches the patterns you mentioned are allowed to go and with the rest do what you do by default, that means, proceed. Here you are Spring Security doc: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc-httpsecurity
I have found that Spring-Working as intended. That being said,any antMAtchers will match the requestPath and not the resourcePath. An example is provided below.
*localhost:8080/image.jpg*
points at the root of the application which is src/main/resources/static/image.jpg
Now why is static used as a resource handler, that is because in the staticResourceConfiguration.java class I had the following lines
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
I'm developing an android app and I'm using Spring as a REST backend.
Every time I try to make post request to the server I get a 403 response with this message "Expected CSRF token not found. Has your session expired?".
I tried to disable csrf in the application.properties and with my own WebSecurityConfigurerAdapter implementation but to no avail.
Did I miss something ?
Try this :
.invalidateHttpSession(true)
.and()
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and()
.csrf()//Disabled CSRF protection
.disable();
Add this on your logoutSuccessHandler(...)
There are different ways to disable CSRF in Spring boot , by default in spring boot is enable
1. By Java Configuration
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
2. By Application.yml
security.enable-csrf: false