Spring Security: Method Level Security Prevent Access to a Role - java

Using Spring Security 5.2.X (latest currently), I need to prevent the access to a third party role to all methods but one in a SOAP service. In other words, I need that particular role to have access only to one particular method among all of the availables in the service.
Normally, a usual method level securization consists of annotation with #Secure("MY_ROLE"). This makes the method only to be accessible for that role.
Is it possible to tell Spring Security Core to do the opposite. I.e, configure it in a way that certain user only has access to the secured method.
Of course, the workaround could be:
// Method accessible by anyone but third party role
#Secured({"GOOD_ROLE1", "GOOD_ROLE2", "GOOD_ROLE3"})
public void methodAccessibleByAnyoneButThirdPartyRole(){
}
// Method accessible by anyone, including third party role
#Secured({"GOOD_ROLE1", "GOOD_ROLE2", "GOOD_ROLE3", "THIRD_PARTY_ROLE"})
public void methodAccessibleByAnyone(){
}
Other workaround would consist of just creating a new service only with the method to be restricted.
But is there any annotation option to get the same straightaway? Something like #PreAuthorize("!hasRole('THIRD_PARTY_ROLE')") or similar?

According to Spring Security doc you can use any Spring Expression Language (SpEL) in #PreAuthorize
Any Spring-EL functionality is available within the expression, so you
can also access properties on the arguments. For example, if you
wanted a particular method to only allow access to a user whose
username matched that of the contact, you could write
#PreAuthorize("#contact.name == authentication.name")
public void doSomething(Contact contact);
So you can use:
#PreAuthorize("!hasRole('THIRD_PARTY_ROLE')")
Also as more readable variant:
#PreAuthorize("not hasRole('THIRD_PARTY_ROLE')")

Related

Role based authorization in spring boot

