context dependent validation for BeanValidation - java

I am a big fan of JSR 303 BV but in my current project i am having a lot of "context dependent validation" and i do not find any reasonable approach to implement them with BV.
Basically validation rules can depend on
logged in user (it is stored in http request)
a user we act upon - the id of the user is path param of REST URL like /foo/bar/user/1/sth
both of these
A little example :
class Alphabet{
#Valid
private Alpha a;
#Valid
private Beta b;
#Valid
private Gamma g;
}
And validation rule:
If the user whose id will provided in URL has role "admin" that none of "a","b","g" properties can be null. If it has role "user" only "a" must be not null and other props must be null.
So basically these kind of rules can be easily implemented as class level-constraint of Alphabet class but custom validator would need somehow access id of the user which is provided in URL. Is there any smart way this could be achieved or i have to force all REST clients to pass user id multiple times: in URL and in payload so the latter will be only used by BV.
The more complex case is when validation rule depends on logged in user, so custom validators will have to somehow access authenticated principal - from ThreadLocal or HttpServletRequest.

You could make use of validation groups:
//Define validation groups
interface AdminChecks {}
interface UserChecks {}
//Assign the constraints to the two groups
class Alphabet{
#NotNull(groups={AdminChecks.class, UserChecks.class})
private Alpha a;
#NotNull(groups=AdminChecks.class)
#Null(groups=UserChecksChecks.class)
private Beta b;
#NotNull(groups=AdminChecks.class)
#Null(groups=UserChecksChecks.class)
private Gamma g;
}
Depending on the role of the current user, you then specify either AdminChecks or UserChecks when invoking the validator, e.g. like this for the admin checks:
Validator validator = ...;
Set<ConstraintViolation<Alphabet>> violations = validator.validate(
new Alphabet(),
AdminChecks.class
);

Related

Call custom method for authorization for each endpoint or resource in Quarkus

