Ways to pass additional data to Custom RevisionEntity in Hibernate Envers? - java

It's RESTful web app. I am using Hibernate Envers to store historical data. Along with revision number and timestamp, I also need to store other details (for example: IP address and authenticated user). Envers provides multiple ways to have a custom revision entity which is awesome. I am facing problem in setting the custom data on the revision entity.
#RevisionEntity( MyCustomRevisionListener.class )
public class MyCustomRevisionEntity extends DefaultRevisionEntity {
private String userName;
private String ip;
//Accessors
}
public class MyCustomRevisionListener implements RevisionListener {
public void newRevision( Object revisionEntity ) {
MyCustomRevisionEntity customRevisionEntity = ( MyCustomRevisionEntity ) revisionEntity;
//Here I need userName and Ip address passed as arguments somehow, so that I can set them on the revision entity.
}
}
Since newRevision() method does not allow any additional arguments, I can not pass my custom data (like username and ip) to it. How can I do that?
Envers also provides another approach as:
An alternative method to using the org.hibernate.envers.RevisionListener is to instead call the getCurrentRevision( Class revisionEntityClass, boolean persist ) method of the org.hibernate.envers.AuditReader interface to obtain the current revision, and fill it with desired information.
So using the above approach, I'll have to do something like this:
Change my current dao method like:
public void persist(SomeEntity entity) {
...
entityManager.persist(entity);
...
}
to
public void persist(SomeEntity entity, String userName, String ip) {
...
//Do the intended work
entityManager.persist(entity);
//Do the additional work
AuditReader reader = AuditReaderFactory.get(entityManager)
MyCustomRevisionEntity revision = reader.getCurrentRevision(MyCustomRevisionEntity, false);
revision.setUserName(userName);
revision.setIp(ip);
}
I don't feel very comfortable with this approach as keeping audit data seems a cross cutting concern to me. And I obtain the userName and Ip and other data through HTTP request object. So all that data will need to flow down right from entry point of application (controller) to the lowest layer (dao layer).
Is there any other way in which I can achieve this? I am using Spring.
I am imagining something like Spring keeping information about the 'stack' to which a particular method invocation belongs. So that when newRevision() in invoked, I know which particular invocation at the entry point lead to this invocation. And also, I can somehow obtain the arguments passed to first method of the call stack.

One good way to do this would be to leverage a ThreadLocal variable.
As an example, Spring Security has a filter that initializes a thread local variable stored in SecurityContextHolder and then you can access this data from that specific thread simply by doing something like:
SecurityContext ctx = SecurityContextHolder.getSecurityContext();
Authorization authorization = ctx.getAuthorization();
So imagine an additional interceptor that your web framework calls that either adds additional information to the spring security context, perhaps in a custom user details object if using spring security or create your own holder & context object to hold the information the listener needs.
Then it becomes a simple:
public class MyRevisionEntityListener implements RevisionListener {
#Override
public void newRevision(Object revisionEntity) {
// If you use spring security, you could use SpringSecurityContextHolder.
final UserContext userContext = UserContextHolder.getUserContext();
MyRevisionEntity mre = MyRevisionEntity.class.cast( revisionEntity );
mre.setIpAddress( userContext.getIpAddress() );
mre.setUserName( userContext.getUserName() );
}
}
This feels like the cleanest approach to me.
It is worth noting that the other API getCurrentRevision(Session,boolean) was deprecated as of Hibernate 5.2 and is scheduled for removal in 6.0. While an alternative means may be introduced, the intended way to perform this type of logic is using a RevisionListener.

Related

Trying to understand SRP when we seggregate responsibilities into different classes

