Spring Security Integration
MoleculeDatabaseFramework has been integrated with Spring Security using annotations. This means as long as you do not enable security in you Application Context, everything will work just fine without any security. Security is applied to all methods in the Service interfaces.
The security integrations allows you to limit user to certain types of entities, eg. one user can only read
SimpleCompound while his supervisor also has access to
SecretCompound. You can also assign roles that allows a user to update and/or delete compounds he created himself. And of course roles that allow to update or delete any compound of a given implementation.
To make use of security you need to follow certain conventions. There are 6 basic "role-types": create, read, update, delete, update_created and delete_created. A complete role is a "role-type" followed by and underscore and the entity class implementations SimpleClassName. So if you have an entity
RegistrationCompound and you want a user to be able to read
RegistrationCompounds he needs the role
read_RegistrationCompound. And so forth.
- A role starts with a "role-type" followed by "_" and the simple class name:
- A user can either read none or all entries for a given entity implementation.
- A service interface method that requires read-role must be annotated with
Above applies to
ChemicalStructure there is always only the supplied entity
ChemicalStructure which a user of the framework should not extend.
ChemicalStructure only has a save-Role and any user that can create or update any type of
ChemicalCompound must have this role
- For managing Users and Roles you need to use the supplied entities
Roleand their services.
MoleculeDatabaseFramework ships with a
PermissionEvaluator implementation. This
PermissionEvaluator checks if a given user can create, update or delete a given domain object. (Note: For read-methods just having the read-role is enough; they use
hasRole instead of
PermissionEvaluator allows users with create, update or delete role to perform that action on any domain object (of the given implementation). Users with update_created or delete_created role can perform that action only on domain objects they created (
Services only offer a
save method. If a domain object is being created or being updated is determined whether its id is set or not (id == null -> create). This is exactly the same what hibernate does.
In your application you should only create exactly 1 implementation of
ChemicalCompoundContainer. However this
Container can hold any type of
Containable and hence any type of
ChemicalCompound. To ensure that a user only sees
Containers that contain a
ChemicalCompound he has the read-role for, all other containers are filtered out. This includes the
count() service method. So users with different privileges on
ChemicalCompounds see different numbers of
PermissionEvaluator requires a
RoleHierarchy bean to be configured in the security context.
RoleHierarchy is very useful as it automatically assigns a "lower" privilege to someone with a "higher" one. So you say
create_RegistrationCompound > read_RegistrationCompound
then anyone with
create_RegistrationCompound role automatically also has role
Cascading of Persist
ChemicalCompoundContainer in their JPA relationships between each other all use
CascadeType.REFRESH. This means changes (updates) to existing entities must always be done using that entities service.save(entity) method because
CascadeType.MERGE (update) is not set and hence updates are not cascaded.
In case of creating a new entity, the
Permission implementations check if the current user has the privilege to also create the associated, new entities. If you create a new
ChemicalCompoundContainer that contains a new
Containable which is made of a new
ContainerPermission will verify if the current user has the privilege to not only create the new
ChemicalCompoundContainer but also to create the new
ChemicalCompound and new
Containable. If this is not the case, an
AccessDeniedException is thrown.
Below example will create a new
RegistrationCompound, a new
Batch and a new
CompoundContainer if the current user has the privileges
RegistrationCompound regCompound = new RegistrationCompound(); regCompound.setCompoundName("Registration Compound"); regCompound.setCas(cas); regCompound.setRegNumber(regNumber); ChemicalStructure structure = chemicalStructureFactory.createChemicalStructure(structureData); ChemicalCompoundComposition composition = new ChemicalCompoundComposition(); composition.setCompound(regCompound); composition.setChemicalStructure(structure); composition.setPercentage(100.0); regCompound.getCompositions().add(composition); Batch batch = new Batch(regCompound, batchNumber); regCompound.getBatches().add(batch); CompoundContainer container = new CompoundContainer("C00001", batch); container = compoundContainerService.save(container);
In case an associated entity already exists, create-privilege is not required, if the entity that is being persisted is the "parent" in the hierarchy. Or said otherwise you can associate a new
ChemicalCompoundContainer with an existing
Containable but you can not associate a new Containable with an existing
ChemicalCompoundContainer because that container could not exist before the containable was created. Same logic for relationship between
To do so, you need to implement your own
PermissionEvaluator and / or