AzureAd authentication - STATELESS (Spring Boot Java) - java

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.

Related

How to implement role based authorization on resource server with new Spring Authorization Server

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

Spring 5 Authorization not working as expected

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.

Spring Security session domain

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).

Spring security default login form unable to load CSS files (ERR_CONNECTION_TIMED_OUT)

It looks like Spring Security's default login page uses bootstrap.min.css and signin.css to style itself. The login page displays correctly when running the project from Eclipse but not when running from the Spring Boot fat jar. The errors are :
Failed to load resource: net::ERR_CONNECTION_TIMED_OUT bootstrap.min.css
Failed to load resource: net::ERR_CONNECTION_TIMED_OUT signin.css
These files are managed by Spring Security and I do not know where they are even stored. Like I said the login page works perfectly when running from Eclipse and the rest of the app works perfectly in both environment (thymeleaf templates using bootstrap with Spring MVC backend controllers, secured by Spring Security).
What could be causing these errors?
Did you use matchers against your static resources to be served ?
In case of local resources in other location than default (not recomended)
http
.authorizeRequests()
.antMatchers("/lib/bootstrap/**",
"/css/**",
"/img/**",
"/js/**").permitAll();
In case of webjars
http
.authorizeRequests()
.antMatchers("/webjars/**").permitAll();
Did you even wanted to protect serving those resources with a login constraints? On what purpose?
In case of static resources in the default known directoriers :
While this may not be a new revelation to those of you that have been
following Spring Boot since the SpringOne announcement, there is one
detail for which you may not be aware. Spring Boot will automatically
add static web resources located within any of the following
directories:
/META-INF/resources/
/resources/
/static/
/public/
If you add those files in one of these defaut location of the project structure then no need to authorize requests to them.
See this article for further details
NB : When using default page of spring you can't have a standalone environment and an internet access is mandatory to laod resources. You have to implement you custom login page.
http
.formLogin()
.loginPage("/login")
.permitAll();
Don't forget to chain your spring security rules if needed

reactjs with proxy not getting anonymous session from spring boot backend

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.

Categories