Spring Security - Custom authentication without provider? - spring-security

I have a hybrid application that uses Spring Security for roles validation but not for login.
PreAuthorize fails with "An Authentication object was not found in the SecurityContext"
I tried to add this to my Login controller but it doesn't seem to work:
SecurityContextHolder.getContext().setAuthentication(makeAuthentication(op));
The configuration is as follow:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebConfig extends WebSecurityConfigurerAdapter {}
Am I forced to use an authentication provider? How would it work in this case? The user roles are stored in the Operator object.
EDIT: It looks like the SecurityContext gets cleared between requests. How do I make it persistent?
I tried adding the security context to the session as SPRING_SECURITY_CONTEXT_KEY attribute but still no luck.
In the end, I made it work by restoring the context in an interceptor. Not sure this is the best way though.

Make sure your client is sending subsequent requests on the same session as your custom login request
If that is ensured, check if your custom login url goes through spring security but as an unsecured url. If it is not the case, you have to add the following to your custom login success stage.
SecurityContextHolder.getContext().setAuthentication(makeAuthentication(op));
HttpSession session = req.getSession(true);
session.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
SecurityContextHolder.getContext());
Once these steps are in place, Spring security's SecurityContextPersistenceFilter will ensure SecurityContextHolder.getContext() is populated on subsequent requests.

Related

Sessionless form login for Spring OAuth2 authorization server?

I would like to avoid leaving a login session open after an OAuth2 authorization code (spring-authorization-server) has been issued. Currently the flow looks like this:
The user requests /oauth2/authorize with a redirect_uri.
If there isn't an authenticated session, the response is a 302 to /login. The original request URL is saved in a session.
The user submits the login form and, if everything checks out, Spring will issue a 302 redirect to the previously saved URL.
This time, /oauth2/authorize will see the authenticated session and redirect the user back to the redirect_uri with a code.
The session then remains, allowing the user to keep fetching new access tokens without re-authenticating.
Using stateless session management, I’ve toyed with CookieRequestCache to keep track of the original request URL in step 2. This works, but I would need some sort of internal redirect between step 3 and 4 or else the authentication state get lost. The browser would then be redirected from /login straight to redirect_uri. Is there a way to do this?
And if all else fails, is there way to write a hook that executes just prior to the redirect to redirect_uri, deleting the session?
You can customize the response handling of /oauth2/authorize in Spring Authorization Server through its OAuth2AuthorizationEndpointConfigurer DSL.
You can take a look at authorizationResponseHandler. A custom version could invalidate the session.
Caveat
That said, requesting to immediately log out the user is a bit uncommon. Indeed, a common use case for an authorization server is to provide single-sign-on across multiple applications. If you choose to invalidate the session, then when the user visits a second application (perhaps introduced down the road), then they will need to log in again for each application that they visit.
With that caveat in mind, here is an example of what a custom AuthenticationSuccessHandler could look like:
public class MySessionInvalidatingAuthorizationResponseHandler
implements AuthenticationSuccessHandler {
private final var redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(
HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
var result = (OAuth2AuthorizationCodeRequestAuthenticationToken)
authentication;
var code = result.getAuthorizationCode().getTokenValue();
var builder = UriComponentsBuilder
.fromUriString(result.getRedirectUri())
.queryParam(OAuth2ParameterNames.CODE, code);
if (StringUtils.hasText(result.getState())) {
builder.queryParam(OAuth2ParameterNames.STATE, result.getState());
}
// invalidate the session ...
this.redirectStrategy.sendRedirect(
request, response, builder.toUriString());
}
}
Alternatively, you could implement SecurityContextRepository to store the SecurityContext in a cookie; however, this comes with a still stronger caveat that storing the security context as a cookie is much harder to secure. In this setup, /oauth2/authorize would work by default since it would have a materialized SecurityContext available. This may be more of the same, though, since if your primary concern is immediately logging the individual out, you would still need to delete the cookie.
UPDATE: One additional thought is that maybe you are actually not wanting to log in the user at all. In that case, the client_credentials flow may be more appropriate. It is a back-end grant flow where the client's id and password are used to get an access token.

How to implement multiple authentication methods in Spring WebFlux Security?

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.

Spring security based application having both form login and SSO