I have an application with 2 entities : A and B.
Each of these entities contain a "Workspace" :
#Entity
class A {
private Workspace workspace;
}
#Entity
class B {
private Workspace workspace;
}
For each request that comes in like a GET <api>/resourceA or a POST <api>/resourceB/{id}/createSomething, we need to check that the caller (that is logged in through Keycloak and has a JWT) has access to the Workspace that A is part of (or B, in the latter case). It's all "dynamic" as it's based on the ID of the specific object A.
So, for each endpoint (or each Resource, might be all that's needed), we need to call a method that is specific to that endpoint/Resource. We cannot do this with just "Roles", because we need to have that specific check on the IDs, like :
A.getWorkspace().isAccessibleBy(theCallingUser)
I know Spring Security has specific methods like "hasRole()" and you can call specific code in the #PreAuthorize annotations, but I haven't seen the same in Quarkus.

Spring Security w/ Nested Accounts

I'm having difficulties with authorizing nested accounts in Spring Security. I'm new to Spring Security. I spent around a week to reach a working solution, but it's an ugly one and I'd love to refactor it...
I'm using Spring 4.2.4 and Spring Security 4.0.3.
I have user accounts that look like this:
Office User A
Office User B
Field User C
--> Field Sub-User a
--> Field Sub-User b
Field User D
--> Field Sub-User c
So, an office user has only one account, but a field user has at least one sub-account always, with the potential for two or more sub-accounts. Each sub-account can have different authorities. Like one sub-account can view only, and another sub-account can view plus create.
The user will sign-in with an account (A, B, C, or D). If A or B signs in, there is no issue. However, if user C signs in, they need to pick (a or b) and we need information for their choice. If user D signs in, we need information for user (c). I'm using Spring Security and struggling with getting the information for User a/b/c above. I came to a solution, but it's not ideal, and I'd like to know a more proper way.
My solution:
In the #AuthenticationPrincipal implementation of UserDetails, add below code:
private Collection<GrantedAuthority> authorities;
private String uniqueId1;
private String uniqueId2;
public void setAuthorities(Collection<GrantedAuthority> authorities) {
this.authorities = authorities;
}
public Collection<GrantedAuthority> getAuthorities() {
if (this.authorities != null) {
return this.authorities; //CHILD
}
return super.getAuthorities(); // (SUPER)
}
public void setUniqueId1(String uniqueId1) {
this.uniqueId1 = uniqueId1;
}
public String getUniqueId1() {
if (this.uniqueId1!= null) {
return this.uniqueId1; //CHILD
}
return super.getUniqueId1(); // (SUPER)
}
public void setUniqueId2(String uniqueId2) {
this.uniqueId2 = uniqueId2;
}
public String getUniqueId2() {
if (this.uniqueId2!= null) {
return this.uniqueId2; //CHILD
}
return super.getUniqueId2(); // (SUPER)
}
Then, in my method to get logged-in user information, accept a string of the selected user and do like such:
public #ResponseBody FullUserDetails getLoggedInUserInfo(
#AuthenticationPrincipal MyImplementationOfUserDetails user,
String selectedUsername)
MyImplementationOfUserDetails user2 = getUserInfo(selectedUsername);
user.setAuthorities(user2.getAuthorities());
user.setUniqueId1(user2.getUniqueId1());
user.setUniqueId2(user2.getUniqueId2());
In this way, I am able to 'change' the authorities and unique id properties which would otherwise be unchangeable because they are private in the parent classes and normally only accessible through a constructor. I tried making a new constructor in the UserDetails implementation, but when I create a new #AuthenticationPrincipal, it doesn't override the one in the session. I think a new constructor would be the most proper way to go. How do I override the #AuthenticationPrincipal in the session with a new UserDetails object? Or is there a better approach entirely, which I'm not thinking of? I just want the new authorities and unique ID information for the sub-user that was selected to be put into the #AuthenticationPrincipal. The next time I get the #AuthenticationPrincipal, it will then have that information.
The consequences of not getting the new information and putting it in the #AuthenticationPrincipal is that the webpage behavior will be wrong. Mostly because the authority levels will not be correct for the user that was selected.
I was trying to call:
SecurityContextHolder.getContext().setAuthentication(newAuthenticationObjectHere);
But I wasn't seeing the changes after calling setAuthentication()...
The only way I was able to see the changes was by directly calling setters in the MyImplementationOfUserDetails object retrieved from the #AuthenticationPrinciple.
Sorry, very confused, but the main idea is almost understandable.
I think you go in cycles with an idea to calculate all complex relations between accounts and after that to give the final account required permission and provide access to some resource.
What if to change the logic of providing access to resources without manipulating the account relations? And the very important chain - to use remote/distributed Authorization server like Spring OAuth2 one? With it, you can have authorities for any account AND scopes (!). Depending on organization conditions an account can have different scopes. And your final resources (usually they are controllers methods) have pre-authentication by scope. According to this idea, you can separate the logic of providing access based on specific of accounts, implementing all logic in DB with accounts.
Maybe it's the wrong idea for your project, for me it works - I change scopes for customers depending their conditions, but not manipulate with their data and relations in runtime.

How to get Query/Mutation operation name

