Spring Boot - how to conditionally enable/disable sessions - java

I've built a REST API service using Spring where I've enabled sessions using MongoDB:
#Configuration
#EnableMongoHttpSession(maxInactiveIntervalInSeconds = Globals.SESSION_MAX_INTERVAL)
public class SessionConfig {
#Bean
public AbstractMongoSessionConverter createSessionConverterBean() {
return new JacksonMongoSessionConverter(Collections.singletonList(new GeoModule()));
}
}
I would however, like to have control over which connections should be issued a session. Currently, every HTTP request has a session generated for it, but there are scenarios where the session is not needed, and I'd prefer not to clutter up the session storage with session objects that will never be used.
One such scenario is a standalone desktop application that acts as a content management system. This application has no need for HTTP sessions because authentication is done via the application side via a custom authorization header. This application also only accesses endpoints from a certain root route mapping:
Public traffic routes to api.domain.com/pub and the CMS traffic routes through api.domain.com/cpi.
It would be nice to be able to tell Spring that it does not need to create a session for any requests coming to /cpi. The desktop application also provides a unique Origin that I can match as well if that is more easily done.
My Web security looks like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.permitAll()
.and()
.cors()
.and()
.httpBasic();
http.csrf().disable(); // Self-implemented
}
I've searched all over and haven't found a thing. Can anyone point me in the right direction?
Thanks!

