Spring Security Expression Baed Access Control with JwtAuthenticationToken - spring-security

I'm working on an RESTful sevice that uses spring-boot-starter-oauth2-resource-server for security. It has some complex endpoint authorization requirements that involve decisions based not just on roles but on other claims in the JWT like location. So the HttpSecurity config's hasRole is not enough.
Is there a way to use values from the JwtAuthenticationToken with Sprng Security's expression baed access control and the HttpSecurity's access(String attribute) method? Or is there some other way to integrate different claims into endpoint authorization?
Any advice wuld be much appreciated

You have access to the Authentication object using SPEL,
so expressions like:
authentication.token.claims['preferred_username'] == ......
I have used it in methods:
e.g.
PreAuthorize("#createSupportQueryRequest.username == authentication.token.claims['preferred_username']")
public void createNewQuery(#RequestBody CreateSupportQueryRequest createSupportQueryRequest) {
But it should also work in .access method.
For more complicated stuff you can reference a bean class thats in your context in the expressions using the #.
e.g.
.access("#isPortfolioOwnerOrAdmin.check()")
This will call the check method on the IsPortfolioOwnerOrAdmin class.
Your bean class has access to the token via the SecurityConect and you can perform your complex verification logic there and return either true or false.

Related

spring security: what's the best practice for include value in permission?

In spring security, or RBAC, the Authority is described as a string, such as "download-file" means user can download file. If I need to limit user maximum daily download times and assign different values to different user, means the Authority contains dynamic values, how can I do this in spring security?
As you are alluding to there is a difference between authorities (i.e. roles) and permissions. Authorities tend to broadly apply for an application and have no state while permissions tend to be on specific objects and contain state.
This seems more like a domain problem than a permissions problem. Putting the logic into security feels a bit like having a form that must contain a valid email and checking the email format in security. I'd consider moving the logic outside of the security code.
If you really want to do this with Spring Security, I'd use a custom Bean that performs the check:
#Component
public class Download {
public boolean isAlowedForUser(Authentication authentication) {
// ...
return result;
}
public boolean isAllowedForCurrentUser() {
return isAllowedForUser(SecurityContextHolder.getContext().getAuthentiation());
}
}
Then you can autowire the Bean into your code and check the permission by invoking the code. If you prefer, you can also integrate into Spring Security's method security to perform the checks. To enable it you need to specify #EnableGlobalMethodSecurity(prePostEnabled = true) at the top of one of your configuration classes. Then you can use something like this on a Spring managed Bean:
#PreAuthorize("#download.isAllowedForCurrentUser()")
public void downloadFile(String fileName) {
Please refer this link
Spring Boot : Custom Role - Permission Authorization using SpEL
You can add new permission , like "DOWNLOAD_FILE" and authenticate if the current user has that permission using -
#PreAuthorize("hasPermission('DOWNLOAD_FILE')")
You can also limit access for Roles as well
#PreAuthorize("hasRole('ADMIN') and hasPermission('DOWNLOAD_FILE')")

Including Domain Object Security #PostFilter in Spring Data repositories Pageable endpoints

In my project I use Spring-Data, Spring-Data-Rest and Spring-Security.
What I need to accomplish is to implement domain object security (ACL) over these repositories. Specificaly #PostFilter over Pageable.findAll() method.
Method level security is easily implemented as outlined here.
There is also a section in docs about using security expression with #Query here.
But although I can use hasPermission(..) method inside #Query too, there is no way to include the object (SQL row) in this method - to be specific do this:
#Query("select u from #{#entityName} u where 1 = ?#{security.hasPermission(u, 'read') ? 1 : 0}")
Now I understand that this is way different than modifying the query pre-execution like this:
#Query("select m from Message m where m.to.id = ?#{ principal?.id }")
I also found the following jira issue:
https://jira.spring.io/browse/DATACMNS-293
Which I suspect that once it gets resolved there will be a solution to this, but it doesn't seem like it's going to be anytime soon.
I still need to implement this functionality and for that I would like to get your input and pointers on possible solutions.
Right now I am thinking about creating my custom annotation that will mimmick the #PostFilter one and use the same syntax but will get invoked manually inside my own BaseRepositoryImplementation. There I will get the repository interface from type and Repositories#getRepositoryInformationFor(type)#getRepositoryInterface(), find the annotation on respective method and manually invoke the security check.
Do you maybe have a different solution, or some notes about my proposed solution?
Also do you happen to know if there is any timetable on the mentioned jira issue?
One lightweight way is to do it is using the hasPermission() method and implementing your own "Permission Evaluator" at the Controller level, if that's an option for you.
#PreAuthorize("hasPermission(#employee, 'edit')")
public void editEmployee(Employee employee) {
...
}
#Component
public class PermissionEvaluatorImpl implements PermissionEvaluator {
#Override
public boolean hasPermission(Authentication auth,
Object targetDomainObject, Object permission) {
// return true if "auth" has "permission" permission for the user.
// Current-user can be obtained from auth.
}
...
}
This is described in more detail here: http://www.naturalprogrammer.com/spring-domain-object-security-logged-in-user/

SpringSecurity: how to specify remember me authentication?

I'm developing an app based on Grails and Vaadin 7. I managed to make them work with SpringSecurity for authentication and authorization, but I had to develop my own Service that calls the Spring Security authentication manager to make it work with Vaadin:
class SecurityService {
static transactional = true
def springSecurityService
def authenticationManager
void signIn(String username, String password) {
try {
def authentication = new UsernamePasswordAuthenticationToken(username, password)
SCH.context.authentication = authenticationManager.authenticate(authentication)
} catch (BadCredentialsException e) {
throw new SecurityException("Invalid username/password")
}
}
}
The problem is that now I need to implement a remember me authentication and I don't know from where to start.
How do I make the authenticationManager know that I want it to use remeberMeAuthentication? I can get a boolean value from a checkbox on the login View, but what do I do with it next?
Since your question is specific to the handling of checkbox value (remember me flag) coming from login page, the answer is that you have to call loginSuccess or loginFail method of RememberMeServices. The loginSuccess adds auto-login cookie in the response and loginFail removes that cookie.
But I guess above answer won't help you much unless you are sure that you have RememberMeServices configured in your app. Maybe following steps that configure RememberMeServices will help you do whole thing your way (or help you understand the out of the box functionality):
(1) Create a class (call it myRememberMeServices) that implements RememberMeServices and LogoutHandler.
(2) In autoLogin method, create an authentication object (UsernamePasswordAuthenticationToken) after parsing the cookie value.
(3) In loginFail method, cancel the cookie.
(4) In loginSuccess method, create an auto-login cookie. Add value that you would use in autoLogin method. Usually cookie value is encrypted.
(5) In logout method , cancel the cookie.
(6) Inject myRememberMeServices in following four places and call appropriate method:
(a) At the time of successful login (if checkbox value is set),
(b) At the time of failed login,
(c) On logout, and
(d) In filter that does autologin
It is worth noting that RememberMeAuthenticationFilter takes authenticationManager and RememberMeServices in its constructor.
Answer to your other question is that the authenticationManager doesn't need to know anything about remember me. It is the filter (or any class handling auto login) that needs to know about authenticationManager and RememberMeServices. (In other words, ask RememberMeServices for a token and pass it to authenticationManager to do auto login).
Spring Security's architecture is based on servlet filters. The sign-in mechanism you have implemented above is normally done by the UsernamePasswordAuthenticationFilter. Another filter called RememberMeAuthenticationFilter takes the responsibility for the remember-me functionality. The authenticationManager is not aware at all whether the remember-me feature is used by the application or not.
If you want to integrate Spring Security with another web-framework, first try to find out how the filters of the two frameworks can play together.

OData - Data Service Simple Authentication

I would like to add simple authentication to Data Services, for now only to restrict access for particular applications by simple token.
I don't need Domain Authentication or Forms authentication.
I read a lot about authentication here:
http://franssenden.wordpress.com/2010/06/14/custom-security-odata-service-wcf-data-services/
http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2008/06/03/10482.aspx
http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2008/01/15/10119.aspx
http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2008/01/10/10100.aspx
Unfortunately it all demands a loooot of work.
Most of all creating custom IHttpModule.
There should be more simple solution.
I know that when I create object context on the client (WPF) I can add Credentials.
Uri uri = new Uri("http://localhost/myapp/odata.svc");
MyEntities ent= new MyEntities (uri);
ent.Credentials = new NetworkCredential("token", "zx5as9vxc5sa9h0vb6523cv56");
But where can I read them (without implementation of custom IHttpModule)?
I thought that I can use something in class that is implementation of Data Service for example:
protected override void OnStartProcessingRequest(ProcessRequestArgs args)
{
string cred = args.OperationContext.AbsoluteRequestUri.UserInfo;
}
I'm not familiar with UserInfo but description for it stands "Gets the user name, password, ...)
So I have two main questions:
Where can I read Credentials included by typing ent.Credentials = new NetworkCredential("token", "zx5as9vxc5sa9h0vb6523cv56");
Where can I (if I can) set UserInfo on the client app and use it in OnStartProcessingRequest method.
Regards,
Daniel SkowroĊ„ski
There's a series of post about authentication and WCF Data Services (which is the .NET implementation of the OData protocol): http://blogs.msdn.com/b/astoriateam/archive/tags/authentication/
You should be able to find lot more information there (including code samples).

asp.net mvc authentication against shibboleth and authorization

Where do I get information about the currently connected user? That is, how does shibboleth pass the information?
Can I set some restrictions on actions using [Authorize] attribute based on data acquired from shibboleth?
Shibboleth publishes user attributes associated with
sessions into HTTP request headers, based on header names defined
in Attribute Acceptance Policy (1.3.x) or Attribute Mapping (2.x)
files. These headers are transformed into CGI variables based
on mapping rules defined by the CGI specification.
You should be aware of this security advisory:
http://shibboleth.net/community/advisories/secadv_20090615.txt
I have never user shibboleth, but you can get information about the user from Controller.User property. It will return a generic principal of current thread. Using this principal you can check whether the user is authenticated and get a login name of the user. This is due to the reason that after logon an authentication cookie is set and this cookie contains limited amount of information. And on each request after logon only this cookie is checked (if it exists and valid - user is authenticated).
So if you need in some specific information you can manually load a user (it's better to use cache here) and check whatever you want.
Also you can create and attach your own principal with necessary information to the thread on start of a request (e.g. on start of a request load the user from db/cache using user name from base principal, create and set your own principal to thread). After this you can check all properties of the user you need.
Where would you attach your own principal? You say on the start of the request but what if you don't want every request authorizing?
You'll want to create a method in Global.asax.cs that has the following signature
protected void Application_PostAuthenticateRequest()
{
//Your code here.
}
This will be called automatically before almost anything else is done (MVC will call this method if it exists, you don't have to "turn it on" anywhere), and this is where you need to set the Principal. For instance, let's assume you have a header called RolesHeader that has a comma separated value of roles and another header called UserId that has (duh) the user ID.
Your code, without any error handling, might look something like:
protected void Application_PostAuthenticateRequest()
{
var rolesheader = Context.Request.Headers["RolesHeader"];
var userId = Context.Request.Headers["UserId"];
var roles = rolesheader.Split(',');
var principal = new GenericPrincipal(new GenericIdentity(userId), roles);
Context.User = principal;
}
It's the Principal/Identity that the [Authorize] attribute uses, so setting it here at the beginning of the request lifecycle means the [Authorize] attribute will work correctly.
The rest of this is optional, but I recommend it:
I like to create my own custom classes that implement IPrincipal and IIdentity instead of using the GenericPrincipal and GenericIdentity, so I can stuff more user information in it. My custom Principal and Identity objects then have much more rich information, such as branch numbers or email addresses or whatever.
Then, I create a Controller called BaseController that has the following
protected new CustomPrincipal User
{
get
{
return (base.User as CustomPrincipal) ?? CustomPrincipal.GetUnauthorizedPrincipal();
}
}
This allows me to access all my rich, custom Principal data instead of just what's defined in IPrincipal. All of my real controllers then inherit from BaseController instead of directly from Controller.
Obviously, when using a custom Principal like this, in the Application_PostAuthenticateRequest() method, you'd set the Context.User to be your CustomPrincipal instead of a GenericPrincipal.

Resources