I'm trying to understand SRP principle and most of the sof threads didn't answer this particular query I'm having,
Use-case
I'm trying to send an email to the user's email address to verify himself whenever he tries to register/create an user-account in a website.
Without SRP
class UserRegistrationRequest {
String name;
String emailId;
}
class UserService {
Email email;
boolean registerUser(UserRegistrationRequest req) {
//store req data in database
sendVerificationEmail(req);
return true;
}
//Assume UserService class also has other CRUD operation methods()
void sendVerificationEmail(UserRegistrationRequest req) {
email.setToAddress(req.getEmailId());
email.setContent("Hey User, this is your OTP + Random.newRandom(100000));
email.send();
}
}
The above class 'UserService' violates SRP rule as we are clubbing 'UserService' CRUD operations and triggering verification email code into 1 single class.
Hence I do,
With SRP
class UserService {
EmailService emailService;
boolean registerUser(UserRegistrationRequest req) {
//store req data in database
sendVerificationEmail(req);
return true;
}
//Assume UserService class also has other CRUD operation methods()
void sendVerificationEmail(UserRegistrationRequest req) {
emailService.sendVerificationEmail(req);
}
}
class EmailService {
void sendVerificationEmail(UserRegistrationRequest req) {
email.setToAddress(req.getEmailId());
email.setContent("Hey User, this is your OTP + Random.newRandom(100000));
email.send();
}
But even 'with SRP', UserService as a class again holds a behaviour of sendVerificationEmail(), though this time it didn't hold the entire logic of sending the email.
Isn't it again we are clubbing crud operation's and sendVerificationEmail() into 1 single class even after applying SRP?
Your feeling is absolutely right. I agree with you.
I think your problem starts with your naming style, since you seem to be quite aware what SRP means. Class names like '...Service' or '...Manager' carry a very vague meaning or semantics. They describe a more generalized context or concept. In other words a '...Manager' class invites you to put everything inside and it still feels right, because it's a manager.
When you get more concrete by trying to focus on the true concepts of your classes or their responsibilities, you will automatically find bigger names with a stronger meaning or semantics. This will really help you to split up classes and to identify responsibilities.
SRP:
There should never be more than one reason to change a certain module.
You could start with renaming the UserService to UserDatabaseContext. Now this would automatically force you to only put database related operations into this class (e.g. CRUD operations).
You even can get more specific here. What are you doing with a database? You read from and write to it. Obviously two responsibilities, which means two classes: one for read operations and another responsible for write operations. This could be very general classes that can just read or write anything. Let's call them DatabaseReader and DatabaseWriter and since we are trying to decouple everything we are going to use interfaces everywhere. This way we get the two IDatabaseReader and IDatabaseWriter interfaces. This types are very low level since they know the database (Microsoft SQL or MySql), how to connect to it and the exact language to query it (using e.g. SQL or MySql):
// Knows how to connect to the database
interface IDatabaseWriter {
void create(Query query);
void insert(Query query);
...
}
// Knows how to connect to the database
interface IDatabaseReader {
QueryResult readTable(string tableName);
QueryResult read(Query query);
...
}
On top, you could implement a more specialized layer of read and write operations, e.g. user related data. We would introduce a IUserDatabaseReader and a IUserDatabaseWriter interface. This interfaces don't know how to connect to the database or what type of database is used. This interfaces only know what information is required to read or write user details (e.g. using a Query object that is transformed into a real query by the low level IDatabaseReader or IDatabaseWriter):
// Knows only about structure of the database (e.g. there is a table called 'user')
// Implementation will internally use IDatabaseWriter to access the database
interface IUserDatabaseWriter {
void createUser(User newUser);
void updateUser(User user);
void updateUserEmail(long userKey, Email emailInfo);
void updateUserCredentials(long userKey, Credential userCredentials);
...
}
// Knows only about structure of the database (e.g. there is a table called 'user')
// Implementation will internally use IDatabaseReader to access the database
interface IUserDatabaseReader {
User readUser(long userKey);
User readUser(string userName);
Email readUserEmail(string userName);
Credential readUserCredentials(long userKey);
...
}
We are still not done with the persistence layer. We can introduce another interface IUserProvider. The idea is to decouple the database access from the rest of our application. In other words we consolidate the user related data query operations into this class. So, IUserProvider will be the only type that has direct access to the data layer. It forms the interface to the application's persistence layer:
interface IUserProvider {
User getUser(string userName);
void saveUser(User user);
User createUser(string userName, Email email);
Email getUserEmail(string userName);
}
The implementation of IUserProvider. The only class in the whole application that has direct access to the data layer by referencing IUserDatabaseReader and IUserDatabaseWriter. It wraps reading and writing of data to make data handling more convenient. The responsibility of this type is to provide user data to the application:
class UserProvider {
IUserDatabaseReader userReader;
IUserDatabaseWriter userWriter;
// Constructor
public UserProvider (IUserDatabaseReader userReader,
IUserDatabaseWriter userWriter) {
this.userReader = userReader;
this.userWriter = userWriter;
}
public User getUser(string userName) {
return this.userReader.readUser(username);
}
public void saveUser(User user) {
return this.userWriter.updateUser(user);
}
public User createUser(string userName, Email email) {
User newUser = new User(userName, email);
this.userWriter.createUser(newUser);
return newUser;
}
public Email getUserEmail(string userName) {
return this.userReader.readUserEmail(userName);
}
}
Now that we tackled the database operations we can focus on the authentication process and continue to extract the authentication logic from the UserService by adding a new interface IAuthentication:
interface IAuthentication {
void logIn(User user)
void logOut(User);
void registerUser(UserRegistrationRequest registrationData);
}
The implementation of IAuthentication implements the special authentication procedure:
class EmailAuthentication implements IAuthentication {
EmailService emailService;
IUserProvider userProvider;
// Constructor
public EmailAuthentication (IUserProvider userProvider,
EmailService emailService) {
this.userProvider = userProvider;
this.emailService = emailService;
}
public void logIn(string userName) {
Email userEmail = this.userProvider.getUserEmail(userName);
this.emailService.sendVerificationEmail(userEmail);
}
public void logOut(User user) {
// logout
}
public void registerUser(UserRegistrationRequest registrationData) {
this.userProvider.createNewUser(registrationData.getUserName, registrationData.getEmail());
this.emailService.sendVerificationEmail(registrationData.getEmail());
}
}
To decouple the EmailService from the EmailAuthentication class, we can remove the dependency on UserRegistrationRequest by letting sendVerificationEmail() take an Email` parameter object instead:
class EmailService {
void sendVerificationEmail(Email userEmail) {
email.setToAddress(userEmail.getEmailId());
email.setContent("Hey User, this is your OTP + Random.newRandom(100000));
email.send();
}
Since the authentication is defined by an interface IAuthentication, you can create a new implementation at any time when you decide to use a different procedure (e.g. WindowsAuthentication), but without modifying existing code. This will also work with the IDatabaseReader and IDatabaseWriter once you decide to switch to a different database (e.g. Sqlite). The IUserDatabaseReader and IUserDatabaseWriter implementations will still work without any modification.
With this class design, you now have exactly one reason to modify each existing type:
EmailService when you need to change the implementation (e.g. use
different email API)
IUserDatabaseReader or IUserDatabaseWriter when you want to add additional user related read or write operations (e.g. to handle user role)
provide new implementations of IDatabaseReader or IDatabaseWriter when you want to switch underlying database or you need to modify database access
implementations of IAuthentication when the procedure changes (e.g. using build in OS authentication)
Now everything is cleanly separated. Authentication doesn't mix with CRUD operations. We have an additional layer between application and persistence layer to add flexibility regarding the underlying persistence system. So CRUD operations don't mix with the actual persistence operations.
As a tip: in future you better start with the thinking (design) part first: what must my application do?
handle authentication
handle users
handle a database
handle email
create user responses
show view pages to the user
etc.
As you can see, you can start to implement each step or requirement separately. But this doesn't mean each requirement is realized by exactly one class. As you remember, we split up database access into four responsibilities or classes: read and write to real database (low level), read and write to database abstraction layer, to reflect concrete use cases (high level). Using interfaces adds flexibility and testability to the application.
There is already a great answer to this question by #BionicCode. I just wan't to add a short summary and some of my thoughts on the matter.
The SRP can be a tricky one.
In my experience the granularity of the responsibilities and the number of abstactions that you place in your system will affect it's ease of use and it's size.
You can add a-lot of abstractions and break everything down to very small components. This indeed is something that we should strive for.
Now the question then is: When to stop?
This will depend on:
The size of your application
What parts of it will change more frequently than others
Do you need to compose objects together, or most of the time your modules are independent of one another and you don't reause many objects.
What time do you have
What is the size of your team
A lot of other stuff...
Let's start with how big is the team.
One reason we break our code into separate modules and classes into seprate files is so that we can work in a team and avoid too many merges in our favorite source control system. If you need to change a file that contains a component of your system and someone else needs to change it too, this may get ugly pretty fast. Now if you do separate modules using SRP you get more but smaller modules that most of the time will change independent of one another.
What if the team isn't that big and our modules are not that big too? Do you need to generate more of them?
Here's an example.
Let's say that you have a mobile application that has setings. We may say that containg these settigns in one responsibility and add it to one interface IApplicationSettings to hold all of them.
In the case where we have 30 settings this interface will be huge and that's bad. It also means that we are probably violating the SRP again as this interface will probably hold settings for multiple different categories.
So we decide to apply Interface seggregation principle and SRP and divide the settings to multiple interfaces ISomeCategorySettings, IAnotherCategorySettings etc.
Now let's say that our applications isn't too big (yet) and we have 5 settings. Even if they are from different categories, is it bad to keep these settings in one interface?
I would say that it's fine to have all settigns in one interface as long as it doesn't start to slow us down or start to get ugly (30 or more settigns!).
Is it that bad to construct an email and send it from your service object? This indeed is something that can get ugly pretty quickly, so you better move this responsibility from the service object to an EmailSender fast.
If you have a service object that contains 5 methods, do you realy need to break this into 5 different objects for every operation? If these methods are big, yes. If they small, keeping them in one object it's that big of a problem.
SRP is great, but take granularity into account and choose it wisely based on code size, team size etc.

How do I add a custom directive to a query resolved through a singleton

I have managed to add custom directives to the GraphQL schema but I am struggling to work out how to add a custom directive to a field definition. Any hints on the correct implementation would be very helpful.
I am using GraphQL SPQR 0.9.6 to generate my schema
ORIGINAL ANSWER: (now outdated, see the 2 updates below)
It's currently not possible to do this. GraphQL SPQR v0.9.9 will be the first to support custom directives.
Still, in 0.9.8 there's a possible work-around, depending on what you're trying to achieve. SPQR's own meta-data about a field or a type is kept inside custom directives. Knowing that, you can get a hold of the Java method/field underlying the GraphQL field definition. If what you want is e.g. an instrumentation that does something based on a directive, you could instead obtain any annotations on the underlying element, having the full power of Java at your disposal.
The way to get the method would something like:
Operation operation = Directives.getMappedOperation(env.getField()).get();
Resolver resolver = operation.getApplicableResolver(env.getArguments().keySet());
Member underlyingElement = resolver.getExecutable().getDelegate();
UPDATE:
I posted a huge answer on this GitHub issue. Pasting it here as well.
You can register an additional directive as such:
generator.withSchemaProcessors(
(schemaBuilder, buildContext) -> schemaBuilder.additionalDirective(...));
But (according to my current understanding), this only makes sense for query directives (something the client sends as a part of the query, like #skip or #deffered).
Directives like #dateFormat simply make no sense in SPQR: they're there to help you when parsing SDL and mapping it to your code. In SPQR, there's no SDL and you start from your code.
E.g. #dateFormat is used to tell you that you need to provide date formatting to a specific field when mapping it to Java. In SPQR you start from the Java part and the GraphQL field is generated from a Java method, so the method must already know what format it should return. Or it has an appropriate annotation already. In SPQR, Java is the source of truth. You use annotations to provide extra mapping info. Directives are basically annotation in SDL.
Still, field or type level directives (or annotations) are very useful in instrumentations. E.g. if you want to intercept field resolution and inspect the authentication directives.
In that case, I'd suggest you simply use annotations for the same purpose.
public class BookService {
#Auth(roles= {"Admin"}) //example custom annotation
public Book addBook(Book book) { /*insert a Book into the DB */ }
}
As each GraphQLFieldDefinition is backed by a Java methods (or a field), you can get the underlying objects in your interceptor or wherever:
GraphQLFieldDefinition field = ...;
Operation operation = Directives.getMappedOperation(field).get();
//Multiple methods can be hooked up to a single GraphQL operation. This gets the #Auth annotations from all of them
Set<Auth> allAuthAnnotations = operation.getResolvers().stream()
.map(res -> res.getExecutable().getDelegate()) //get the underlying method
.filter(method -> method.isAnnotationPresent(Auth.class))
.map(method -> method.getAnnotation(Auth.class))
.collect(Collectors.toSet());
Or, to inspect only the method that can handle the current request:
DataFetchingEnvironment env = ...; //get it from the instrumentation params
Auth auth = operation.getApplicableResolver(env.getArguments().keySet()).getExecutable().getDelegate().getAnnotation(Auth.class);
Then you can inspect your annotations as you wish, e.g.
Set<String> allNeededRoles = allAuthAnnotations.stream()
.flatMap(auth -> Arrays.stream(auth.roles))
.collect(Collectors.toSet());
if (!currentUser.getRoles().containsAll(allNeededRoles)) {
throw new AccessDeniedException(); //or whatever is appropriate
}
Of course, there's no real need to actually implement authentication this way, as you're probably using a framework like Spring or Guice (maybe even Jersey has the needed security features), that already has a way to intercept all methods and implement security. So you can just use that instead. Much simpler and safer. E.g. for Spring Security, just keep using it as normal:
public class BookService {
#PreAuth(...) //standard Spring Security
public Book addBook(Book book) { /*insert a Book into the DB */ }
}
Make sure you also read my answer on implementing security in GraphQL if that's what you're after.
You can use instrumentations to dynamically filter the results in the same way: add an annotation on a method, access it from the instrumentation, and process the result dynamically:
public class BookService {
#Filter("title ~ 'Monkey'") //example custom annotation
public List<Book> findBooks(...) { /*get books from the DB */ }
}
new SimpleInstrumentation() {
// You can also use beginFieldFetch and then onCompleted instead of instrumentDataFetcher
#Override
public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher, InstrumentationFieldFetchParameters parameters) {
GraphQLFieldDefinition field = parameters.getEnvironment().getFieldDefinition();
Optional<String> filterExpression = Directives.getMappedOperation(field)
.map(operation ->
operation.getApplicableResolver(parameters.getEnvironment().getArguments().keySet())
.getExecutable().getDelegate()
.getAnnotation(Filter.class).value()); //get the filtering expression from the annotation
return filterExpression.isPresent() ? env -> filterResultBasedOn Expression(dataFetcher.get(parameters.getEnvironment()), filterExpression) : dataFetcher;
}
}
For directives on types, again, just use Java annotations. You have access to the underlying types via:
Directives.getMappedType(graphQLType).getAnnotation(...);
This, again, probably only makes sense only in instrumentations. Saying that because normally the directives provide extra info to map SDL to a GraphQL type. In SPQR you map a Java type to a GraphQL type, so a directive makes no sense in that context in most cases.
Of course, if you still need actual GraphQL directives on a type, you can always provide a custom TypeMapper that puts them there.
For directives on a field, it is currently not possible in 0.9.8.
0.9.9 will have full custom directive support on any element, in case you still need them.
UPDATE 2: GraphQL SPQR 0.9.9 is out.
Custom directives are now supported. See issue #200 for details.
Any custom annotation meta-annotated with #GraphQLDirective will be mapped as a directive on the annotated element.
E.g. imagine a custom annotation #Auth(requiredRole = "Admin") used to denote access restrictions:
#GraphQLDirective //Should be mapped as a GraphQLDirective
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD}) //Applicable to methods
public #interface Auth {
String requiredRole();
}
If a resolver method is then annotated with #Auth:
#GraphQLMutation
#Auth(requiredRole = {"Admin"})
public Book addBook(Book newBook) { ... }
The resulting GraphQL field fill look like:
type Mutation {
addBook(newBook: BookInput): Book #auth(requiredRole : "Admin")
}
That is to say the #Auth annotation got mapped to a directive, due to the presence of #GraphQLDirective meta-annotation.
Client directives can be added via: GraphQLSchemaGenerator#withAdditionalDirectives(java.lang.reflect.Type...).
SPQR 0.9.9 also comes with ResolverInterceptors which can intercept the resolver method invocation and inspect the annotations/directives. They are much more convenient to use than Instrumentations, but are not as general (have a much more limited scope). See issue #180 for details, and the related tests for usage examples.
E.g. to make use of the #Auth annotation from above (not that #Auth does not need to be a directive for this to work):
public class AuthInterceptor implements ResolverInterceptor {
#Override
public Object aroundInvoke(InvocationContext context, Continuation continuation) throws Exception {
Auth auth = context.getResolver().getExecutable().getDelegate().getAnnotation(Auth.class);
User currentUser = context.getResolutionEnvironment().dataFetchingEnvironment.getContext();
if (auth != null && !currentUser.getRoles().containsAll(Arrays.asList(auth.rolesRequired()))) {
throw new IllegalAccessException("Access denied"); // or return null
}
return continuation.proceed(context);
}
}
If #Auth is a directive, you can also get it via the regular API, e.g.
List<GraphQLDirective> directives = dataFetchingEnvironment.getFieldDefinition().get.getDirectives();
DirectivesUtil.directivesByName(directives);

spring security permission programatic check

I have in place a spring security ACL system, and it seems to work fine, only that I `m not sure how should I perform a permission check programmatically.
My app is split into 3 layers (View,Service(Business),DAO) and I want to perform the auth in the Service layer. So, for a method that take as an argument a domain object :
#PreAuthorize("hasPermission(#proj,'write'")
public Project updateProject(Project proj) {
.............
}
the problem is solved with annotations.
But for a method that take as an argument an object that does not have an acl on it I have to programmatically check if user has permission.
Let`s say i have an object ProjectWrapper:
public class ProjectWrapper {
private Project project;
private Something something;
// setters and getters here
}
so now my Service method received this type of argument:
public Project updateProject(ProjectWapper projWrapp) {
Project p = projWrapp.getProject();
// before performing any operation on project I need to know if current user has neccessary permissions on this object
// ??? how do i check that ?
}
Do i need to use AclService to perform that ? just like when I need to create/update a permission, or is there an cleaner/nicer possibility ?
The same question for deleteProject(Long id) methods,as first i have to get the object from db to check if the current user has delete permission.
Method security annotations support Spring EL expressions. In case of your wrapper class, you can use it as follows.
#PreAuthorize("hasPermission(#projectWrapper.project, 'write'")
public Project updateProject(ProjectWrapper projectWrapper) {
// body omitted
}
And if you have just an object identifier instead of the actual object, you can use pattern below.
#PreAuthorize("hasPermission(#id, 'my.package.Project' 'delete'")
public void deleteProject(Long id) {
// body omitted
}
You may need to adjust default configuration (e.g. strategy to retrieve object identity and the like) to meet you requirements. See org.springframework.security.acls.AclPermissionEvaluator class for more details.

Using Stripes, what is the best pattern for Show/Update/etc Action Beans?

I have been wrestling with this problem for a while. I would like to use the same Stripes ActionBean for show and update actions. However, I have not been able to figure out how to do this in a clean way that allows reliable binding, validation, and verification of object ownership by the current user.
For example, lets say our action bean takes a postingId. The posting belongs to a user, which is logged in. We might have something like this:
#UrlBinding("/posting/{postingId}")
#RolesAllowed({ "USER" })
public class PostingActionBean extends BaseActionBean
Now, for the show action, we could define:
private int postingId; // assume the parameter in #UrlBinding above was renamed
private Posting posting;
And now use #After(stages = LifecycleStage.BindingAndValidation) to fetch the Posting. Our #After function can verify that the currently logged in user owns the posting. We must use #After, not #Before, because the postingId won't have been bound to the parameter before hand.
However, for an update function, you want to bind the Posting object to the Posting variable using #Before, not #After, so that the returned form entries get applied on top of the existing Posting object, instead of onto an empty stub.
A custom TypeConverter<T> would work well here, but because the session isn't available from the TypeConverter interface, its difficult to validate ownership of the object during binding.
The only solution I can see is to use two separate action beans, one for show, and one for update. If you do this however, the <stripes:form> tag and its downstream tags won't correctly populate the values of the form, because the beanclass or action tags must map back to the same ActionBean.
As far as I can see, the Stripes model only holds together when manipulating simple (none POJO) parameters. In any other case, you seem to run into a catch-22 of binding your object from your data store and overwriting it with updates sent from the client.
I've got to be missing something. What is the best practice from experienced Stripes users?
In my opinion, authorisation is orthogonal to object hydration. By this, I mean that you should separate the concerns of object hydration (in this case, using a postingId and turning it into a Posting) away from determining whether a user has authorisation to perform operations on that object (like show, update, delete, etc.,).
For object hydration, I use a TypeConverter<T>, and I hydrate the object without regard to the session user. Then inside my ActionBean I have a guard around the setter, thus...
public void setPosting(Posting posting) {
if (accessible(posting)) this.posting = posting;
}
where accessible(posting) looks something like this...
private boolean accessible(Posting posting) {
return authorisationChecker.isAuthorised(whoAmI(), posting);
}
Then your show() event method would look like this...
public Resolution show() {
if (posting == null) return NOT_FOUND;
return new ForwardResolution("/WEB-INF/jsp/posting.jsp");
}
Separately, when I use Stripes I often have multiple events (like "show", or "update") within the same Stripes ActionBean. For me it makes sense to group operations (verbs) around a related noun.
Using clean URLs, your ActionBean annotations would look like this...
#UrlBinding("/posting/{$event}/{posting}")
#RolesAllowed({ "USER" })
public class PostingActionBean extends BaseActionBean
...where {$event} is the name of your event method (i.e. "show" or "update"). Note that I am using {posting}, and not {postingId}.
For completeness, here is what your update() event method might look like...
public Resolution update() {
if (posting == null) throw new UnauthorisedAccessException();
postingService.saveOrUpdate(posting);
message("posting.save.confirmation");
return new RedirectResolution(PostingsAction.class);
}

Restrict access to the owner of an object in DDD

Let's say there is an object TaskList which can be edited and deleted only by its owner. Other users should only by able to take a task and update its status.
The following options come to my mind:
check the ownership and access in the controller of the web application
let the repository return proxy object which throws exception on certain operations, but the controller (or view) would still need to know which actions (in form of links or form fields) should be visible
pass the caller (user) to the method of the domain object, so that the domain object can itself check whether the caller ist allowed or not.
The used technology is Java.
Any other/better ideas?
Interesting articles about security and DDD
Domain Object Security with the Spring framework
Security in Domain-Driven Design
I have accepted my own answer now, because that is what I actually use, but further suggestions are welcome.
I would not encode the ownership/permissions model into the TaskList domain object. That sort of business logic should be external. I also don't like the idea of a proxy object. Although it would certainly work, it would confuse debugging and is, in this case at least, unnecessarily complex. I would also not check it in the controller.
Instead I would create a business logic object which oversees the permissions for TaskList. So the TaskList would have an owner field but you would have something like:
public class TaskListAccessor {
private TaskList taskList;
private User reader;
public void updateStatus(Status status) {
// everyone can do this
taskList.updateStatus(status);
}
/** Return true if delete operation is allowed else false */
public boolean isDeleteAllowed() {
return taskList.getOwner().equals(reader);
}
/** Delete the task. Only owners can do this. Returns true if worked else false */
public boolean delete() {
if (isDeleteAllowed()) {
taskList.delete();
return true;
} else {
return false;
}
}
// ... other accessors with other is*Allowed methods
}
If you need to require that all operations on TaskList objects go through accessors then you could create a factory class which is the only one who creates TaskList using package constructors or something. Maybe the factory is the only one who would use the DAO to look up the TaskList from the data store.
However, if there are too many methods to control in this fashion then a proxy might be easier. In both cases having TaskList be an interface would be recommended, with the implementation class hidden by the proxy or the accessor.
I found it unnecessarily complex to create accessor classes for each protected domain class as suggested by 'Gray'. My solution is probably not perfect, but simple to use and - more important - robust. You cannot forget to use a certain object or to check conditions outside.
public class TaskList {
private SystemUser owner;
private List<Task> tasks = new ArrayList<>();
public TastList(SystemUser owner) {
this.owner = owner;
}
public void Add(Task task) {
Guard.allowFor(owner);
tasks.add(task);
}
}
The Guard knows the current user (from a thread local for example) and compares it to the owner passed as parameter to allowFor(owner). If access is denied a security exception will be thrown.
That is simple, robust and even easy to maintain since only the guard has to be changed if the underlying authentication changes.

Categories

Resources