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.
Related
I have a project with AAD authentication, everything works fine until I add the following code to my HttpSecurity config
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and();
Application starts asking to login again and again in endless cycle.
If I remove that part of code - the app works as expected but there are issues with swagger.
Looks like swagger reads cached authorization from the app, and swagger logout button does no effect. (also app can read cached authorization from swagger login)
This string in properties has no effect.
spring.cloud.azure.active-directory.sessions-stateless=true
Is there any way to separate work of the app and swagger - so they do not interfere each other authorization?
Thx.
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.
My friend and I are making a Java spring boot application for University practice. Its front is on Firebase, and the API is on Heroku
The problem is the following, I configured Spring Security as follows:
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/admin/**", "/bid/getBids", "/bid/{id}", "/purchase/create",
"/purchase/{id}", "/purchase/question/{questionId}/answer").hasAuthority("ROLE_ADMIN")
.antMatchers("/registration/**", "/registration").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/").deleteCookies("JSESSIONID")
.invalidateHttpSession(true);
}
While I'm testing the API on Heroku via swagger/postman, everything works fine, including role restrictions.
But when it tries to set up authorization via the /login path, it redirects to the swagger-ui page, because that's how I set it up. I rewrote the redirect to its main page on Firebase, but the session doesn't work that way, apparently because cookies are saved to the address of my application on Heroku.
Please tell me how I can configure Spring Security so that its site saves user sessions during authorization, and the site works normally with my API?
I use a translator for some phrases, sorry about that
Your frontend and backend applications are served on different domains and HTTP cookie information is stored for only the specific domain. So I think you can easily serve your static page (or single page application resources) by putting under src/resources/static of your spring boot application. By doing this you can also restrict your front-end application and allow for only authorized users. If you want to serve the front-end application on firebase and backend on Heroku you should forward it to the upstream host by configuring rewrite rules in the firebase.json file (https://firebase.google.cn/docs/hosting/full-config?authuser=0#rewrites).
Trying to setup login authentication with Spring Boot starter 2.3.0 and Spring Security 5.3.2
My loginController was working initially a /login POST request
Then I added Spring Security and a UsernamePasswordAuthenticationFilter, and other classes to authenticate that I copied from other apps and it works.
It's going out and authenticating the username and password but it doesn't go through the Controller /login method. It seems to just skip it (sysout logs aren't showing). But if I remove the method then it doesn't work (so it's like it has to be there but doesn't go into it).
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests()
.antMatchers(SecurityConstant.PUBLIC_URLS).permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(
// authenticationFilter(),
jwtAuthorizationFilter,
UsernamePasswordAuthenticationFilter.class);
Has anyone experienced anything like this before? Thanks, appreciate any help, trying to learn Spring Security
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()