I need to restrict edtiting functionality in my Vaadin 12 app basing on user assigned roles
Currently we have page level security, i.e user can see only pages basing on assigned roles, like #Secured(Role.VIEW_PAGE)
User must see view button when view role assigned and see edit button when edit role assigned.
You can use this method for this, which accepts one Role and looks if the users authorities contain this Role. It basically does the same as SecurityUtils.isAccessGranted(securedClass) only it looks for a specific role and not the roles defined in the #Secured annotation of a view.
public static boolean userHasRole(Role role){ // your own Role class/enum
Authentication userAuthentication = SecurityContextHolder.getContext().getAuthentication();
List<String> allowedRoles = Arrays.asList(role.name());
return userAuthentication.getAuthorities().stream().map(GrantedAuthority::getAuthority)
.anyMatch(allowedRoles::contains);
}
A good place to define this method is the already mentioned SecurityUtils class if you already have it. If not, now is a good time to create one ;).
You can now call the method like this in your view:
if(SecurityUtils.userHasRole(Role.EDIT_PAGE)){
add(new Button("Edit"));
} else {
add(new Button("View"));
}
If you wish, you can of course change this method to accept a list of roles instead of only one.
Related
Let's consider we have two entities. User entity can have many offers and an Offer must have one User.
class User {
...
#OneToMany(mappedBy = "user", orphanRemoval = true)
private Set<Offer> offers;
}
class Offer {
...
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "fk_user")
private User user;
}
At this moment there are two controllers. UserController and the OrderController. The UserController is mapped under /api/v1/users/ and the OrderController is mapped under /api/v1/orders/.
What should an endpoint look like that fetches the user's offer list?
Should it be in the same controller? I do have by functionality project structure.
How to modify or delete an Offer for a particular User? In case we would have /api/v1/users/{username}/offers/{offerId} to delete or update an offer, should we have also /api/v1/offers/{offerId} endpoint that allows to edit or remove an offer? Perhaps it is worth having it for an administrator?
General rules of thumb that I use when creating my endpoints are:
URLs need to be clean and easy to understand
They should be as short as possible while still informative.
Try to build it in a such manner that it allows you to reuse it within the reasonable amount
Think about the user experience(whether this is called from browser or mobile app etc.)
I am not sure if there is a written rule exactly how one should build an URL though.
In your specific case I would use /users/{username}/offers/{offerId} only if this is the only place you are exposing and using offers, since you are separating your code by functionality.
If you have any further logic around offers and/or have beans that have such logic I would create a separate controller for Offers which would be under /offers.
Concerning your last question. This very much depends on what you are trying to achieve. If you need to be able to update/delete/create offers then it makes sense to have such functionality. Even if it only used by the administrator. You can restrict the access to the endpoint. How to do that depends on the way you are authorize your users and the information that you have on them. Most people use roles.
If you decide to have the full CRUD functionality I would suggest to use a single path with combination of request methods.
Personally I would create the following:
#RestController
#RequestMapping(value = "/users")
class UserController {
#GetMapping("{userId}/offers")
public Set<Offer> getAllOffers(#PathVariable("userId") String userId){
...
}
#GetMapping("{userId}/offers")
public Offer getOffer(#PathVariable("userId") String userId, #RequestParam(required = true) String offerId){
...
}
#PutMapping("{userId}/offers")
public Offer createOffer(#PathVariable("userId") String userId, #RequestBody Offer offer){
...
}
#PostMapping("{userId}/offers")
public Offer updateOffer(#PathVariable("userId") String userId, #RequestBody Offer offer){
...
}
#DeleteMapping("{userId}/offers")
public void deleteOffer(#PathVariable("userId") String userId, #RequestParam(required = true) String offerId){
...
}
}
In this scenario I think the POST/PUT for create and update will be cleaner as there will be no duplication of information. To be precise the IDs.
I agree that it should be in the same 'UserController', it makes sense because offers belong to the user, so having an endpoint like:
#GetMapping("{user}/offers")
public Set<OfferDTO> getOffers(#PathVariable("user") String user) {
return offerService.getOffers(user);
}
You can define special DTOs for getting the meta-data from the offers if you wanted to display them in a list for example, and you could display them as a list to your user.
You could set up a similar endpoint for updating the offer which could be a POST endpoint, and a DELETE endpoint for deleting. You might want to think about what would happen if the user is looking at an offer when you delete it though, like making an asynchronous task for deleting the offer in a background thread and updating the UI to inform the user that the offer is deleted.
Spring has some really nice annotations for security stuff (check this and this), you could write your own annotation for administrator endpoints:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasAuthority('" + ROLE_ADMIN + "')")
public #interface IsAdmin {}
Then annotate your method like this:
#DeleteMapping("/{user}/{offer}/delete")
#IsReceiverAdmin
public void delete(#PathVariable("user") String user, #PathVariable("offer") String offer){
return offerService.delete(user, offer);
}
Of course the implementation of the service layer would be quite important, but it could be as simple as calling your repositories and performing the operations there :)
I am looking to use Spring Security w/ MySql to store Users, Roles, Permissions (authorities). I have done the following:
ApplicationUser (id, firstName, lastName, username, password, roles)
ApplicationRole (id, name, description, permissions) implements GrantedAuthority
ApplicationPermission (id, name, description) implements GrantedAuthority
I created a class that implements UserDetailService. In the loadUserByUsername method I doing the following:
ApplicationUser applicationUser = userRepository.findByUsername(username);
if(applicationUser == null) {
throw new UsernameNotFoundException(username);
}
// Extract role/role permission grantedAuthorities from db user
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
for (Role role: applicationUser.getRoles()) {
grantedAuthorities.add(role);
grantedAuthorities.addAll(role.getPermissions());
}
return new User(applicationUser.getUsername(), applicationUser.getPassword(), grantedAuthorities);
However, this still leaves me a bit confused and here are a few of my questions...
Is it necessary to implement GrantedAuthority on my ApplicationRole
and ApplicationPermission class. I don't see others doing it in many
examples that I have seen but it appears to have made my life easier
so I can just get them and pass them in as is.
I have not
implemented UserDetails with my ApplicationUser class. If I were to
do this what would be the purpose? Is the only reason so I would be
able to customize the getAuthorities, isAccountNonExpired,
isAccountNonLocked, isCredentialsNonExpired, isEnabled methods? Is
there even a default implementation of these methods or only if I
create my versions. Why would I need to implement getAuthorities
here if I am already doing it with loadbyUserName in
UserDetailsServiceImpl?
What is the purpose of SimpleGrantedAuthority? I see it implements GrantedAuthority and only accepts a String name. However, I don't feel like I need to use it since I implemented GrantedAuthority with my ApplicationRole and ApplicationPermission classes.
I think my problem is that I am confused as to when/how to properly implement UserDetail and UserDetailService making sure I am loading the authorities from the database and setting them each time a user logs in. Additionally, is there any point in implementing GrantedAuthority with my ApplicationRole and ApplicationPermission class the way I am?
It's not necessary and I wouldn't recommend it either. It's good to keep these different aspects of your application separate. As far as I know it's a common practice to fetch the roles in your custom UserDetailsService and wrap their textual representation in a SimpleGrantedAuthority (i.e. their name). Note that to differentiate between roles and authorities within Spring Security you have to prefix roles with the ROLE_ tag by default (see hasRole and hasAuthority access-control expressions).
Having a custom UserDetails implementation is not necessary but might have benefits, for example you can store extra fields that are specific to your application. The default implementation is org.springframework.security.core.userdetails.User, most of the time you can just extend this one.
See #1
is there any point in implementing GrantedAuthority with my ApplicationRole and ApplicationPermission class the way I am?
It wouldn't make any sense, no. Many use-cases are covered by the existing implementations, but for the most simple use-cases you can just stick to SimpleGrantedAuthority.
I have a RESTful service that exposes resources like /user/{id}
Now, the user can provide the credentials, get the token and access the resource. However, once authenticated, the user can access the resources for any id.
Meaning, user1 can access the URIs like /user/1 as well as user/2 and so on. I ended up using a Principal in the controller methods and started checking the id of the Principal with the id the user is trying to access.
Further, the user has multiple resources associated with it. Say, user1 owns res1 and res2, user2 owns res3 and res4. These can be accessed via /user/1/res/2. I need a way where I can prevent /user/1/res/3 as res3 is owned by user1 and not user2.
But I believe that this problem is very common and I am not really convinced with my solution.
Is there a better way to deal with this problem?
Thanks
You should not be exposing resourse /user/{id} at all if you all user can do is access only their own ID.
If I understand correctly, just exposing /user is enough, find ID of user from Principal or session etc and return result.
If you really want to do it, you can have custom implementation of #PreAuthorize. Got this code from a blog.
#PreAuthorize("isUsersRes(#id)")
#RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
public UsersfindById(#PathVariable long id) {
return Users.findOne(id);
}
public class CustomMethodSecurityExpressionRoot
extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
public CustomMethodSecurityExpressionRoot(Authentication authentication) {
super(authentication);
}
And implemenation of isUsersRes
public class CustomMethodSecurityExpressionRoot
extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
public boolean isMember(Long OrganizationId) {
//user logic
}
Check complete blog here
This is a common problem with varied solutions. Also its not a problem related to REST alone. We have had this ever since apps exist. Employee can see his salary slip, leave records, etc but not another employee's.
One solution I like the most is 'security in depth'. This idea comes from how I have seen this work in banking systems for decades. This needs to get supported in the DB layer first.
You would need a table design like this example (or whatever your app's entity hierarchical structure is):
Organisation
-Dept
--user
And all non-master tables need to have a relation to one of these entities. Example:
Payslip -> user
Leave record -> user
Manager -> dept
HR Manager -> org
etc...
You would need another table to map out the basic access levels (This can get complex if we need to implement different sub access levels)
user1:dept2:org1
user2:dept2:org1
(I have seen some implementations that send this table's info as part of an encrypted access token that is used on every access request if the access has to be sessionless.)
You have not mentioned a framework/language but most languages have a database layer. For example if the DB layer is hibernate-java. There are interceptors (https://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/Interceptor.html#onPrepareStatement(java.lang.String)) that can be used to modify the query thats being executed.
Every query to DB will go with additional where-clause for these relationship keys.
We can get clever with Spring AOP, REST interceptors and a lot of other techniques on top of this basic architecture to enforce this security.
Idea will be that DB layer does not return data thats not accessible to the logged in user principal irrespective of what queries higher layer code uses.
if this is in place, a REST GET call for
/payslip/user1/Jan-2017
will end up with a 404 and not a 403.
Expecting this to be solved by a framework or a superficial set of interceptors is both risky and not future proof. We end up continuously tweaking the interceptors as the url patterns evolve.
Addition to show table examples:
ACL table
user, uid, dept, org
--------------------
jhon, 1 , 1 , 1
mary, 2 , 2 , 1
will, 3 , 2 , 1
Payslip table
--------------
month, net, deductions,..., uid
-------------------------------------
Jan , 200, 15.5 ,..., 3
Feb , 200, 15.5 ,..., 3
Project table
-------------
pname, pstart, pbudget, dept
------------------------------------
mark1, 12/21 , 20000 , 2
markx, 12/31 , 40000 , 2
What you want is user roles and permissions + cross user control. To find out user roles and permissions refer this
Also additionally you may want to cross check their user ID to the resource ID. Since you cannot let user1's resource ID 1 to view by user2, you will need to add userID as part of the resource id ex:- /user/user_id_1.
Otherwise we don't have a logical way to separate which resources are applicable to which users.
I'm being writing web application right now and got stuck at the stage of designing the DAO layer. Already have surfed through variaty of articles on that subject but still haven't reached the clarity.
And my question is:
What kind of methods are allowed to be declared and implemented in DAO classes?
Are they just limited set of CRUD operations (create, read, update, delete)? Is it considered a good practice to extend this set with some custom methods fitting in your concrete needs in developing a business logic layer?
For example:
I have an entity class named User which fields fully reflect a corresponding database table. Let's suppose I'm about to validate user's login and password while authorization. What approach would be more appropriate in that situation? Should I call generic CRUD method List<User> findAll() to retrieve all users and validate these concrete login and password in method of business logic (something like boolean validateUser(String login, String password, List<User> users)). Or should I add some not CRUD method like boolean checkUser(String login, String password) directly in DAO class?
I'm being writing web application right now and got stuck at the stage of designing the DAO layer.
Are you writing it by hand using plain old servlets or using a web framework (e.g Spring MVC) to ease your pain?
And my question is: What kind of methods are allowed to be declared and implemented in DAO classes? Are they just limited set of CRUD operations (create, read, update, delete)?**
Generally speaking, yes -- the methods should be limited to CRUD operations.
Is it considered a good practice to extend this set with some custom methods fitting in your concrete needs in developing a business logic layer?**
Within reason, yes.
For example: I have an entity class named User which fields are fully reflect a corresponding database table. Let's suppose I'm about to validate user's login and password while authorization. What approach would be more appropriate in that situation? Should I call generic CRUD method List findAll() to retrieve all users and validate these concrete login and password in method of business logic (something like boolean validateUser(String login, String password, List users)). Or should I add some not CRUD method like boolean checkUser(String login, String password) directly in DAO class?
In addition to the standard CRUD methods that your DAO classes are expected to have, you can add a helper method like:
User findUser(String login) whose job is to return a populated User object for the specified login parameter, or null if the login is non-existent.
User findUser(String login) should leverage List<User> findAll() which should already exist with the rest of the CRUD methods in the DAO class. It could be implemented as follows:
public User findUser(String login) {
User user = null;
final SearchCriteria criteria = buildSearchCriteria(login); // construct a search criteria from the login parameter
List<User> users = findAll(criteria);
if (null != users) {
assert (users.size() == 1) : "More than one user was matched - login must be unique.";
user = users.get(0);
}
return user;
}
To summarize, you only need 2 methods to implement the authorization logic:
User findUser(String login) in your DAO layer and;
boolean checkUser(String login, String password) which will be in your frontend layer. If you are not using any web framework, this method will be implemented in your servlet otherwise this method will go inside your controller class (if you are using an MVC framework).
short answer is no: dont add any business logic in dao layer. Just let every tier has its own responsibility, so when someone else (or even you) needs changes they will know where to look.
EDIT:
Other answers:
Q:What kind of methods are allowed to be declared and implemented in DAO classes?
A:Methods that allow you to access database objects or their properties. i.e. public User getOldUsers(), public boolean isUserExist(Long userId)etc...
Q:Are they just limited set of CRUD operations (create, read, update, delete)?
A:Yes additionally you can control persistence or transaction properties
Q:Generic CRUDS?
A:Almost all the projects I work on we use generic CRUDS (AbstractDao classes) and add additional methods
I have a User class with many variables (name, email, password, etc) and sometimes I need to update only one or two of them (using a form). I get the data from the form and use bind of a json object:
Form<User> userForm = User.form.bind(json);
if(userForm.hasErrors()) {
return badRequest("error");
}
hasError() retrieves error because it doesn't receive some data. How can I tell to hasError() that it have not to validate some specific fields?
Take a look at the "Forms" sample app on GitHub. It shows how to assign a "group" to your constraints such that you can enforce a different set of constraints depending on the situation. The projects I'v worked on are still on Play 2.0.x which didn't have this, but I believe it is in Play 2.1 and/or 2.2.
https://github.com/playframework/playframework/tree/master/samples/java/forms
The files you want to look at are the User model and Wizard controller.
app/models/User.java
In your model you assign constraints to specific groups. The groups seem to just be interfaces defined within the model class.
#Required(groups = {All.class, Step1.class})
#MinLength(value = 4, groups = {All.class, Step1.class})
public String username;
app/controllers/Wizard.java
Now when you do your form binding you pass in the group/interface class that you want to validate.
Form<User> filledForm = form(User.class, User.Step1.class).bindFromRequest();