I'm new to Spring boot + GraphQL.
I need to get the Query/Mutation operation name inside my controller class.
Purpose : Need to grand permission to some users to specific mutation/Query operations.
Here the user type will be passed as a request header and will be validated and check whether the user is allowed to access that operation.
#PostMapping
public ResponseEntity<Object> callGraphQLService(#RequestBody String query, #RequestHeader("user") String userName) {
ExecutionResult result = graphService.getGraphQL().execute(ExecutionInput.newExecutionInput()
.query(query)
.context(userName)
.build());
return new ResponseEntity<>(result, HttpStatus.OK);
}
Suggest any efficient mechanism to perform authorization for specific Query/Mutation
I think you're thinking of authorization in REST terms here, and it doesn't map well to GraphQL. Instead of a single decision at the top level based on the operation name (or based on the URL in REST), you need a more granular approach. You need to know who's allowed to see/do what at the field level, as the client is allowed make ad-hoc selections.
There's multiple ways to do this, but since you mentioned Spring, you can simply use Spring Security at the service level. If each protected field is backed by a service method (and it should be), you can protect those methods using Spring Security as usual.
Even better, you should also provide a custom GraphqlFieldVisibility implementation, so that unauthorized clients can't even know about the the existence of fields they're not allowed to see in the schema. You can use e.g. Spring's SpelExpressionParser to make decisions on what parts of the schema are visible dynamically, for each user, based on Spring Security rules.
If Spring Security is not an option, you can implement a custom Instrumentation (e.g. by extending SimpleInstrumentation). There you can implement the callbacks like beginExecuteOperation, that will give you access to the parsed query (enough if you really just want to do REST-style top-level auth only), or begin(Deferred)Field (which gives you access to the FieldDefinition) or beginFieldFetch/instrumentDataFetcher (which gives you access to the entire DataFetchingEnvironment) to perform auth per-field.
If you go this way, you can keep the auth information (e.g. the required roles) in the field definition itself as directives. And keep the currently logged in user in the shared context. This way you always have everything you need to do authentication at each level.
In all cases, it's advisable to provide GraphqlFieldVisibility to completely hide the existence of the protected fields contextually.
Here's an abstract example showing the major points using the Instrumentation approach (as you need nothing special for the Spring Security approach, just use Spring Security as usual):
//Checks if the current user has the needed roles for each field
public class AuthInstrumentation extends SimpleInstrumentation {
#Override
public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher, InstrumentationFieldFetchParameters parameters) {
GraphQLFieldDefinition fieldDefinition = parameters.getEnvironment().getFieldDefinition();
//Each protected field is expected to have a directive called "auth" with an argument called "rolesRequired" that is a list of strings representing the roles
Optional<GraphQLArgument> rolesRequired = DirectivesUtil.directiveWithArg(fieldDefinition.getDirectives(), "auth", "rolesRequired");
if (rolesRequired.isPresent()) {
List<String> roles = (List<String>) rolesRequired.get().getValue();
User currentUser = parameters.getEnvironment().getContext(); //get the user from context
if (!currentUser.getRoles().containsAll(roles)) {
//Replace the normal resolution logic with the one that always returns null (or throws an exception) when the user doesn't have access
return env -> null;
}
}
return super.instrumentDataFetcher(dataFetcher, parameters);
}
}
You don't have to store the required roles in the directives, it's just a convenient place. You can get the same info from an external source if it's appropriate.
Then register this instrumentation:
GraphQL graphQL = GraphQL.newGraphQL(schema)
.instrumentation(new AuthInstrumentation())
.build();
And when executing a query, put the current user into the context:
//Get the current user's roles however you normally do
User user = loadUser(userName);
ExecutionInput input = ExecutionInput.newExecutionInput()
.query(operation)
.context(user) //put the user into context so the instrumentation can get it
.build()
This way you have everything neatly separated (no auth logic in resolvers, no external context needed) and contextual per field, even without using Spring Security.
Let's go further and make a custom GraphqlFieldVisibility:
public class RoleBasedVisibility implements GraphqlFieldVisibility {
private final User currentUser;
public RoleBasedVisibility(User currentUser) {
this.currentUser = currentUser;
}
#Override
public List<GraphQLFieldDefinition> getFieldDefinitions(GraphQLFieldsContainer fieldsContainer) {
return fieldsContainer.getFieldDefinitions().stream()
.filter(field -> isFieldAllowed(field, currentUser))
.collect(Collectors.toList());
}
#Override
public GraphQLFieldDefinition getFieldDefinition(GraphQLFieldsContainer fieldsContainer, String fieldName) {
GraphQLFieldDefinition fieldDefinition = fieldsContainer.getFieldDefinition(fieldName);
return fieldDefinition == null || !isFieldAllowed(fieldDefinition, currentUser) ? null : fieldDefinition;
}
private boolean isFieldAllowed(GraphQLDirectiveContainer field, User user) {
//Same as above, extract this into a common function
Optional<GraphQLArgument> rolesRequired = DirectivesUtil.directiveWithArg(field.getDirectives(), "auth", "rolesRequired");
List<String> roles = (List<String>) rolesRequired.get().getValue();
return currentUser.getRoles().containsAll(roles);
}
}
As you see, visibility depends on the user, which this time you can not get from the context, so you have to instantiate it per request. This means you need to transform the schema and instantiate GraphQL per request as well. The rest is the same.
GraphQLSchema schema = baseSchema.transform(sch ->
sch.codeRegistry(baseSchema.getCodeRegistry().transform(code ->
code.fieldVisibility(new RoleBasedVisibility(currentUser)))));
GraphQL graphQL = GraphQL.newGraphQL(schema)
.instrumentation(new AuthInstrumentation())
.build();
With that, you have a full security setup. Unauthorized users won't even know a field exists if they're not allowed to. If they're allowed to see it in general, but they can only fetch it conditionally, the AuthInstrumentation covers it.

