Difference between WebMvcConfigurer and WebSecurityConfigurerAdapter - spring-security

What is the difference between those two? When do I use one over the other?
In the Spring Security Documentation it says that, among other things, WebMvcConfigurer has the following feature:
Require authentication to every URL in your application
The WebSecurityConfigurerAdapter example shown in HttpSecurity says:
Ensures that any request to our application requires the user to be authenticated.
Isn't that the same?
EDIT
These two types of configs seem to serve different purposes, I just don't quite understand yet, when to use which: What are the two distinct scenarios for each of the config types?
In the introduction to the HttpSecuriy section, it says
How does Spring Security know that we want to require all users to be authenticated? How does Spring Security know we want to support form based authentication?
So right now I am thinking: the first one says what should happen when authenticating a user and the second says in what cases do users need to be authenticated. Is that correct?
E.g., the first config "Generate a login form for you" and the second determines, when that login form should be shown?

This does appear to be a documentation bug (https://github.com/spring-projects/spring-security/issues/6809):
This raises confusion about the role of WebMvcConfigurer in Spring Security and the use cases for WebMvcConfigurer vs WebSecurityConfigurerAdapter.
Most likely the intention in the example was:
#EnableWebSecurity
public class WebSecurityConfig implements WebSecurityConfigurerAdapter {
instead of
#EnableWebSecurity
public class WebSecurityConfig implements WebMvcConfigurer {

Related

Spring Security - Custom authentication without provider?

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.

Add 'ROLE' to spring security / Auth0 authorization

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.

Configure DefaultMethodSecurityExpressionHandler using Spring Security Java Config

I was trying to use the Role Hierarchy feature provided by Spring Security in a Spring Boot application and I found some problems with the java config.
In that application, I've the GlobalMethodSecurity enabled in order to use the #PreAuthorize annotations. Because of that, what I need to do in order to use the Role Hierarchy support is to create a new instance of a DefaultMethodSecurityExpressionHandler and set an instance of a RoleHierarchyImpl instance with the configuration that we want (the role hierarchy itself).
Although, if I try to do this using a WebSecurityConfigurerAdapter and the configure(HttpSecurity http) method, I'm not able to do that because the .expressionHandler() is expecting a SecurityExpressionHandler<FilterInvocation> and the DefaultMethodSecurityExpressionHandler is a SecurityExpressionHandler<MethodInvocation>.
In order to solve this problem, I found out that the solution is to create a subclass of GlobalMethodSecurityConfiguration and override the method that is creating the ExpressionHandler bean like it's described in the docs
GlobalMethodSecurityConfiguration - Spring Security Docs
By saying this, I'm wondering if the .expressionHandler() method shouldn't also allow to do this configuration. If not, maybe a reference in the javadoc pointing to the GlobalMethodSecurityConfiguration would be useful.
After this, I think that the idea of WebSecurityConfigurerAdapter and the .expressionHandler are just applied to the security that is applied based on a Filter of the http request and it isn't supposed to be applied at the method level, but opinions and advices are welcome to confirm that I'm doing as it's supposed.

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
}

Writing aspectd to trap usernames after successful logins and logouts (Spring Security 3.0.X)

I'm writing a pair of aspects. The first is to trap usernames when users successfully authenticate against my web app and the other is to trap when they explicitly logout. I'm having trouble finding Spring framework methods which are called only once and which will therefore let me capture this information.
We are using a basic Spring Security 3.0 configuration, with our only additions being to provide our own UserDetailsService implementation.
Can anyone help?
It turns out that this was completely the wrong way to do this. Spring has a set of baked-in ApplicationEvent classes which you can create ApplicationListeners to catch. Strangely, there seems to be no "LogoutEvent" but there are the very useful AuthenticationSuccessEvent, AbstractAuthenticationFailureEvent, HttpSessionCreationEvent and HttpSessionDestroyedEvent. Most interesting of all is the RequestHandledEvent.
To catch these I created my own bean which implemented
org.springframework.context.ApplicationListener;
and overrode
public void onApplicationEvent(ApplicationEvent appEvent)
In this I just if/else my way through the various appEvent types and take the appropriate actions to track users and sessions.

Resources