I just want to make sure if I get this correctly, so I would be thankful for any response; in my configure-override:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.
[...]
permitAll()
[...]
}
the permitAll() allows any request, while:
anonymous()
will only grant access for users that are not logged in but
in both cases a HttpSession-Object is created by default.
Is that right?
From the Spring documentation:
It's generally considered good security practice to adopt a “deny-by-default” where you explicitly specify what is allowed and disallow everything else. Defining what is accessible to unauthenticated users is a similar situation, particularly for web applications. Many sites require that users must be authenticated for anything other than a few URLs (for example the home and login pages). In this case it is easiest to define access configuration attributes for these specific URLs rather than have for every secured resource. Put differently, sometimes it is nice to say ROLE_SOMETHING is required by default and only allow certain exceptions to this rule, such as for login, logout and home pages of an application. You could also omit these pages from the filter chain entirely, thus bypassing the access control checks, but this may be undesirable for other reasons, particularly if the pages behave differently for authenticated users.
This is what we mean by anonymous authentication.
and
Note that there is no real conceptual difference between a user who is "anonymously authenticated" and an unauthenticated user. Spring Security’s anonymous authentication just gives you a more convenient way to configure your access-control attributes.
Using the .permitAll() will configure the authorization so that all requests(both from anonymous and logged in users) are allowed on that particular path.
The .anonymous() expression mainly refers to the status of the user(logged in or not).
Basically until a user is "authenticated" it is an "Anonymous user". It is like having a "default role" for everybody.
Related
I'm using Spring's expression-based authorization check system to configure that certain checks pass before a user is able to access certain paths of my API:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/objA/{id}/**")
.access("#objAChecker.checkAccess(authentication.principal, #id)")
.antMatchers("/api/objB/{id}/**")
.access("#objBChecker.checkAccess(authentication.principal, #id)");
}
Where objAChecker and objBChecker both have a checkAccess method that returns a boolean true only if the user may access the given object.
However, I would like to configure my security such that if a user is trying to access the objA, the security context's Authentication is updated to a new one that contains information relevant to objA, including a set of granted authorities that's only valid in the context of the objA that the user is requesting. That way, in my controller and service layer, I can take advantage of method-level #PreAuthorize annotations, using a set of granted authorities that's essentially "context-aware", because they'd be derived from the user and their relationship to the objA they're accessing.
My naive approach to this would be as follows:
In objAChecker.checkAccess, after fetching the objA, if user may access it, use SecurityContextHolder.getContext().setAuthentication to update the security context's authentication to one whose granted authorities are specific to the objA and user that's accessing it.
On a controller method, for example #GetMapping("/api/objA/{id}/data"), I would be able to place #PreAuthorize("hasAuthority('read_data')"), so that only users who have the read_data authority for the specific objA they're requesting can have access.
My question, then, is as follows: Is the above solution a valid way to achieve context-based granted authorities in Spring? Furthermore, is there a simpler approach built into spring security for solving this sort of problem that I'm not aware of?
When defining new spring boot REST resources, I tend to forget to also create a spring security configuration for their url patterns.
How can I, by default, deny access to all URLs, and only allow access to explicitly configured URL patterns? (I am using .hasRole for to allow access) I want to avoid as many unintended security holes as possible.
Let's say I have three REST resources: /jobs, /desks and /salary. My current code might look like this:
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/jobs")
.hasRole("my_user")
.antMatchers(HttpMethod.GET, "/desks")
.hasRole("my_user");
But currently, access to url /salary is provided to everyone (because it is not yet configured)!
Spring's Expression-Based Access Control has a denyAll expression which always evaluates to false.
So what you can do is use this denyAll method to deny access to everything, and then perhaps allow access to a certain URL(s) via hasRole:
http.authorizeRequests().antMatchers("/admin/**").access("hasRole('ADMIN')").antMatchers("/**").denyAll();
So for example, this will allow users with ADMIN access to access any page starting with /admin. And then it will deny access to all other pages. Note that the order is important as if you put in .antMatchers("/**").denyAll() first, it will deny all access and ignore the rest of your expression.
Or alternatively, you could use permitAll() for a certain URL pattern:
http.authorizeRequests().antMatchers("/users/**").permitAll().antMatchers("/**").denyAll();
Just to note that you might need to allow access to some way of logging in too, so the system can let someone log in with a specific role, so to combine it all together, and allow everyone to try login, only admin users to access the admin page(s) and deny all others, then something like:
http.authorizeRequests().antMatchers("/login").permitAll().antMatchers("/admin/**").access("hasRole('ADMIN')").antMatchers("/**").denyAll();
You can deny all requests by default with: .anyRequest().denyAll()
and explicit allow requests with .hasRole
anyRequest().denyAll() to deny all requests by default and
.hasRole to explicit allow requests
I'm using spring security to implement a programmatic, manual user login. I have a scenario where I have positively established the user's identity, and wish to log them in. I don't know their password, and so can't use the regular login code path where you submit a form to a url, which spring intercepts via a servlet Filter, doing all of it's auth+session magic.
I've searched, and it seems most people create their own Authentication object, and then tell spring about via:
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(user, "", user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
Indeed, this works. Spring even puts it into the session for me, making subsequent http requests maintain their auth status.
However, I feel like this is a dirty hack. I'll present some details that I hope will give concrete examples of the problems associated with using setAuthentication() inside a controller to achieve a manual login:
To give an idea, my config is:
httpSecurity
.authorizeRequests()
.antMatchers("/test/**").permitAll()
.antMatchers("/admin/**", "/api/admin/**").hasRole("USER_SUPER_ADMIN")
.and()
.formLogin()
.loginPage("/sign-in?sp")
.loginProcessingUrl("/api/auth/sign-in")
.successHandler(createLoginSuccessHandler())
.failureHandler(createLoginFailureHandler())
.permitAll()
.and()
.logout()
.logoutUrl("/api/auth/sign-out")
.logoutSuccessHandler(createLogoutSuccessHandler())
.and()
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry)
;
Key points in the above config:
I use custom success and failure handlers for the form login
I want to config behavior for max concurrent sessions per user
I want to maintain spring's default session fixation protection (changing session id upon login).
I want to use a session registry
... more of these session/login functionalities, had I chosen to config it.
I stepped through the code to see how spring processes a form login. As expected, Spring does all the session/login functionalities that my HttpSecurity config told it to do when I use the form login. But, when I do my own custom/manual login via SecurityContextHolder.getContext().setAuthentication(), it does NONE of those functionalities. This is because spring does all of it's session/login functionalities stuff inside of a servlet Filter, and my programmatic code can't really call a Filter. Now, I can attempt to add the missing functionalities myself, duplicating their code: I see that the spring Filter uses: ConcurrentSessionControlAuthenticationStrategy, ChangeSessionIdAuthenticationStrategy, and RegisterSessionAuthenticationStrategy. I can create these objects myself, configure them, and call them after my custom login. But, that's really lame to duplicate all that spring code. Furthermore, there's still other behaviors I'm missing - I noticed that when using the form login code path, that spring triggers some login events which don't get triggered when I do my custom login. And there's probably other stuff that I'm missing or don't understand. The whole process is pretty complicated, and I feel like there's a high chance of introducing bugs if this isn't done right, not to mention that library updates would be a pain if I started duplicating spring code.
So, I feel like I'm approaching this from the wrong way. Should I be using a different strategy, so that I'm not bypassing so much of the stuff that spring does for me? Maybe I should try to make my own AuthenticationProvider to accomplish this custom login?
*To clarify, my code more or less works. But, I feel like I accomplished it using a poor strategy because I had to write code duplicating a lot of stuff that spring does for me. Further, my code doesn't perfectly replicate what spring does, making me wonder what negative implications might result. There must be a better way to programatically achieve login.
I wanted to elaborate on how I implemented the advice of dur. In my scenario, I only used a custom AuthenticationProvider.
Instead of creating a custom servlet Filter, such as extending AbstractAuthenticationProcessingFilter, which seemed like a lot of work, I choose to instead use the following strategy:
At the point in my code where I was confident that I had identified the user, and wanted them to be "logged in", I stuck a flag in the user's session, marking that they should be logged in on the next request, along with any other identity/bookkeeping info I needed, such as their username.
Then, I told the browser client to make an http post to the loginProcessingUrl (the same one I configured spring security to use for form-based login), telling them to send the standard username and password form params, although they don't need to send real values - dummy values like foo are fine.
When the user makes that post request (eg to /login), spring will invoke my custom AuthenticationProvider, which will look in the user's session to check for the flag, and to gather the username. Then it will create and return an Authentication object, such as PreAuthenticatedAuthenticationToken, which identifies the user.
Spring will handle the rest. The user is now logged in.
By doing it this way, you stay within the "normal" way of doing logins, and so spring will still automatically:
Call any custom success and failure handlers you configured for the form login, which is nice if you use that place to do certain things on login, like query or update a db.
It will respect any max concurrent sessions per user settings that you may be using.
You get to keep spring's default session fixation attack protection (changing session id upon login).
If you set a custom session timeout, eg via server.session.timeout in a properties file, spring will use it. There's probably other session config attributes that are done at this time too.
If you enabled spring's "remember me" functionality, it will work.
It will fire a login event, which is used for other spring components, such as storing the user's session in a SessionRegistry. I think the events are also used by other parts of spring, such as the actuator, and for auditing.
When I first tried just doing the typically recommended SecurityContextHolder.getContext().setAuthentication(authentication) to login my user, instead of the custom AuthenticationProvider, none of the above bullets were done for me, which can utterly break your app... or cause subtle security bugs - neither are good.
Here's some code to help solidify what I said:
Custom AuthenticationProvider
#Component
public class AccountVerificationAuthenticationProvider implements AuthenticationProvider {
#Autowired
private AppAuthenticatedUserService appAuthenticatedUserService;
#Autowired
private AuthService authService;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// This will look in the user's session to get their username, and to make sure the flag is set to allow login without password on this request.
UserAccount userAccount = authService.getUserAccountFromRecentAccountVerificationProcess();
if (userAccount == null) {
// Tell spring we can't process this AuthenticationProvider obj.
// Spring will continue, and try another AuthenticationProvider, if it can.
return null;
}
// A service to create a custom UserDetails object for this user.
UserDetails appAuthenticatedUser = appAuthenticatedUserService.create(userAccount.getEmail(), "", true);
PreAuthenticatedAuthenticationToken authenticationToken = new PreAuthenticatedAuthenticationToken(appAuthenticatedUser, "", appAuthenticatedUser.getAuthorities());
authenticationToken.setAuthenticated(true);
return authenticationToken;
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
Config spring security to use the provider
// In your WebSecurityConfigurerAdapter
#Configuration
#EnableWebSecurity
public class AppLoginConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AccountVerificationAuthenticationProvider accountVerificationAuthenticationProvider;
#Autowired
private ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider;
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
// Spring will try these auth providers in the order we register them.
// We do the accountVerificationAuthenticationProvider provider first, since it doesn't need to do any slow IO to check,
// so it's very fast. Only if this AuthenticationProvider rejects (which means this http request is not for programmatic login), will spring then try the next AuthenticationProvider in the list.
authenticationManagerBuilder
.authenticationProvider(accountVerificationAuthenticationProvider)
// I'm using ActiveDirectory / LDAP for when a user logs in via entering a user + password via the html form, but whatever you want to use here should work.
.authenticationProvider(activeDirectoryLdapAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
...
}
}
For custom web authentication you should implement combination of a custom authentication filter (for example AbstractAuthenticationProcessingFilter or just GenericFilterBean), a custom authentication provider (AuthenticationProvider) or/and custom authentication token (AbstractAuthenticationToken).
For example, see source of Spring Security Kerberos.
See also:
The AuthenticationManager, ProviderManager and AuthenticationProvider
I would like to ask if there is a point to secure the methods which I call in a REST Controller with Pre and Post annotations. I have configured a security through java configuration like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.and()
.formLogin()
(...)
.and()
.authorizeRequests()
.antMatchers("/api/**").hasAuthority("ROLE_USER");
}
So every request under /api should be authorized with ROLE_USER. I tried to find some information about this in the internet but the only thing i could find was this:
https://coderanch.com/t/549265/Spring/method-security-spring-security
However I really can't think of a use case where a hacker would access somehow the methods in the service layer.
URL security and method security in service layer aims at different use cases.
If all you need is control that only users with a certain role can call URL with a given prefix (here API) URL security is what you need full stop.
If you have a complex application where some service methods can be called from different controllers and you want to make sure that you did not fail to restrict an access, method security can come to help by ensuring that only valid users can do certain business actions.
If you have a complex security model, for example several officse with one manager in each that has read and/or write access to his own employees data, method security on service layer directly using business model objects is the way to go.
BTW, using method security in a controller or even worse on a rest controller is generally design smell: if you can do it inside a controller it is generally better to use URL security. If it seems to make sense, you probably have imported business logic into a Fat Ugly Controller. Not speaking about method security being implemented with Spring AOP using by default JDK proxies, when controllers generally do not implement interfaces.
In addition to making it possible to have some kinds of functionality, using both techniques gives an additional layer of security.
Method level security is used to authorize the user. Spring security performs two basic operations before allowing the access.
Authenticate (Who is the user)
Authorize (What authorities the user has)
so for example if the user is having an authority of ROLE_USER and later in the architecture you decide to have rights assigned to some of the roles.
for example let's consider a role 'ROLE_USER'
and following rights has been assigned to the USER
CAN_VIEW_DATA
CAN_ADD_SUB_USERS
and so on.
so when some of the users have the right of CAN_ADD_SUB_USERS and some dont, then the method level security comes in handy.
Of course you have to play with the spring configurations for the rights and authority. But Once configured it provides an extra level of security that the applicaton might need.
Refer to this link for more info http://www.baeldung.com/role-and-privilege-for-spring-security-registration
REST is stateless. You should send something like access token (like Google API) with every request:
https://{server}/api/customers?access_token=BGhznFGDS
You can also send this information via Header-Attribute. The validation layer (Filter) decides whether the controller method may be called or not.
I prefer to implement my own Filters to get 100% of control.
I am studying for the Spring Core certification and I have some dobut related the meaning of this Spring Security diagram finding into the documentation:
It explain what is the architecture of the Spring Security projects and the interaction between its components but what exactly mean?
It show an Authentication Manager component, reading on the documentation I found that it handles authentication requests from other parts of the framework so I think that it provide something like an interface with some methods to perform the autherntication operations and that this interface it will be implemented by a specific authentitication providerd (according to the authentication technology choose)
What means that the Authentication Manager populates the Security Context. What exactly is the *Security Context** in Spring? Is it a "place" where are stored the information related to the Principal (for example an user authenticated on a web application) and the list of the authorizations of this principal on the secured resources? (for example the logged user and what operations this user can perform on the secured resources?) Is it right or am I missing something?
Then there is a Security Interceptor that I think have to be a proxied class that use something like a before advice AOP mechanism that perform a security advice befeore some specific joint point. Thee jointpoint are the operations on the secured resource (for example the method execution on a secured bean).
Looking at the picture I think that the proxy obtain this information from the Security Context that contains the principal (the logged user) and its authorizations (what operations can do this logged user) so it can create the before advices to check this operations. Is it right or am I missing something?
What represents the AccessDecision Manager component? and what are the voters showed into the picture?
Tnx
The security-context contains the security information about the current user (name, login, privileges...). It is bounded to the current thread and session https://stackoverflow.com/a/6408377/280244
The Authentication Manger will put ( poulate ) the security information about the user when he login into the security context.
The Security interceptor (Method or Http Request) will intercept the invocations before they invoke an protected/secured resource. It obtain the information about the current user from the security context. What the requies rules to allow the invocation are, are obtained form some configuration (xml, annotations, ...). The decision about that the current user matches the required rules are delegated to the Access Decision Manger
The Access Decision Manger does not implements the desision rules by its own, instead it uses (different) Voters that vote for access granted, access denied (or abstain).
#See: Spring Security Reference: Chapter 13 Authorization Architecture