I have searched enough but I haven't got a clear answer and thus posting this question.
I have an existing application which uses spring security for authentication.
Current implementation uses a custom implementation of UsernamePasswordAuthenticationFilter for doing this.
Thus the flow is something like below(in very simple terms):
inputrequest>DelegatingFilterProxy>LoginUrlAuthenticationEntryPoint>CustomUsernamePasswordAuthenticationFilter>AuthenticationManager>CustomAuthenticationProvider
Now I have a requirement to implement SSO (since the user is already asusmed to be authenticated) in some scenarios.
The requirement states that if I have a specific request parameter present then I need to automatically authenticate the request without bothering about user/password.
So it is same set of resources and I do not have to authenticate user/password if the specific SSO related request parameter is present.
e.g
suppose a resource \test\bus is a secure resource.
if I come from normal way then we need to check if the user is authenticated or nor and force user to put valid user/password
if I come from SSO channel then I need to show the \test\bus resource as the user is already authenticated.
currently all the access restrictions are put through <http> element
e.g the snippet of security-config.xml is as follows:
Query: What options do I have in this case. I can think of below options:
Pre-authenticate the user before spring security framework kicks in. This will mean creating an authentication token and putting in spring context before spring security filter is called. This can be done through another filter which is called before spring security filter chain. I have tested it and it works.
Create another custom security filter which set-up the authentication token. I am not clear if this is correct approach as not sure when do we create multiple custom security filter
Create another custom authentication provider e.g SSOCustomAuthenticationProvider. This provider will be called in the existing current flow as we can have multiple authentication providers to a authentication manager. The only issue is that in order to achieve this I have to change the request url to authentication filter's target url so that spring security doesn't check for authentication.
to explain more,
let's say request uri is /test/bus, I will write a filter which will intercept the request and change it to /test/startlogin. This is currently my CustomUsernamePasswordAuthenticationFilter's target url i.e
<property name="filterProcessesUrl" value="/test/startlogin"/>
The flow will be
inputrequest>DelegatingFilterProxy>LoginUrlAuthenticationEntryPoint>CustomUsernamePasswordAuthenticationFilter>AuthenticationManager>SSOCustomAuthenticationProvider
I have tested this and this works. Is this a valid approach or a hack.
Is there any other viable option available with me.
Thanks for reading this.

How to change password using Spring LDAP and Spring security

I'm using latest version of both Spring LDAP and Spring security. Also, I'm using annotation based configuration and I have no XML configuration files.
What I'm trying to achieve is really basic, I want to be able to allow users to change their password from my web application.
I've found that I could execute that request through DirContext.modifyAttributes. This method requires two attributes, the first one is the current userDn, which I'm not sure how to easily get through Spring. I'm pretty sure that there's a functionality to get it.
Then using a password Attribute as modification item for the second argument. Now, how can I know the password encoding that needs to be applied to the password provided by the user?
I've never used Spring LDAP / Security and a small, simple example would be awesome. Right now, I'm testing against in-memory ldap, but I'll have to switch to a real LDAP at the end of the week.
Thanks!
You need to use an instance of org.springframework.security.ldap.userdetails.LdapUserDetailsManager, it implements UserDetailsManager and has methods for changing user passwords. To instantiate it in your non-XML configuration, do something like this:
#Bean
public UserDetailsService getUserDetailsService() {
return new LdapUserDetailsManager(); // TODO give it whatever constructor params it needs
}

External authentication using Spring Security

We got our own central session management. Generally user can authenticate over it with an username and password, and as a result he gets an session_id. All other operations are done with that session_id. Let's say that the session management is accessed by a XML RPC.
I have two cases to implement:
Central web application made in Spring, which has login form
External web applications also made in Spring, which are relying on
passed session_id only.
Few more notices regarding system:
- session_id is stored in a cookie (after successful login, I have to add cookie to a response)
- every page request has to check session_id validity in session management system
I'm quite new to Spring, so I'm struggling to understand where and how to implement my custom logic.
My questions are:
What parts of a system I have to implement to have my own login
logic (got to have access to a response object too - to set cookie)?
I tryed something with extending UsernamePasswordAuthenticationFilter and implementing my own
AuthenticationManager, but I'm not sure that I'm going the right
way.
Is there point where/how can I implement my "every request session
check" in Spring Security manner?
session_id is stored in a cookie (after successful login, I have to add cookie to a response)
Do this in a AuthenticationSuccessHandler that is configured into your <form-login> element:
<form-login authentication-success-handler-ref="authenticationSuccessHandler"/>
External web applications also made in Spring, which are relying on passed session_id only.
Create a new filter where you check for the session_id cookie. If the cookie is not present or if it is invalid redirect to the central web application for the user to log in. If the cookie is present and valid and the user isn't already authenticated then create a new Authentication and add it to the SecurityContextHolder.
Take a look at RememberMeAuthenticationFilter.doFilter() for an example of what you want to do in your filter.
Add this filter to the filter chain using the <custom-filter> element.

Resources