I am new to Spring boot. I need to implement role based authorization in spring boot. I am having different roles and multiple users will be mapped to each role. I will be setting different access (read, add, delete, edit)
Whenever an api gets called, need to check the access and allow permission.
I am planning to use interceptor to call method having the query to get the access from DB and deny or access the api.
Is there any other better way I can use for the same?
If you are using Spring Security you can handle it with method security annotations like #PreAuthorize, #PostAuthorize .. even combine them to new annotations.
First your User need to implements UserDetails then you should implement getAuthorities() method according to your Role and Authority structure Spring Security basically checks what getAuthority() method returns if returned value prefixed with "ROLE_" like "ROLE_ADMIN" it will be processed as ROLE if it does not prefixed with "ROLE_" it will be processed as Authority
you can use method annotation for checking authority and role like following example:
#PreAuthorize("hasRole('ROLE_ADMIN') and hasAuthority("READ")")
and Spring Security will check your granted Authorities by getAuthorities() implementation of your User then, according to your annotation it will be checked automatically by Spring Security behalf of you.
For clarity you can check
https://www.baeldung.com/spring-security-granted-authority-vs-role
For quick working implementation you can check article below(I would not directly use it but you can understand the idea. Also you can use permissions but simple solution probably the solution below.):
https://www.baeldung.com/role-and-privilege-for-spring-security-registration
For authorization, there can be these two ways as well:
OAuth (Reference - https://medium.com/#bvulaj/mapping-your-users-and-roles-with-spring-boot-oauth2-a7ac3bbe8e7f)
Spring Security Roles and Privileges(Reference- https://www.baeldung.com/role-and-privilege-for-spring-security-registration)
You can create a custom annotation to handle request for each role. I you can read this article for more details about how to implement.
And in api will have format:
#GetMapping(...)
#YouCustomAnnotation("roleName")
public void doSomeThing(){
}
This api will be called if role of user matched with role define in annotation and server will return 404 code if user's role not match.

How to apply validation of method param value in java using annotation?

I'm trying to achieve object-based access control using annotations. Would like to verify user's access to a specific object with minimal code.
Assume i have a spring mvc request handler:
public String updateForm(Form form){
//update form
formService.updateForm(form);
}
I would like to add annotation which can validate based on spring security's logged in user if the user has access.
#ValidateAuth
public String updateForm(Form form){
//dont allow if no auth
//update form
formService.updateForm(form);
}
Now the annotation should consider the form's id(form.getId()) as well as logged in user principal to check if the auth is allowed. I'm trying to see if there is a way to do it via aop where we can read a argument's value as well in a neat way.
Kindly help, thanks in advance.
Spring Security has out-of-the-box support for ACL.
It is covered in this section of the Spring Security reference guide.
When configured you can use the #PreAuthorize tag with an expression to allow or disallow access to the method. You could also filter results from a method.
#PreAuthorize("hasPermission(#form, 'admin')")
public String updateForm(Form form){ ... }
You can also make it a bit more complex
#PreAuthorize("hasRole("ADMINISTRATOR") and hasPermission(#form, 'admin')")
public String updateForm(Form form){ ... }

Can you use Java Annotations to evaluate something in a method?

I want to see if it is possible to use annotations to evaulate if a user is logged in or not.
Example
#AuthRequired
public String myProtectedArea() {
return View("view/protectedArea"); // If user is NOT authenticated, return "view/login"
}
As per your edit:
Check this SO Post:
Scanning Java annotations at runtime
I'd still recommend using Spring Security for this, it's tested and secure:
#PreAuthorize("hasRole('ROLE_USER')")
public String myProtectedArea() {
return View("view/protectedArea");
}
The annotation will check if the user is logged in and has the required credentials.
Another way with Spring Security is to intercept the URL pattern by setting this inside a spring.security-settings.xml:
<intercept-url pattern="/view/protectedArea/*" access="hasRole('ROLE_USER')" />
I'd recommend using both to maximize security.
In the security settings file you can then tell spring security where to redirect the user to login. If the user is already logged in, you can redirect him to yet another page:
<form-login login-page="/view/login.xhtml" default-target-url="/view/protectedArea/home.xhtml"
authentication-failure-url="/view/login.xhtml" />
It's a tested framework and thus secure and versatile. However it requires a bit of setting up if you want more than the standard behaviour.
The annotation doesn't check if the user is logged in or not--annotations are metadata on classes/methods. Something must still make use of the annotation.
Something in your code checks to see if the method is annotated with #AuthRequired, if it is, checks if logged in, then executes the method based on that.
For example, a web app might look for the annotation in a filter, base servlet, interceptor, etc. and decide whether or not the request process should continue.
Depending upon what type of application you are creating there are a number of options available to you for defining authentication levels for specific methods.
I would most likely recommend to you Spring Security for such a task.
Something like the below example would be the end result after configuration using Spring Security.
#Secured( {"USER_ROLE"} )
public String getSecretData() {
return "SECRET! SHHH!";
}
Then only users verified by Spring Security to have the role you provide to the annotation will have authorization to call the method.
There are a couple other annotation options in Spring Security you can utilize such as #PreAuthorize.
Instead of re-inventing the wheel, have a look at JAAS:
http://docs.oracle.com/javaee/6/tutorial/doc/bncbx.html#bncca
http://docs.oracle.com/javaee/6/tutorial/doc/bncas.html
http://docs.oracle.com/javaee/6/tutorial/doc/gijrp.html
http://docs.oracle.com/javaee/6/api/javax/annotation/security/package-summary.html

Using Aspect Oriented Programming for user authentification in Java?

I like to add an user authentification to my REST webservice (Guice + Jersey).
I first wanted to solve the authentification with the Google Guice method interceptions. For example:
#Path("user")
public class User {
#OnlyAdmin
#Post
public void addUser(String apiKey) {
}
}
But unfortunately Guice only support AOP for classes with a no-argument constructors.
Is it generally a good idea to use AOP for user authentification?
Are there other frameworks to build an user authentification?
Edit: Framework is maybe the wrong term. I'm only looking for a way to inject some code in every annotated method and this code should check the parameters of the method
The only important point for AOP to work in your case is that your classes get created by Guice.
If you have constructors with arguments, ensure that they are injectable (directly or with assisted injection).
It wouldn't be AOP but you could inject a current user role bound to the request scope wherever the user needed to be checked and use either method intercepts or explicit logic to check that the right user class is performing some action.

Is it possible to implement method-level access checks with annotations?

Consider some basic authorization framework with Users and Groups where access to methods should be guarded by checks which make sure that the user or the group have the necessary PriviledgeLevel to execute the method and fails otherwise.
What I imagine is something like this:
#AccessCheck(PriviledgeLevel.ADMINISTRATOR)
public static void secureMethod(){ ... }
Where the code checking basically does
if(currentUser.getPriviledgeLevel >= PriviledgeLevel.ADMINISTRATOR ||
currentUser.getGroup.priviledgeLevel >= PriviledgeLevel.ADMINISTRATOR)
// Allow access
else
// Deny access
Would it be possible to implement it this way?
I did a bit of research which points to some existing things based on AspectJ, mostly on the Security Annotation Framework (SAF) and on Spring Security.
I'm a bit concerned because SAF doesn't seem very active anymore and the documentation isn't that great.
I'm not sure about Spring Security but it seems to be more focused on security problems in web-related topics.
The Java Authentication and Authorization Service seems to be related, but doesn't use the annotation approach.
Does it make sense trying to define these security requirements with this declarative approach?
Is there another library/framework I'm missing, which already implements what I want or some techonology which would be relevant here?
Or is there a completely different solution (like implementing my own ClassLoader, ...) which is superior to what I imagine (in terms of conciseness and readability for the library user)?
I think AspectJ will do what you want it to do. We have a whole bunch of methods which you need certain access rights for and we've created an AspectJ aspect which will check that and error out if the user does not have those permissions.
As a plus, because AspectJ is "woven" into the classes at compile time it cannot be disabled by configuration.
We also use Spring Security, it is possible to use both in harmony!
You could do this fairly trivially yourself by using dynamic proxies.
public interface MyInterface {
#AccessCheck(Privilege.ADMIN)
public void doSomething();
}
The proxy would be created on the class that implements your interface and you would annotate your interface with your custom annotation.
MyInterface aInterface = (MyInterface) java.lang.reflect.Proxy.newProxyInstance(obj.getClass()
.getClassLoader(), obj.getClass().getInterfaces(),
new YourProxy(new Implementation());
In the invoke() method of your proxy, you can check if your method has the annotation and throw a SecurityException if the privileges are not met.
public YourProxy implements InvocationHandler {
....
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ( method.isAnnotationPresent(AccessCheck.class) {
....// do access check here and throw SecurityException()
}
}
With Spring Security, you just have to add:
#Secured("ADMINISTRATOR")
public static void secureMethod(){ ... }
And configure it properly, by:
use JdbcDaoImpl as your UserDetailsService
enable group support
customize the queries (if you are using database credential storage)
If you are not using database credential storage, just configure your preferred UserDetailsService to add both user and group credentials to the authorities of the generated UserDetails.
Of couse, it is hard to understand it without checking the concepts at the documentation, but method level access checks is perfectly possible with spring security and it's my prefered technology for it.
In Spring Security, as the docs state, both #Secured and #PreAuthorize can be used at method level.
To enable #PreAuthorize (if you haven't already...), you need to put <global-method-security pre-post-annotations="enabled" />
in your configuration XML;
For #Secured use <global-method-security secured-annotations="enabled" />.
For more details, refer to this article.

Categories

Resources