Design patterns - How to enforce object attributes only in some situations (Builder pattern, Dependency Injection)

I am in a very particular situation with one of the classes I'm coding. I have this class called User that looks like this:
public class User {
private long id; // + getters and setters
private boolean isDeletable; // + getters and setters
private String name; // + getters and setters
private String password; // + getters and setters
private String email; // + getters and setters
private String authenticationRealm; // + getters and setters
private String displayName; // + getters and setters
private Date deletedDate; // + getters and setters
}
Within my code there are several situations where I just need an empty object of the type User and therefore just build it using the default constructor: new User().
However, I have another class called CreateUserRequest which models a REST request to create the user in a server. The minimum payload must contain the name, password, email, and authenticationRealm attributes sent in JSON format.
Right now I am handling this by checking for these parameters in the constructor of the request:
public CreateUserRequest(User user) {
if(user.getName() == null || user.getPassword() == null || user.getEmail() == null || user.getAuthenticationRealm() == null)
throw new RuntimeException("Not enough attributes in User object. Minimum: name, password, e-mail and authentication realm.");
}
This is working OK but something is itchy... I would like to enforce this in a safer way, so that the code would enforce the attributes to be populated with no possibility of an exception being thrown.
I feel like there must be a better way to do this with a design pattern. I thought of creating a UserRequestBuilder class, but that would also possibly imply throwing an exception in the build() method (otherwise, is there a way I can guarantee that the attributes are populated before build()?). Dependency injection also sounds like a possibility, but I'm not sure how I would put it in place in this particular example...
Any thoughts?
How about making your REST services operate on a UserDTO? (Off course, the UserDTO could be replaced with a subclass of User).
You could annotate the fields, setters or constructor parameters on the UserDTO with #NonNull and have the Checker Framework issue compiler warnings when passing null values instead of name password, email etc to the UserDTO.
Using a framework like Mapstruct, mapping between the REST services DTOs and the backend objects is very easy:
#Mapper
public interface UserMapper {
public static final UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDTO map(User user);
User map(UserDTO userDTO);
}
Above code will upon compilation generate a UserMapper implementation, with autogenerated code for the specified methods ( - and the autogenerated code simply pairs similarly named getters and setters. You could do this yourself, but with many DTOs/Entities is becomes time consuming and boring).
In the DTOs you could exclude all those fields you do not want to expose.
Ps. My own usage of above mentioned is this: I am creating a REST server based on Jersey, i.e. the reference implementation of JAX-RS. This project, call it A, only knows about the DTOs. The REST methods calls into another project B, which retrieves the objects from database, and maps them to the corresponding DTO, which is then returned to project A. Part of the reason for this pattern is that the entities of project B for historical reasons are cluttered with methods/functionality, which should not be exposed to project A. As for the sanity checks (JSON to DTO), jersey supports Bean Validation, which is to say, that the framework will validate each rest resource's input beans if they are annotated with #Valid.
It is also possible to create your own custom annotations, which have a ConstraintValidator defined. The bean validation framework will check these constraints on the annotated jersey REST method parameters.
See https://jersey.java.net/documentation/latest/bean-validation.html#d0e13690
I came up across a similar problem , I came up with the solution of adding a Custombuilder with constructor having arguments. So it ensures that i am ensuring that client(user) has to provide those credentials for building that object
class UserRequestBuilder{
public UserRequestBuilder(String name,String password,String email,String authenticationRealm){
// set values here
}
}

