How to separate authorization server spring security in java - java

I have started to learn spring security (Oauth2). I am having a REST API service which is protected by Spring Oauth2. What i want to do is, I want to separate authorization server and resource server, For example,
I am having
Authorization: http://server1:8080/RESTTest/oauth/token/grant_type=client_credentials&client_id=clientt&client_secret=secret
And
Resource
http://server1:8080/RESTTest/api/users/?access_token=2cf682c6-2900-47dc-a468-441fcee0dc18
What i want is,
Authorization : http://Server1:8080/authorizationserver /oauth/token/grant_type=client_credentials&client_id=clientt&client_secret=secret
Resource:
http://server2:8080/RESTTest/api/users/?access_token=2cf682c6-2900-47dc-a468-441fcee0dc18
I am using JDBCTokenstore. I am not sure how to separate it. Can someone help me.
Thanks,

You can map your custom endpoint to defaults provided, fyi http://projects.spring.io/spring-security-oauth/docs/oauth2.html
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
endpoints.pathMapping("/oauth/token", "/authorizationserver/oauth/token")
}
}

Related

Setting up CSRF for spring websocket

I am building an application where authentication is done by spring security for HTTP handlers, for HTTP I've disabled csrf protection, and now I want to disable csrf for spring web socket, but I can't figure out how to accomplish this, I've already tried many different approaches but no one seems to be working. If it is impossible to disable csrf for WebSocket how to get a csrf token? (I tried setting up the csrf endpoint to obtain a token but it is not work, and all tutorials I've found are outdated)
Thanks in advance!
web socket security config:
#Configuration
#EnableWebSocketSecurity
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Bean
AuthorizationManager<Message<?>> messageAuthorizationManager(
MessageMatcherDelegatingAuthorizationManager.Builder messages) {
messages.anyMessage().permitAll();
return messages.build();
}
#Override
protected boolean sameOriginDisabled() {
return true;
}
}
security config:
#Configuration
#EnableWebSecurity(debug = true)
public class SecurityConfig {
#Autowired
private JwtFilter jwtFilter;
#Bean
SecurityFilterChain securityFilterChain(HttpSecurity HTTP) throws Exception {
return http.addFilterBefore(jwtFilter, BasicAuthenticationFilter.class)
.cors(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/authenticate").permitAll()
.requestMatchers("/createchatroom").authenticated()
.requestMatchers("/public/*").permitAll()
.requestMatchers("/private/*").permitAll()
.requestMatchers("/ws/**").authenticated()
.requestMatchers("/register").permitAll()
.requestMatchers("/csrf").authenticated()
.requestMatchers("/addEmployeeToFavorites").hasAnyAuthority(EMPLOYEE.name(),
ADMIN.name())
.requestMatchers("/addChatRoomToFavorites")
.hasAnyAuthority(EMPLOYEE.name(), ADMIN.name())
.requestMatchers("/home").hasAnyAuthority(EMPLOYEE.name(), ADMIN.name()))
.build();
}
}
By default, Spring Security requires the CSRF token in any CONNECT message type. This ensures that only a site that has access to the CSRF token can connect. Since only the same origin can access the CSRF token, external domains are not allowed to make a connection.
Spring Security 4.0 has introduced authorization support for WebSockets through the Spring Messaging abstraction.
In Spring Security 5.8, this support has been refreshed to use the AuthorizationManager API.
To configure authorization using Java Configuration, simply include the #EnableWebSocketSecurity annotation and publish an AuthorizationManager<Message<?>> bean or in XML use the use-authorization-manager attribute. One way to do this is by using the AuthorizationManagerMessageMatcherRegistry to specify endpoint patterns like so:
#Configuration
#EnableWebSocketSecurity
public class WebSocketSecurityConfig {
#Bean
AuthorizationManager<Message<?>> messageAuthorizationManager(MessageMatcherDelegatingAuthorizationManager.Builder messages) {
messages
.simpDestMatchers("/user/**").authenticated()
return messages.build();
}
}
Any inbound CONNECT message requires a valid CSRF token to enforce the Same Origin Policy.
The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request.
Our messages require the proper authorization. Specifically, any inbound message that starts with "/user/" will require ROLE_USER. Additional details on authorization can be found in [websocket-authorization]
At this point, CSRF is not configurable when using #EnableWebSocketSecurity, though this will likely be added in a future release.
To disable CSRF, instead of using #EnableWebSocketSecurity, you can use XML support or add the Spring Security components yourself, like so:
Java
#Configuration
public class WebSocketSecurityConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
}
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
AuthorizationManager<Message<?>> myAuthorizationRules = AuthenticatedAuthorizationManager.authenticated();
AuthorizationChannelInterceptor authz = new AuthorizationChannelInterceptor(myAuthorizationRules);
AuthorizationEventPublisher publisher = new SpringAuthorizationEventPublisher(this.context);
authz.setAuthorizationEventPublisher(publisher);
registration.interceptors(new SecurityContextChannelInterceptor(), authz);
}
}
web.xml
<websocket-message-broker use-authorization-manager="true" same-origin-disabled="true">
<intercept-message pattern="/**" access="authenticated"/>
</websocket-message-broker>
On the other hand, if you are using the legacy-websocket-configuration and you want to allow other domains to access your site, you can disable Spring Security’s protection. For example, in Java Configuration you can use the following:
#Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
...
#Override
protected boolean sameOriginDisabled() {
return true;
}
}
References
WebSocket Security - Spring Security

