Inherit entities - spring

How to do when getting the user entity in Spring Boot, depending on the role that is the property of the user entity to get the entity that extend the user. For example, if user.role = "admin" gets an object of type Admin, which inherits User.

Use https://docs.oracle.com/javaee/5/api/javax/persistence/DiscriminatorValue.html for that.
In example:
#Entity
#DiscriminatorColumn(name="ROLE", discriminatorType=STRING, length=20)
#DiscriminatorValue("user")
public class User{ ... }
#Entity
#DiscriminatorValue("admin")
public class Admin extends User { ... }
If you use a EntityManager and assuming the User having the ID 1 is a admin, this might work:
Admin admin = (Admin) em.find(User.class, 1);

Related

Annotations needed to validate request data from set of values

Is there any annotation provided by spring to validate the input values from predefined set ?
Requirement validate roles assign to user, and Role value should be either user, admin, moderator.
Can I validate at the time when request comes in controller ?
You could use the Enum type to define the expected constants:
Role {
USER,
ADMIN,
MODERATOR
}
And then, your request would be:
public class User implements Serializable {
#NotNull(message = "role cannot be null")
private Role role;
}

How should I design endpoint to return different models depending on User role in Spring

So lets assume I have 2 model classes - User and Presentation, and they look something like this:
#Entity
public class Presentation {
#Id
private Long id;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
}
#Entity
public class User implements UserDetails {
#Id
private Long id;
private String username;
private String name;
private String surname;
private String password;
#Enumerated(EnumType.STRING)
private Role role;
}
As you can see I have a unidirectional mapping for user in Presentation class. My endpoint looks something like this:
#RestController
public class PresentationController {
#GetMapping("/{presentationId}")
public PresentationDTO getPresentation(#PathVariable Long presentationId) {
return presentationService.getPresentationById(presentationId);
}
#GetMapping
public List<PresentationDTO> getAllPresentations() {
return presentationService.getAllPresentations();
}
}
Now for my question - how do I change getAllPresentations() to return the presentations that the users with role "user" own, and return all presentations for users with role "admin"? I know I can create a separate endpoint with a different mapping (like /admin/presentations) and add #PreAuthorize(hasRole("admin")), but here is the tricky part.
For the getAllPresentations() endpoint which everyone who is authenticated is supposed to fetch his own presentations, how do I know for which user I have to return his presentations? Maybe I can get the username as a parameter but that might be dangerous cause he can submit any username he wants and get the presentations for that user. I don't know too much about Spring Security and I don't even know the right question to ask google to get an answer so I'm stuck...
Any help will be appreciated, thanks!
You don't have to pass username to your controller method. The currently authenticated user is available through a number of different mechanisms in Spring.The simplest way to retrieve the currently authenticated principal is via a static call to the SecurityContextHolder like this :
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
So you can refactor you method getAllPresentations() in service class to accept username as argument, and then you can load user by passed username and return presentations for that user.
One way to do what you want is to use #PostFilter annotation to filter List<Presentation> that the authenticated user owns or if the authenticated user has a role ADMIN like this:
#GetMapping
#PostFilter("filterObject.user.username == authentication.principal.username or hasRole('ADMIN')")
public List<PresentationDTO> getAllPresentations() {
return presentationService.getAllPresentations();
}

How to do a complicated #PreAuthorize check for an ID that is contained in child property?

According to this great post Spring-Boot #PreAuthorize allow operation only for admin or if the authenticated user id is same as path parameter id
it is shown that you can match the URL id against the user id using:
#PreAuthorize("hasRole('ROLE_ADMIN) or #authUser.id == #userId")
but what if I need to check if userId matches a child of authUser?
So suppose I have entity:
public class User {
int id;
#OneToMany(mappedBy = "owner")
Set<Store> stores;
}
and I want to validate based on #userId == #authUser.ANY_ONE_OF_THE_STORES.id?
You can create the component, for example
#Component
public class AuthComponent {
public boolean hasPermission(User user, Long id) {
// do whatever checks you want here
return someResult;
}
}
And then you can access the component method in SPEL like this
#PreAuthorize("#authComponent.hasPermission(#authUser, #userId)")
Since SPEL supports bean reference via # docs

join between two table in spring and hibernate Mysql

Table 1 name is users field name is userid ,roleid and username
Table 2 name is roles field name is roleid and rolename
I want to create relation between these two table.
I have follows more than 10 example. but i have not got any result.
Please help me and create the code according to me
Thanks
In order to create a relation between two entities/tables, you need to determine the type of relation you want to represent, whether that is a one-to-one, one-to-many, many-to-one, or many-to-many.
For your use case between a User and Role, this is typically a many-to-many because a User is associated to many roles and a role may be associated to many differing users.
User.java:
#Entity
public class User {
/* other things */
#ManyToMany
#JoinTable(name = "user_roles")
private List<Role> roles;
}
Role.java
#Entity
public class Role {
#ManyToMany(mappedBy="roles")
private List<User> users;
}
In this particular example, the relationship is owned by the User beacuse typically you would have roles created separately and then you associate a user to a set of roles.

Role and permission custom Model

I have a custom Model of Autorization that i want to represent with spring security :
I have the concpt of roles and permissions :
#Entity
public class User
...............
#ManyToMany
#Column
private Set<Role> roles;
#ManyToMany
#Column
private Set<Permission> permissions;
}
In my custom UserdetailsService i have a clean way to load the roles but i on't find any way and any componenent in spring-security related to the permissions :
public class BELUserDetailService implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User connectedUser = userRepositoy.findUserByUsername(username);
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
for (Role r :connectedUser.getRoles()) {
authorities.add(new SimpleGrantedAuthority(r.getRoleAWB().name()));
}
BELUserDetails belUserDetails = new BELUserDetails(connectedUser.getIdUser(), authorities);
.....
....
}
}
My roles are :
ADMIN
NORMAL USER
TRANSACTION USER
My Permissions are :
VALIDATE_TRANSATION
INIT_TRANSACTION
And the functional use case is if you want Validate a Transaction you have to have the ROLE TRANSACTION USER and the permission VALIDATE_TRANSACTION.
hasRole("ROLE_TRANSACTION_USER") and hasPermission("VALIDATE_TRANSACTION")
Another important case is that i want in the future use PermissionEvaluator to put some limits when trying to validate a transaction if the user has the Role "ROLE_TRANSACTION_USER" and the permission VALIDATE_TRANSACTION , he must also have a Amountlimit greater than the amount of the transaction and this functionality is very cool with PermissionEvaluator
That's why i need to implements both Role and permission Concepts
How i will add my permission to the standard flow of spring-security .
Thanks in advance .
By default you have only authorities in Spring Security. Just add all your roles and permissions into authorities collection. Then you can do:
hasRole("ROLE_TRANSACTION_USER") and hasRole("VALIDATE_TRANSACTION")
In most cases mixing the two is not a problem.
You have permissions in Spring Security ACL module, but you need ACL only if you want to have different security rules per domain object.
EDIT. I think the most easy way to do some additional security checks is to use SpEL. Example:
#PreAuthorize("hasRole('ROLE_TRANSACTION_USER')
and hasRole('VALIDATE_TRANSACTION')
and #amountValidatorServiceBean.isAmountValidForCurrentUser(#amount)")
public void doTransaction(Integer amount, ...)

Resources