How to avoid anemic data model? Can repositories be injected into entities?

I have an immutable User entity:
public class User {
final LocalDate lastPasswordChangeDate;
// final id, name, email, etc.
}
I need to add a method that will return information if the user's password must be changed i.d. it has not been changed for more than the passwordValidIntervalInDays system setting.
The current approach:
public class UserPasswordService {
private SettingsRepository settingsRepository;
#Inject
public UserPasswordService(SettingsRepository settingsRepository) {
this.settingsRepository = settingsRepository;
}
public boolean passwordMustBeChanged(User user) {
return user.lastPasswordChangeDate.plusDays(
settingsRepository.get().passwordValidIntervalInDays
).isBefore(LocalDate.now());
}
}
The question is how to make the above code more object oriented and avoid the anemic domain model antipattern? Should the passwordMustBeChanged method be moved to User if so how to access SettingsRepository, should it be injected into User's constructor, or should a Settings instance be provided to the ctor, or should the passwordMustBeChanged method require a Settings instance to be provided?
The code of Settings and SettingsRepository is not important, but for completness, here it is:
public class Settings {
int passwordValidIntervalInDays;
public Settings(int passwordValidIntervalInDays) {
this.passwordValidIntervalInDays = passwordValidIntervalInDays;
}
}
public class SettingsRepository {
public Settings get() {
// load the settings from the persistent storage
return new Settings(10);
}
}
For a system-wide password expiration policy your approach is not that bad, as long as your UserPasswordService is a domain service, not an application service. Embedding the password expiration policy within User would be a violation of the SRP IMHO, which is not much better.
You could also consider something like (where the factory was initialized with the correct settings):
PasswordExpirationPolicy policy = passwordExpirationPolicyFactory().createDefault();
boolean mustChangePassword = user.passwordMustBeChanged(policy);
//class User
public boolean passwordMustBeChanged(PasswordExpirationPolicy policy) {
return policy.hasExpired(currentDate, this.lastPasswordChangeDate);
}
If eventually the policy can be specified for individual users then you can simply store policy objects on User.
You could also make use of the ISP with you current design and implement a PasswordExpirationPolicy interface on your UserPasswordService service. That will give you the flexibility of refactoring into real policy objects later on without having to change how the User interacts with the policy.
If you had a Password value object you may also make things slightly more cohesive, by having something like (the password creation date would be embedded in the password VO):
//class User
public boolean passwordMustBeChanged(PasswordExpirationPolicy policy) {
return this.password.hasExpired(policy);
}
just to throw out another possible solution would be to implement a long-running process that could do the expiration check and send a command to a PasswordExpiredHandler that could mark the user with having an expired password.
I have stumbled upon a document that provides an answer to my question:
A common problem in applying DDD is when an entity requires access to data in a repository or other gateway in order to carry out a business operation. One solution is to inject repository dependencies directly into the entity, however this is often frowned upon. One reason for this is because it requires the plain-old-(C#, Java, etc…) objects implementing entities to be part of an application dependency graph. Another reason is that is makes reasoning about the behavior of entities more difficult since the Single-Responsibility Principle is violated. A better solution is to have an application service retrieve the information required by an entity, effectively setting up the execution environment, and provide it to the entity.
http://gorodinski.com/blog/2012/04/14/services-in-domain-driven-design-ddd/

Categories