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

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){ ... }

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.

Spring Security: Method Level Security Prevent Access to a Role

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')")

Ensure a particular user can only see their own user details - Using Spring

Working with Spring / Spring security on a small project at the moment and having difficulty implementing this feature. Ideally I only want user1 to view the details of user1 and not those of 2,3 or 4 for example.
I've implemented Spring Security with Roles and understand that I can retrieve a UserDetails object or a principle, I'm not sure exactly but I know I can retrieve the details of the current logged in user using one of, what appears to be many methods.
This is what I'm currently using as a proof of concept when we go to the Admin/home page:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Gamer gamer = gamerService.findGamerByEmail(auth.getName());
System.out.println("Auth: " + auth.getName());
System.out.println("Gamer: " + gamer.getName() + gamer.getId() + gamer.getEmail());
The security config takes care of whether or not the current user can access because of the roles assigned to it.
I believe I should be able to go to the url of /mysite/viewUserDetails and have that page display information of the current user but I cannot find any examples of this, I've found plenty of example that prove a logged in user can view a page but none that specify checks in place to ensure user1 can only view user1's details.
On an older page I do this to display information for a particular user but I understand this to be bad practice-
<a th:href="#{/gamer/{gamerid}/games/excited (gamerid=${gamer.id}) }">
*Worth noting that this isn't using any form of login/registration to pull out this info, I'm simple using the id I pass in as part of the DB query.
It maps onto :
#RequestMapping("/gamer/{gamerid}/games/excited")
public String getExcited(#PathVariable final Long gamerid, Model model){
addGamerListAttributes(model, gamerid, "EXC");
return "games";
}
So my question becomes, and I hope you can point in the right direction, How can I implement a solution where a user can only view his/her details and how should this be represented via the form and connecting controllers as passing ids in the url is kinda ugly (I could use a guid but...)
Thanks so much in advance.
It's actually quite an easy choice. Either you have an entry point like:
#RequestMapping("/gamer/{gamerid}/games/excited")
and you manually check that the user in session can access the requested resource, or you have something like
#RequestMapping("/my-games")
that automatically reads the user id from the security context.
More than a security choice, I'd pick one depending on code reuse and future use-cases (for example the same page/set of pages can be seen by more than one user).
Have a look at #PreAuthorize annotation. It is possbile to annotate given endpoint with it and create custom logic in a bean. Then you can use custom method to allow or disallow the endpoint to proceed :
#Controller
public class HomeController {
#Autowired
private AuthenticationService authenticationService;
#RequestMapping("/gamer/{gamerid}/games/excited")
#PreAuthorize("#authenticationService.hasAccess(#gamerid)")
public String getExcited(#PathVariable final Long gamerid, Model model){
addGamerListAttributes(model, gamerid, "EXC");
return "games";
}
}
Service class :
#Service
public class AuthenticationService {
public boolean hasAccess(String tgamerid) {
//implement logic here
return true;
}
}
Method hasAccess in the AuthenticationService should return boolean. #PreAuthorize will be launched before controller handler method is invoked. The controller above is just an example. You can pass Authentication object in SPeL expression in #PreAuthorize annotation to service method or get it from security context inside service class, to implement logic which fits your needs. More information can be found here and in Spring Docs.

How to define access condition based on #PathVariable or #RequestBody in Keycloak?

We are using Keycloak v6.0.0 and Spring Framework. We want to define some access conditions based on #PathVariable value and #RequestBody fields value in Keycloak admin panel, but we can't find any way to do this. How can we access these fields value and define Resource or Policy based on it?
I think that it will help you the Admin REST API. Also, I've write a Keycloak-Client in Kotlin for some basic APIs like: signUp, login and logout. Maybe it will help you.

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

Categories

Resources