You could add multiple security configuration in the following scheme. Where one is explicitly matching for the all /cpi requests and the other one handling the remaining requests.
You could also configure different authentication methods this way.
#Order(1)
#Configuration
public static class Custom1WebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {
http
.antMatcher("/cpi/**")
.authorizeRequests()
...
http.sessionManagement() // dont create a session for this configuration
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Order(2)
#Configuration
public static class Custom2WebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {
http
.authorizeRequests()
...
}

You could try below in application.yml file.
server:
servlet:
session:
persistent: false
timeout: 0

Related

How to specific different authentications in different urls in springboot in my situation?

i have backend urls for some service to access, and frontend urls for website login to access, my situation is:
/backend/**: HTTPS two-way authentication
/frontend/**: HTTPS one-way authentication and token authentication
I don't want to start two different springboot process.
I have found this answer but springboot not allow to disable client-auth for specific urls:
Spring Boot: Disable Client Auth for specific URL
server:
ssl:
client-auth: need
and this answer maybe helpful, but i don't know how to mix two authentication method in my situation.
How set up Spring Boot to run HTTPS / HTTP ports
please help.
For Spring-Boot 2.7.0 this should be as simple as defining 2 instances of SecurityFilterChain, idealy you'd want one of them to be the default (remove the http.mvcMatcher line) and give the other #Order(1).
Incase of older implementations i'm not 100% sure, for further research you probably find better results looking for a way to support 2 login method depending on endpoint than looking into how to disable certain elements.
#Configuration
public class WebSecurityConfig
{
#Bean
public SecurityFilterChain frontendFilterChain(HttpSecurity http) throws Exception
{
//#formatter:on
http
.mvcMatcher("/frontend/**")
.authorizeRequests(auth -> auth.anyRequest().permitAll());
//Extend with needed authentication
//#formatter:off
return http.build();
}
#Bean
#Order(1)
public SecurityFilterChain backendFilterChain(HttpSecurity http) throws Exception
{
//#formatter:on
http
.mvcMatcher("/backend/**")
.authorizeRequests(auth -> auth.anyRequest().permitAll());
//Extend with needed authentication
//#formatter:off
return http.build();
}
}
```

Lazy initialise spring security at runtime + reload spring security configuration

Spring usually eagerly loading the spring security configuration while starting the application. I'm using OAuth with Spring Security
I'm maintaining a configuration table for storing the SSO related values (like jwk-url, client_id, client_secret). This values will be populated by an admin user via CRUD in the same spring boot application.
Then only the jwk-url is available to be configure in the Spring security configuration (refer below code - jwkSetUri(...)). This would not available at the application startup.
So I wanted to initialise the spring security configuration after the value is loaded into the table, like a lazy loading (#Lazy) at runtime. I know how to do Lazy loading of a regular class/service.
But still I'm not sure how to invoke the configure(HttpSecurity http) method at runtime and how to p
ass the HttpSecurity parameter. When I just try invoke new ResourceServerConfiguration() like a lazy loading at runtime, I don't see the configure() method is called. (Or) this class needs to be maintained as bean and lazy load whenever needed. But still not sure about how to call configure() in code.
Another thing is how to refresh/reload the spring security configuration at runtime, if the JWK url is changed by admin. Then only the spring security configuration can take effect of the changes.
#Configuration
#EnableWebSecurity
public class ResourceServerConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.cors()
.and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
.accessDeniedHandler(oAuth2AccessDeniedHandler)
.jwt()
// Some Auth server URL which would be fetch from table
.jwkSetUri(ssoConfigService.getActiveSSOCertificateURL());
// Eg. http://localhost:8090/auth/realms/demo-app/protocol/openid-connect/certs
}
}
I have already referred these links. But it doesn't help for my purpose. Any help would be appreciated.
How do I lazy load Spring Security?
How to reload the Configure method of WebSecurityConfigurerAdapter when the application is up and running
Modify Spring Security Config at Runtime
Configure Spring HTTP Security at Runtime
Please, check this link Customizing CORS Filtering at Runtime that include a similar use case related to your but for him, he needed to change allowed origins dynamically. They decide to create a new filter and simple extends OncePerRequestFilter.
Take in account to check the OAuth2ResourceServerProperties for your use case.
UPDATING:
Try with this code for this scenario:
Another thing is how to refresh/reload the spring security configuration at runtime, if the JWK url is changed by admin. Then only the spring security configuration can take effect of the changes.
#Override
public void configure(HttpSecurity http) throws Exception {
http.cors()
.and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.anyRequest().authenticated()
// TODO: test with and without this and check if work for you
.and()
.oauth2ResourceServer()
.authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
.accessDeniedHandler(oAuth2AccessDeniedHandler)
.jwt()
// Some Auth server URL which would be fetch from table
.jwkSetUri(ssoConfigService.getActiveSSOCertificateURL());
// Eg. http://localhost:8090/auth/realms/demo-app/protocol/openid-connect/certs
http.addFilterBefore(new OncePerRequestFilter() {
// Every time a request occur, this method will be called.
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
try {
http.oauth2ResourceServer()
.authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
.accessDeniedHandler(oAuth2AccessDeniedHandler)
.jwt()
// Some Auth server URL which would be fetch from table
.jwkSetUri(ssoConfigService.getActiveSSOCertificateURL());
} catch (Exception e) {
e.printStackTrace();
}
}
}, BasicAuthenticationFilter.class);
}
I hope this info can help you.

Java Spring Security hasAnyAuthority doesn't works

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.

Spring Boot security form login and Oauth2 resource server

I'm using Spring Boot and I want my app to host Oauth2 resource server for accessing my api endpoints on the same server. I also need to have a web interface with secured pages via form login.
For example I have api endpoints /api/v1/** where requests can only be made via having a token from my oauth2 resource server.
Additionally there are endpoints like /account/** where user needs to be logged in via form.
All of this needs to be in one Spring Boot instance for now.
My WebSecurityConfig file:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/account/**").authenticated()
.and()
.httpBasic();
}
}
And in my Oauth2SecurityConfig I have:
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/v1/me/**").authenticated();
}
}
The problem is, oauth2 config seems to override the first configuration and all my webpage resources are exposed without asking username password in form login. And if I try accessing my api endpoints I get the expected oauth error response.
Do I need to have them both in one overriden method? Do I need to have 2 instances of HttpSecurity? How can I solve this?
I had faced the same situation. Finally got a solution for this. You just need to make the use of #Order annotation.
Add this to your WebSecurityConfig class
#Order(1)
And add this to your ResourceServerConfiguration class
#Order(2)
To secure all your resources you would have to add
.authorizeRequests().anyRequest().authenticated(). Did you mean that your "/account/**" resource is exposed?
Those two HttpSecurity objects are not the same object. That being said you don't need to have both of them configured, but each one of them serves different purpose. (I have both of them configured in my project and it's working fine)
I would start by reviewing your expectations for this as I am not sure whether it is feasible to have a part of your server protected by OAuth and another part by another authentication mechanism (Form login). Both would be considered .authenticated(). You could manage the access by roles and oauth scopes, but then you would have to also provide both login/logout mechanisms by different filters and maybe another filter to provide persisting of both authentications when navigating through your server. Seems to me like a lot of not so standard work and I would think about different solutions.

What additional configuration needs to be done in order to enforce https using spring-security?

I am trying to secure my webapp such that all requests need to be made using https. I am using a Java based configuration, in particular I have a class which extends WebSecurityConfigurerAdapter. I have attempted to configure my security using the #Override protected void configure(HttpSecurity http) {} method as detailed here and here.
I've tried both of those and many variants of configuring the HttpSecurity object, as well as several variants of authentication. In almost all cases, I come up with the following issue:
[nio-8080-exec-2] o.a.coyote.http11.Http11NioProcessor : Error parsing HTTP request header
I tried doing some reading into this but a lot of the search results turned out to be dead ends for me. My assumption was that the solution that was hinted at in the two posts I referenced would give me roughly the correct answer, but is there any additional configuration I need to do before I can get https working? If so what is it, and if not, what am I missing here?
Below is my current configuration, which replicates the error described above (it is basically the default one plus the https channel):
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// Specify the authentication mechanisms that will allow user access to the site.
#Autowired
public void configureGlobal(AuthenticationManagerBuilder builder) throws Exception {
builder.inMemoryAuthentication()
.withUser("user").password("password").roles("ROLES_USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic()
.and()
.requiresChannel().anyRequest().requiresSecure();
}
}
On the front end I am getting an SSL Connection Error : Unable to make a secure connection to the server. This may be a problem with the server, or it may be requiring a client authentication certificate that you don't have.
As #M.Deinum mentioned in comments, the difficulty was in the fact that I had not configured SSL in my application.properties. Creating one akin to the following:
server.port=9090
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password={password}
security.require-ssl=true
Resolved the issue.

Categories