Wiki

Clone wiki

jummp / Access Control List and Model Sharing

Access Control List

Jummp uses the Spring Security ACL plugin for access control lists. In Jummp access to Models and Revisions is protected by an ACL, so that only authorized users are able to interact with the Models.

It is not possible to secure every function call. Most important all calls going directly to the database cannot be protected. This means GORM's static methods, dynamic finders, HQL and criteria circumvent the ACL.

def models = Model.list() // returns all models without checking against ACL
der Model model = Model.get(1) // returns the first Model without checking against ACL
model = Model.findByName("Model") // returns the Model with name "model" without checking against ACL
def criteria = Model.createCriteria()
// returns all Models, which have a Revision with id 1 without checking against ACL
models = criteria.list() {
    revisions {
        eq('id', 1)
    }
}

Using these methods is not allowed and code outside the core using these calls will not be accepted during code review! Instead of going to the database directly use the service layer which provides secure access:

class MyService {
    def modelService // dependency injection of model service

    def myServiceMethod() {
        // retrieve all models the user has access to
        // be aware: this method is paginated, it only returns the first ten models!
        List<Model> model = modelService.getAllModels()
    }
}

Most of the API calls are protected using annotations and the Spring expression language. Most important is here the hasPermission() expression. This can be used to check if the current logged in user has a given permission on a parameter:

@PreAuthorize("hasPermission(#model, write)")
public Revision addRevision(Model model, File file, String comment) {
    // secure implementation
}

If a user has not the required permission an AccessDeniedException is thrown. It is important to know that the protection using annotations does not work if a direct function call is used. The protection is only available if the call is routed through the Spring context.

@PostFilter("hasPermission(filterObject, read) or hasRole('ROLE_ADMIN')")
public List<Revision> getAllRevisions(Model model) {
    return model.revisions.toList().sort {it.revisionNumber}
}

@PreAuthorize("hasPermission(#model, admin) or hasRole('ROLE_ADMIN')")
public void grantReadAccess(Model model, User collaborator) {
    // direct access does not work, this would return the same as model.revisions!
    List<Revision> revisions = getAllRevisions(model)
}

To prevent unexpected results, it is important to use Integration Tests for all security relevant functionality!

Jummp's ACL

Model

  • BasePermission.READ: indicates that the owner of the permission will gain BasePermission.READ on any new Revision. It does not influence the visibility of the Model. A Model is only visible to a user, if there is at least one Revision the user has the BasePermission.READ on.
  • BasePermission.WRITE: indicates that the owner of the permission is allowed to add new Revisions to the Model.
  • BasePermission.DELETE: indicates that the owner of the permission is allowed to delete the Model
  • BasePermission.ADMINISTRATION: indicates that the owner of the permission is the owner of the model. He is allowed to grant/revoke read/write access to other users.

Revision

  • BasePermission.READ: indicates that the owner of the permission is allowed to read the Revision and by that also the Model.
  • BasePermission.DELETE: indicates that the owner of the permission is allowed to delete the revision.
  • BasePermission.ADMINISTRATION: indicates that the owner of the permission is the owner of the Revision. This does not have any further implications.

Model Sharing

Model sharing is enabled by the modelService pairs of ACL based functions: grantReadAccess, grantWriteAccess and revokeReadAcces, revokeWriteAccess. Each of these takes as arguments a model and the username of the user to whom the rights are to be granted. Only a user with model administration rights can modify the sharing permissions of a model (checked using the canShare function, provided by modelService). This generally is the user who originally submitted the model, or a user with administrator rights.

The sharing page itself is sufficiently complex on the client side to merit an MVC based implementation, using BackboneJS. The model in this case is the user (username and real name), and what access rights have been granted to them. A collection of such objects is maintained, with a list associated with it. New users are added through a search box, which has an autocomplete mechanism that queries for users by their names (functionality implemented in the JummpController). Sanity checks are made on users added to the sharing list by querying on the server with the name provided (again through the JummpController). The client communicates with the server through AJAX and JSON.

Updated