I am new to Spring Security. We are using Spring Security 5.4.5 with Spring Boot in one of my sample examples.
I have below config class in which am trying to apply the Spring Security authentication/authorization in /user and /admin endpoints of the REST API.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
PasswordEncoder bcryptPasswordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().principal("guest").authorities("GUEST_ROLE")//Provide the name and role to the annonymous user
.and()
.authorizeRequests()
.antMatchers("/register").anonymous()//allows registration page to be accessed by annonymous users only
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET,"/admin").hasAnyRole("ADMIN_ROLE")
.antMatchers(HttpMethod.GET,"/user").hasAnyRole("STUDENT_ROLE", "ADMIN_ROLE")
.and()
.httpBasic();
}
#Override
#Bean
protected UserDetailsService userDetailsService() {
UserDetails annaSmithUserDetails = User.builder()
.username("annasmith")
.password(bcryptPasswordEncoder.encode("password"))//default password enoder is bcrypt
.roles("STUDENT_ROLE", "ADMIN_ROLE") //role of the user
.authorities("STUDENT_READ","STUDENT_WRITE","COURSE_READ","COURSE_WRITE") //authorities or we can say permission assigned to the user
.build();
return new InMemoryUserDetailsManager(annaSmithUserDetails);//can configure different
}
}
As per the above Spring configuration /user will be accessible to both the USER and ADMIN role and /admin will be accessible to the ADMIN role.
When am trying to access /user in the browser it displays the username and password popup and once I enter the correct credentials of the configured user it is not working and gives the 403 error.
I have below three questions
Am not seeing any error in the console log and is there a way I can see why Spring Security is showing the 403 error?
What is the issue with the above Spring Security configuration as I am not able to access the REST API endpoints?
Am not seeing any error in the console log and is there a way I can see why spring security is showing the 403 error?
By enabling spring debug logs, how to do this can be done with a simple google search or found in the spring documentation. Learn to debug your application (debugging your application should always be the first thing you learn and should be done before asking on stack overflow).
What is the issue with the above spring security configuration as I am not able to access the REST API endpoints?
Could be several issues since you have not disclosed how you are accessing the application. By curl, web browser, another webclient using fetch in a react application etc. etc. Should also be included when you ask on stack overflow so that people can be able to reproduce the issue at hand.
But listing some of the things that can be wrong:
Your request is done improperly
Your password might not be correct, because i see you are encrypting your password incorrectly (see the documentation of how to actually do it)
ensure your password is stored with the correct prefix, or use UserBuilder users = User.withDefaultPasswordEncoder(); when building your user as in the docs.
Roles should be defined without prefixes or suffixes (_ROLE) if to follow any standard
after you are logged in are you redirected to something you are not allowed to access?
As you can see there are several things that can be wrong, but you have provided too little information to be able to answer, and there is a lot of things you can do before asking on stack overflow.
The answer is vague since the question is vague.
Related
I am trying out the new Spring Authorization Server, and I have hit a dead end in my endless googling.
Without the #Secured and #EnableGlobalMethodSecurity configured, it works like a charm, but the moment I try to secure the resource server with the above annotations I now get a 403 Forbidden error.
Authorization Server Configuration
DefaultSecurityConfig.java
MongoDBUserDetailsService.java (User Detail Service)
The roles are in the format of "ADMIN" without the prefix "ROLE_" since its already added during runtime.
Resource Server Configuration
ResourceServerConfig.java
ArticlesController.java
I kinda figured out a way to do it, which was to implement a custom converter for my jwt token, where I then can query the user and their roles from db using the claim from token and then injecting that to the request filter.
CustomJWTAuthenticationConverter
ResourceServer SecurityFilterChain
I'm trying to use create-react-app to start the frontend for my spring-boot project.
I use redis to store sessions.
For some reason I actually need to enable session generation for anonymous users.
The following code is my security config for spring boot:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
//#formatter:off
http
.formLogin()
.loginPage("/login")
.permitAll()
.loginProcessingUrl("/form-login")
.and()
.cors()
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/restricted/**")
.authenticated()
.antMatchers("/**")
.permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
//#formatter:on
}
}
I've tested this by having a very simple index.html inside the "static" folder under my spring-boot project. Then I go to "http://localhost:8080" and I saw the session cookie.
Then I removed "index.html" file and start the react app with proxy config. By default the new url is "http://localhost:3000". I do see the default reactjs startup page but I no longer get any session cookies.
My proxy setting in "package.json" for my create-react-app is as follows:
"proxy": "http://localhost:8080"
I also tested that I can still get session cookie only if I directly go to "http://localhost:8080" instead of port 3000.
Any help is appreciated. Thanks so much in advance.
Okay people, after waiting for a couple days without any answers I did some research myself and found the answer. I decided to post the answer here in case other people having the same issue.
The issue with create-react-app proxy is that it is a forward proxy. So the session cookie doesn't really work well with forward proxy. Sadly there is no easy solution solving this issue but there is a workaround.
As I mentioned above, I can for sure get the session cookie by directly accessing the backend url. So if I want to get the session cookie by using the proxy, I should put some code in the frontend to access the backend first and then put the session cookie in the header whenever the app starts. Then keep monitoring the frontend and reacquire the session whenever it expires.
For the best practice, the backend should really have a mock service which has no session, no login and no tokens but mocked data. Because the frontend doesn't really care about how session, access token or login works, these are the backend jobs. The frontend just need to get the data and then display the data.
But in reality having a mock server may take time and it is not worth doing that for every thing case.
So if you do not want to write the mock server, you either go with proxy but have a little hack in your frontend to actually acquire the session. Or you build the entire frontend app and put it under the "static" folder in your spring boot app.
For me I would rather separate the frontend and backend rather than putting them all together.
I have a REST service, built using Java, Spring-boot and using Spring Security with Basic Access Authentication. There are no Views, no JSP etc, no 'login', just stateless services which can be called from a React app hosted separately.
I've read a variety of documentation about CSRF protection, but can't decide whether I should be using spring-security CSRF config, or just disabling it? If I disable the csrf protection I can call the service with curl using my basic auth like this:
curl -H "authorization:Basic c35sdfsdfjpzYzB0dDFzaHA=" -H "content-type:application/json" -d '{"username":"user","password":"password","roles":"USER"}' localhost:8081/api/v1/user
If I enable the csrf protection and provide a x-csrf-token header, then the spring CsrfFilter attempts to cross check this against a value from (I think) a session cookie in the HttpServletRequest. However since its a stateless REST service I don't have a session, and haven't 'logged in'.
I have a config class which looks like this:
#EnableWebSecurity
#Configuration
public class ServiceSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and().httpBasic();
if (!serviceProperties.isCsrfEnabled()) {
http.csrf().disable();
}
}
The more I think about it, the more it seems that I will just need to disable CSRF protection. Is there another way to configure spring security so it will work?
thanks
To answer your first question, in the context that you describe, you do not need CSRF protection. The background of CSRF protection is to ensure that the user is not tricked into doing some unwanted action.
For example, in pure theory, you could have logged into a bank's website (and thus established a session) and then went to some shady website. This site could have a form making a POST request to the bank's APIs. Because you have a session there, if the endpoint is not CSRF protected, then the request may go through.
As such, CSRF mostly acts as a protection against browser + session based attacks. If you expose a pure REST API with e.g. OAuth protection, then I don't see any reason for CSRF.
As you use spring boot, you could also disable CSRF using the application.properties / application.yaml configuration file.
security.enable-csrf=false
You can check out the Common Application Properties documentation page for more out-of-the-box configuration options.
If you want to disable csrf in more proper way you can call it like this(if using java configuration)
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and().httpBasic();
.and()
.csrf()
.disable()
I am trying to implement OAuth security and met a problem that for me is not clear enough configuration class.
While implementing AuthorizationServerConfigurer i have three configurers:
ClientDetailsServiceConfigurer used to provide the way how and from where to get client details. As an example, it can be service which provides registered clients from the database.
When it comes to AuthorizationServerSecurityConfigurer and AuthorizationServerEndpointsConfigurer I am not sure what they do or how they should be configured. In the documentation it said only:
AuthorizationServerEndpointsConfigurer: defines the authorization and
token endpoints and the token services.
Maybe someone can explain in simple words what these two configurers do, or what they are used for.
AuthorizationServerConfigurer's javadoc is more informative than the linked documentation. AuthorizationServerSecurityConfigurer, as its name suggests, configures the security of the Authorization Server itself. For example you can override the OAuth endpoints security such as /oauth/token, provide an access denied handler or restrict to SSL access. Here are what the documentation says about it:
Configure the security of the Authorization Server, which means in
practical terms the /oauth/token endpoint. The /oauth/authorize
endpoint also needs to be secure, but that is a normal user-facing
endpoint and should be secured the same way as the rest of your UI, so
is not covered here. The default settings cover the most common
requirements, following recommendations from the OAuth2 spec, so you
don't need to do anything here to get a basic server up and running.
As for AuthorizationServerEndpointsConfigurer:
Configure the non-security features of the Authorization Server
endpoints, like token store, token customizations, user approvals and
grant types. You shouldn't need to do anything by default, unless you
need password grants, in which case you need to provide an
AuthenticationManager.
Here is a sample from one of my projects:
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.tokenStore(jwtTokenStore())
.tokenEnhancer(tokenEnhancer());
}
Here I provided a JwtTokenStore as my TokenStore and a AuthenticationManager since I was using Password Grants.
I am using spring-security-oauth, there is a helpful documentation maybe help you :
projects.spring.io/spring-security-oauth/docs/oauth2.html
I am building a RESTful Spring Boot and React/Alt application. I want to add spring security to make sure that there could be no unauthenticated requests to the API.
I am using Auth0 for an authentication provider so users can log in to the application and more specifically the spring-security-auth0 library to handle the server side security side of things.
https://github.com/auth0/spring-security-auth0
After following the basic tutorial on Auth0, I have configured the security config in my spring application so that requests to the API will not work without a JSON web token. This works, but there are some endpoints (those that need a POST) in the controllers that don't. I get this error in Chrome devtools -
Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'
I understand that there are no CSRF headers present and that is why it isn't working. But the main reason I am confused is because I have disabled CSRF and it still happens. As the spring docs instruct, I've done this -
#Configuration
#EnableWebSecurity
#ComponentScan("com.auth0")
#ImportResource("classpath:auth0-security-context.xml")
#PropertySource("classpath:auth0.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
I don't need CSRF in this case as the app will only ever be used in a dev environment. Why does this still happen even though I have disabled CSRF completely?
The CsrfFilter that is responsible for the Exception is definetly enabled.
This can have various reasons. Can it be you have another instance of WebSecurityConfigurerAdapter configured somewhere ?
You can try the following :
Set a breakpoint in line 'http.csrf().disable();' to see if its really executed.
Set breakpoints in the constructor(s) of WebSecurityConfigurerAdapter to see whether many instances are created.
This should show you whats going wrong..