How to authenticate WebSocket within an existing HTTP environment with Spring Security - spring-security

I have a pretty simple requirement (I use Spring-Security 4.0.1) but I can't find any examples on the web except what is been told on this page: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-server-handler
It is relatively simple to integrate a WebSocketHandler into other
HTTP serving environments with the help of
WebSocketHttpRequestHandler.
What I have: An implementation of WebSocketHandler that does the job and an HTTP serving environments using a Basic Authentication. My WebApplicationInitializer looks like this:
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
...
// WebSocket support - Handshake
Dynamic ws = servletContext.addServlet("webSocketHttpRequestHandler", new HttpRequestHandlerServlet());
ws.addMapping("/streaming/*");
// Spring Security Filter
FilterRegistration.Dynamic springSecurity = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
springSecurity.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
}
}
This is how I plugged my websocket endpoint to my existing web application.
My WebSocket configuration class looks like (very simplified) this:
#Configuration
public class WebSocketServicesConfig{
#Bean
public WebSocketHttpRequestHandler webSocketHttpRequestHandler() {
return new WebSocketHttpRequestHandler(new StreamingWebSocketHandler());
}
}
StreamingWebSocketHandler implements WebSocketHandler.
I also have a RESTful Web Service (in the same server) that uses the configured Basic Authentication.
What is working: My RESTful Web Service is working with any web browsers. I can do some authenticated queries (credentials can be sent in the HTTP headers).
WebSocket queries are working and ask for authentication the first time I try to do some (under FireFox, a popup appears asking for credentials, once I enter them, client and server are able to communicate via WebSocket messages).
In my WebSocketHandler, the Spring object: WebSocketSession that contains informations about the authenticated user is correct (#getPrincipal() method returns a Authentication containing the right granted Authorities, details and so on...).
Note that once the websocket is authenticated, I can relaunch the query without re-enter them.
What I want: On a user point of view, this is bad because the credentials are required twice:
First for RESTful queries
Second for WebSocket queries
How can I bypass the second authentication assuming the first one succeeded? Is there a way to detect the client has been authenticated and not ask for credentials?
What I don't want: I don't want to use neither Stomp over websocket nor SockJs (I don't need to support old web browsers).

Related

Use custom authorities with Okta Spring Boot Starter

I am using version 1.4.0 of the Okta Spring Boot Starter to validate incoming JWT tokens. By using the Starter, both authentication and authorization works out of the box (the default works so well you don't even need to define anything in your own security configuration).
But the default created roles are not to my liking, so I want to map the incoming scopes & roles to my own defined Spring authorities. When using the plain OAuth starter, one can define a AuthoritiesExtractor bean to do just that:
#Bean
public AuthoritiesExtractor authoritiesExtractor() {
return new YourOwnAuthoritiesExtractor();
}
Next to that, there is also the option to implement a custom jwtAuthenticationConverter in your security configuration:
http
..
.oauth2ResourceServer()
.jwt(jwt -> jwt.jwtAuthenticationConverter(new JwtAuthenticationConverter() {
#Override
protected Collection<GrantedAuthority> extractAuthorities(final Jwt jwt) {
// implementation
}
})
But all of these things seems not to work with the Okta Starter, because the extractors are never called when a JWT token is send to the server. Does someone know how to implement it for Okta?
TL;DR
It's not possible with the standard Okta Starter at the moment.
Explanation
As Okta uses its own configurer to setup the oauth2ResourceServer, you cannot use a custom JwtAuthenticationConverter as it will be overridden by the one Okta defines. Neither can you use the AuthoritiesExtractor, as the interface is not even packaged with the Okta Starter.
To overcome this issue, Okta introduced the concept of the AuthoritiesProvider interface. By defining a custom bean, you can add you own authorities to the ones already set by Okta :
#Bean
AuthoritiesProvider myCustomAuthoritiesProvider() {
return (user, userRequest) -> lookupExtraAuthoritesByName(user.getAttributes().get("email"));
}
Sadly enough, the AuthoritiesProvider interface only supports authorization code flow and not resource servers. As long as #160 is not resolved, there will be no native suport for Opaque and JWT.

Verifying user authorization from inside the application with Spring Security Filter Chain programmatically

I'm currently developing an application with Spring Boot 1.4.2.RELEASE and Spring Security 4.1.3.RELEASE. The application has Rest Controllers and receives and responds json messages. This application will be communicating with an Angular application.
I already have authentication and authorization working with configurations like:
http.authorizeRequests()
.antMatchers(HttpMethod.POST, "/foo/bar/**")
.access("(hasRole('OPERATOR') && hasRole('MAKER')) || hasRole('ADMIN')")
.anyRequest().authenticated()
.and()
.httpBasic();
And rules in the RestControllers methods like:
#PreAuthorize("hasRole(#id) || hasRole('ADMIN')")
All that is working without problems, now I'm adding Spring Hateoas.
I know that Hateoas is not related to user authorization to resources, but I want to be able to send to the angular app additional information. Not just the link of the resource but what actions (http verbs) the user has access to.
I don't want to do this to improve the security of the application, it's just to improve the user experience. In the Angular app I want to be able to activate or deactivate a functionality depending of what the server is sending.
So here comes my question, is there any available class in Spring Security that I can Autowire in order to test a URL and see if the user is authorized to execute a specific action to that particular URL?
All the classes mentioned in the Spring Security documentation that I have tested so far are not recognized by the #Autowire annotation.
Interesting question, look at WebInvocationPrivilegeEvaluator it might suits your needs.
isAllowed(String contextPath, String uri, String method, Authentication authentication)
You can see it in action for example here.

Spring Security (basic-authentication) - receiving 401 Unauthorized for correct credentials

I am trying to add a basic authentication security layer over a REST service that I developed using Spring boot 4.3.
I have essentially did two main things:
Implement UserDetailsService interface to provide user details. Here I read from a text file the usernames and the encoded (via Bcrypt) passwords.
I declare a bean as follows in my #EnableWebSecurity annotated security configuration class:
#Bean
public BCryptPasswordEncoder getPasswordEncoder () {
return new BCryptPasswordEncoder();
}
to return the specific password encoder.
I am testing the authentication using rest clients both ARC (for Chrome) and REST Client of Firefox.
The issue is as follows:
When I enter my credentials for the first time and upon successful authentication, the response is 200 OK. This is true for a bunch of users. In other words, as long as I supply correct pair of credentials I get a 200 response.
But, after a single request with incorrect credentials the authentication process breaks down. Sometimes I get 200 and other times a 401 even for correct credentials. Other users authentication is affected as well, at this point of time.
There is a curious log that appears at step 2:
WARN 6813 BCryptPasswordEncoder : Empty encoded password
To elaborate a bit on the hashing of the passwords, I ran the Bcrypt password encoder utility and encoded a bunch of passwords and saved them manually in a text file for the corresponding user names.
I am unsure where the issue lies: whether the clients caching the credentials or the Spring security context caching the incorrect principal or the user details service breaking down (no such exception in the logs though).
Any help is appreciated. If you need any further specific information, please do let me know.

How can I do an SSO to REST API with Spring security?

I have an application comprised of an NGINX server, front end server and a backend server.
The NGINX and frontend handle the login (some legacy code I have to use for now), and it is done successfully.
I need to do an SSO to the RESTfull API with Spring Security.
The API is running in a Spring-boot application on an embedded tomcat 8 server.
The spring-security version is 4.0.3, the spring-boot version is 1.3.3.
I started with:
#Configuration
#EnableWebSecurity()
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().permitAll();
}
}
And now I get 401 (unauthorised) from the API, looking at the legacy code and consulting with other developers (I am new to the organisation), I can see that when using an XML configuration they used:
<authentication-manager alias="authenticationManager"/>
So the authentication manager just passes the requests (and they do the rest of the verifications in filters).
I would like to do something similar, or add the verification of data present in the headers at this stage, but I can't find a clear documentation for this that is not for XML configuration.
I thought this might be equivalent to the XML code used in the legacy system, but it doesn't work:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authentication -> {
authentication.setAuthenticated(true);
return authentication;
});
}
I am looking for a correction to my ideas, or alternative ways to do this.
Apparently I had a context problem, this works without the authentication manager configuration

Call a Grails restful web service in a spring security application

I need to submit a simple and unique request to a web service hosted inside a regular web based Grails application which is secured with Spring Security plugin. My request should look like:
curl -F username=john password=mypass message="Hello World" http://localhost:8080/myapp/restapi/echo
No work flow, just an unique request and I'm done.
I have a simple secured controller to respond to this request as follows:
#Secured(["ROLE_REST_CLIENT"])
class RestapiController {
def echo() {
respond params.message
}
}
The issue here is that spring security default behavior is to redirect any new request to the login page. How can I change that, search the http params for the user name and password, register the user and go on TO the requested controller action, all in the same unique stateless request?
I had a look at Spring Security REST Plugin but it is aimed to provide a token-based work flow which isn't exactly what I need. (I would also appreciate some guidance to this work flow approach as an optional solution)

Resources