I am trying to use 2 authorization mechanisms simultaneously: LDAP and DAO.
They work in order of configuration. This is not appropriate if the user credentials match in both mechanisms.
(For example, in LDAP there is a user m.smith with a password qwerty and in the database there is a user m.smith with a password qwerty)
Is it possible to somehow convey the flag which mechanism to use at the current moment? Аnother mechanism in this case should be ignored.
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource)
.userSearchFilter("(sAMAccountName={0})")
.userDetailsContextMapper(userDetailsContextMapper);
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
If you have two mechanisms that are completely disjoint then you should probably fix it on upper levels (starting from UI). For instance if user uses LDAP authentication you would send a flag (for instance a HTTP header) that would indicate what auth type to use. Then you can implement custom filter that would perform specific type of authentication (programmatically).
I am not aware of any other solution that could do what you want in runtime.
Related
I have the following requirement that I need to implement on a project, but not matter how many books or articles I read on spring security I cannot figure out what the configuration methods are actually doing.
My requirements are as follows.
when REST calls are made to /api/** I just need to check that the user has included a token in the header and if so, I need to validate the token using an in house component. If the token is not present or not valid I just want to return a 401 to the client.
If the token is valid then they are authenticated and can proceed to the respective controller. Role based auth is not required, so I am assuming this is where permitAll() comes in?
rest calls to actuator /info, /health do not require the user to be authenticated
calls to /hawtio and /jolokia require the same as part 1), but if the token is not present they are redirected to the login page where they can enter a username and password. The username and password is then validated using an internal service and the generated token added to the users header. The user can also logout of the web ui, which should return them to the login page.
So for instance, if we take the example below.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
**.authorizeRequests()**
.antMatchers("/resources/**")**.permitAll()**
.anyRequest()**.authenticated()**
.and()
.formLogin()
.loginPage("/login")
**.permitAll()**
.and()
.logout()
**.permitAll()**.logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
What is the significance of the parts I have surrounded with ** **
I think I understand that REST calls to /resources/** just pass straight through without the user needing to have been authenticated. But the next line
.anyRequest().authenticated()
just confuses me. I think I get that it's stating ALL other requests require the user to be authenticated. But authenticated by what? How do you get authenticated and what happens if they are not authenticated?
Any help appreciated.
.authorizeRequests() means you want to start configuring which requests to which endpoints should be checked for authorization.
.antMatchers("/resources/**")**.permitAll()** here you are saying that all requests to /resources/** are allowed without any authorization.
The last 2 permitAll are so that clients can access the login endpoint and logout endpoint.
All of this is the absolute basics of spring security. And is talked about in many tutorials on the internet.
If you seriously are going to work with spring security i suggest you spend some time reading the architecture of spring security https://docs.spring.io/spring-security/reference/servlet/architecture.html so that you understand the basics. Otherwise you will have a hard time.
Become friends with the spring security documentation as it will help you a lot more than tutorials.
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.
I'd like to provide two ways to authenticate in my application, one is basic auth (users), and the other is some kind of token based (technical users). I understand that I need a custom ReactiveAuthenticationManager but I can't find clues on the big picture. (Actually, there are a very few insights for MVC, and none for WebFlux.)
1) How do I populate the Authentication's name and credentials in the token based approach? If I configure Spring Security to use httpBasic it's already populated. Some kind of filter needed?
2) How do I distinguish in the authentication manager where the credentials are coming from? Do I have to lookup in the userRepository and (if not found) in the technicalUserRepository too?
3) Do I have to override the SecurityContextRepository? All the tutorials do it but I don't see any reason to do so. What is it exactly? This source states that "SecurityContextRepository is similar to userDetailsService provided in regular spring security that compares the username and password of the user." but I think he means ReactiveUserDetailsService (neither UserDetailsService nor ReactiveUserDetailsService does that by the way, it's just for user lookup).
Since i am decent at Webflux and i have worked a lot with oauth2 i'll try and answer some of your questions.
1) How do I populate the Authentication's name and credentials in the
token based approach? If I configure Spring Security to use httpBasic
it's already populated. Some kind of filter needed?
A token never contains credentials. A token is something you get issued after an authentication has been done. So usually you authenticate against an issuing service. After you have authenticated yourself against that service you will be issued a token.
If its an oauth2 token the token itself is just a random string. It contains no data about the user itself. When this token is sent (using the appropriate header) to a service using spring security. Spring security has a token filter that will basically check that the token is valid, usually by sending the token to the issuer and asking "is this token valid?".
If using a jwt, its different, the jwt must contain some information like issuer, scopes, subject etc. etc. but its basically the same thing, there is a built in filter that will validate the jwt by sending it to the issuer (or using a jwk that the service fetches from the issuer so it can verify the integrity of the jwt without doing an extra request).
2) How do I distinguish in the authentication manager where the credentials are coming from? Do I have to lookup in the userRepository and (if not found) in the technicalUserRepository too?
You don't You usually define multiple SecurityWebFilterChains for different url paths. I have not done this in Webflux Spring Security, but thats how you do it in regular Spring Applications, and i don't see any difference here. Unless you are doing something crazy custom.
3) Do I have to override the SecurityContextRepository? All the tutorials do it but I don't see any reason to do so. What is it exactly? This source states that "SecurityContextRepository is similar to userDetailsService provided in regular spring security that compares the username and password of the user." but I think he means ReactiveUserDetailsService (neither UserDetailsService nor ReactiveUserDetailsService does that by the way, it's just for user lookup).
The answer here is probably no. You see Spring security 4 had very bad support for oauth2 and especially JWT. So people got accustomed to writing their own JWT parsers. When spring Security 5 came, Spring implemented a jwt filter that you can configure and use built in. But there are a lot of outdated Spring Security tutorials out there and foremost there are a lot of developers that don't read the official documentation.
They mostly google tutorials and get the wrong information and then work on that.
But easy explained:
SecurityContextRepository
If you have session based authentication (server establishes a session with a client) it will store the SecurityContext (session) in ThreadLocal during a request. But as soon as the request ends, the session will go lost unless we store it somewhere. The SecurityContextPersistenceFilter will use the SecurityContextRepository to extract the session from ThreadLocal and store it, most common is to store it in the HttpSession.
AuthenticationManager
Override this if you want to do a custom authentication process. Example if you want to validate something, call a custom LDAP, database, etc etc. It\s here you perform you authentication. But remember, most standard logins (like ldap, sql-servers, basic login etc.) already have prebuilt configurable managers implemented, when you select what login type like .httpBasic() you will get a pre-implemented AuthenticationManager.
UserDetailsManager
You override this when you want create a custom UserDetails object (also usually called Principal) In the UserDetailsManager you do you database lookup and fetch the user and then build and return a UserDetails object.
Those two interfaces are the most regular custom implementations, and are used if you need to to basic authentication/session based authentication.
If you wish to do token, you have to think about, who is the token issuer? usually the issuer is separate and all services just get tokens and validate them against the issuer.
I hope this explains some of the questions. I have written this on the bus so some things are probably wrong and not 100% correct etc. etc.
In my Spring Boot application i'm working with Auth0 to manage access to my rest api.
In addition to Auth0's scope i would like to add a ROLE to each user which in turn will provide an additional layer of access control where specific API's won't be accessible to low privileged users.
I've been reading about custom rules and authorization extensions but couldn't quite understand what is the right implementation for me.
Here's my WebSecurityConfigurerAdapter code snippet:
So basically i want only 'ADMIN' for example to be able to access /test/**
#Override
protected void configure(HttpSecurity http) throws Exception {
JwtWebSecurityConfigurer
.forRS256(configBean.getAuth0ApiAudience(), configBean.getAuth0Issuer())
.configure(http)
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/test/**").hasAuthority("read:test")
.anyRequest().authenticated();
}
Any help would be much appreciated!
You have a few options here (at least..).
1). You could conceivably use a Rule to do handle the decision logic on which "ROLES" are assigned to given user - and rather than tag this onto scope (which you could do too..), you may decide they belong instead as a custom claim on that access token. Body of Rule may contain something like
// lookup the permissions for given user somehow (secured webhook, static map etc) - here lets imagine we want ROLE_USER assigned
context.accessToken.scope = "ROLE_USER"
// or
context.accessToken['https://mydomain/roles'] = "ROLE_USER"
2). Simply use the fact that you have the auth0 userid available in the JWT Access token from Auth0 that you send to the API - you could use this knowledge to look up the finer grained permissions for that use "out of bands" of Auth0 (using your own database storage for permissions keyed on user Id etc or some other customer claim tagged on the access token - or by using auth0 if for example you tagged the ROLE information as metadata onto the Auth0 User profile. You could then do an Auth0 user profile lookup (management api) by user id and get details that way. See example here for an illustration in Java on getting the userId claim from the JWT access token if you like this approach.
3). Take a look at the Auth0 authorization extension which provides support for user authorization via Groups, Roles, and Permissions. You can define the expected behavior during the login process, and your configuration settings will be captured in a rule that's executed during runtime.
There is no hard and fast answer here, each of the above merits consideration, and what you need for your project. If you really want to leverage the existing declarative authorization as per your code above, then Option 1, and pegging the ROLES information to the scope is the easiest approach.
However, I would actually advocate option 2). above myself, for most "pragmatic" small to medium sized ventures. Here, you would require a little programmatic code inside your Controller endpoint to lookup the ROLES and then make a security decision that way. You could also push out the lookup code into a common Custom Filter that executes before the Controller code is reached, and does the necessary Spring Security manipulation that way - more of an advanced developer option - (I have written libraries in the past that supported this approach for Spring Boot / Security - and can therefore vouch it is a reasonable approach. See here for demonstration but again, sure you would prefer to get on with building your business logic and not detour into building a library, right?).
Option 3). is definitely worth exploring if you are building out a serious enterprise app, and need all the integrations - especially where integration with enterprise connections such as Active Directory are in play.
Leave me comments if you are still confused, but hopefully the above offers sufficient insights to explore further.
Quick update
Further to our discussions, here is a little Rule that gives you the idea you were asking about:
function addRoleScopesToAccessToken(user, context, callback) {
console.log("add-role-scopes-to-access-token rule");
user.app_metadata = user.app_metadata || {};
var roles = user.app_metadata.roles;
if (roles && roles.length > 0) {
context.accessToken.scope = roles.join(' ');
}
callback(null, user, context);
}
And this is how your "app_metadata" might look like:
{
"roles": [
"role1",
"role2"
]
}
You should end up with a JWT access token with the roles added to the scope. eg.
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).