Spring Security - Wildcards/matchers in authorization rules

While configuring the security of my Spring Boot application, I wanted to secure parts of the API depending on the PathVariable that is entered there. My current configuration is as follows:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//not important
#Override
public void configure(HttpSecurity http) throws Exception {
http.cors();
http.authorizeRequests()
.mvcMatchers("/api").authenticated()
.mvcMatchers("/api/TEST").hasAuthority("SCOPE_dep:TEST")
.and().oauth2ResourceServer().jwt();
}
}
In the the 'api/{PathVariable}' endpoint is the one I want to have customized, making sure that someone with the authority 'SCOPE_dep:TEST' can access the 'api/TEST' endpoint, someone with 'SCOPE_dep:TEST2' authority can access the 'api/TEST2' endpoint, even allowing more then one such endpoint for a user which has multiple of these authorities.
Is there a way to do this by using a type of wildcard/matcher that I'm unaware of, or is the only possiblity hardcoding all these different authorities?

Access OAuth2 Protected api from the Java Batch Application

I have Springboot Microservice app comprises( Discovery , Eureka Client , Zulu Proxy , Gateway )which is configured with OAUTH2 which is working fine.
and OAUTH2 is configured as the in memory token store. i have rest end points gateway exposed
ex :
localhost:8080/hello/gateway
now i have java batch , which will call micro service app gateway example (above api) to get the required response. since that is protected with OAUTH2 i cant access api directly.
is there a way to access the api without token or can we bypass the authorization logic by passing the hardcoded token from batch and validating in the Gateway
Tried to create a non-expiring token but since its in-memory token, it will not work after the api restart
Tired to create a custom filter and but it didnt work as expected . below is my resource server code.
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "resource_id";
#Autowired
private AppProperties appProperties;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.
anonymous().disable()
.authorizeRequests()
.antMatchers("/testService/**").authenticated()
.and()
//.addFilterBefore(new BatchCustomFilter(), BasicAuthenticationFilter.class)
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
Let me if know there is any good way of doing this , Suggestions are highly appreciated .
yes had overridden WebSecurityConfigurerAdapter configure method to ignore the specific endpoint.
#Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring().antMatchers("/testService/testApi/**");
}
Now im able to access Api from batch after ignoring the endpoint from web security.

Spring security default configuration always throws 401

I'm creating a new Spring REST application with some basic services and entities.
I added Spring Security and without overriding any class, i just added to application.properties a user and password.
So far so good, i opened Postman to try out a endpoint and it always return 401 to my requests.
I tried in postman set the authorization via "Basic Auth" (is what header WWW-Authenticate asks), tried "Digest auth" using the "Realm" value from the header. But none of it works.
Here is what i have in my application.properties
spring.security.user.name=root
spring.security.user.password=root
This is my request
https://imgur.com/URM3TGD
(Sorry i can't embbed the image because of my reputation)
And here is the endpoint
#PostMapping("saveUsuario")
public Usuario saveUsuario(Usuario usuario) {
return usuarioRepository.save(usuario);
}
(If possible) i don't want to override any Spring Security class, just "use as it".
Thank you!
So here is what i found.
Thanks to #jzheaux we discover that the problem was with the csrf configuration (Using POST request).
So i was forced to override the class WebSecurityConfigurerAdapter to disable it.
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
But then, the endpoints could be called without authentication!
So, this is the final code:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.cors();
http.authorizeRequests().anyRequest().fullyAuthenticated();
http.httpBasic();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
}
}
First disable the CSRF.
Then enable Cors.
I set that i want any request to be fully authenticated
The challenge type is HTTP basic
I disable the creation of cookies so it'll always ask for credentials.
So far so good, it's working!
Per https://docs.spring.io/spring-boot/docs/1.5.0.RELEASE/reference/htmlsingle/#boot-features-security
you should change your password with
security.user.password=root
instead of spring.security.user.password=root
similar security properties that are overridable are in the #ConfigurationProperties class: SecurityProperties.java
See https://github.com/spring-projects/spring-boot/blob/v1.5.0.RELEASE/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java

Spring websocket (STOMP) registration

Good day! I have a simple chat with Spring websocket and STOMP.
In some examples I have seen authentication with spring-security-web and spring-security-config - something like
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
But the problem is - withUser("user") is hardcoded and method is called at whole system start up - what if I wand a dynamic user registration?
So the questions are:
1) How can I make dynamic registration? Something like :
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat", "/registration").withSockJS();
}
And do some #MessageMapping("/registration") ? and inside parce the message with registration data? I quess there is a better way...
2) After user registration from question 1 - how can I dynamically check if user is registered when he connects to web socket and prevent subscribing to my endpoints and sending messages if he is not?

Categories

Resources