Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagejava
public class EnrollmentService {

    @Secure("principal.id == callerUserId or hasRole('ADMIN') or " + 
      "(hasRole('RESEARCHER') and hasOrgSponsoredStudy(studyId))")
    public PagedResourceList<EnrollmentDetail> getEnrollmentsForStudygetEnrollments(...) {
    }
    
    @Secure("principal.id == callerUserId or hasRole('ADMIN') or " + 
      "(hasRole('RESEARCHER') and hasOrgSponsoredStudy(studyId))")
    public List<EnrollmentDetail> getEnrollmentsForUser(...) {
    }
    
    @Secure("principal.id == callerUserId or hasRole('ADMIN') or " + 
      "(hasRole('RESEARCHER') and hasOrgSponsoredStudy(studyId))")
    public Enrollment enroll(...) {
    }
    
    @Secure("principal.id == callerUserId or hasRole('ADMIN') or " + 
      "(hasRole('RESEARCHER') and hasOrgSponsoredStudy(studyId))")
    public void updateEnrollment(...) {
    }
    
    @Secure("principal.id == callerUserId or hasRole('ADMIN') or " + 
      "(hasRole('RESEARCHER') and hasOrgSponsoredStudy(studyId))")
    public Enrollment unenroll(...) {
    }
}

...

Nothing Spring does is that hard to duplicate with a DSL that uses our existing RequestContext. I think it makes sense to call these in the services, where multiple endpoints might create multiple conditions under which a call is acceptable. It could look something like this:

Code Block
languagejava
public class EnrollmentService {
    private static final AuthEvaluator IS_ORGSELF_ADMIN_OR_STUDY_RESEARCHER = 
        AuthUtils.orgMembercanAccessStudy().inRole(ORG_ADMIN);RESEARCHER).or()
            .inAnyRole(ADMIN, SUPERADMIN).or()
            // If we pass arguments in when we check, these are threadsafe and composable
private static final AuthEvaluator IS_ORGisSelf();

    public PagedResourceList<EnrollmentDetail> getEnrollments(...) {
        IS_SELF_ADMIN_OR_ADMIN = IS_ORG_ADMIN.or().inAnyRole(ADMIN, SUPERADMINSTUDY_RESEARCHER.checkAndThrow("studyId", studyId);
    }
    
    public voidEnrollment mustBeAnOrgAdmin(String appId, String orgId) {enroll(...) {
        IS_ORGSELF_ADMIN_OR_STUDY_RESEARCHER.checkAndThrow("orgIdstudyId", orgIdstudyId);
    }
    
   // do something
} public void updateEnrollment(...) {
        IS_SELF_ADMIN_OR_STUDY_RESEARCHER.checkAndThrow("studyId", studyId);
    }
    
    public voidEnrollment mustBeSomeKindOfAdmin(String appId, String orgId) {unenroll(...) {
        IS_ORGSELF_ADMIN_OR_STUDY_ADMINRESEARCHER.checkAndThrow("orgIdstudyId", orgIdstudyId);
    }
// do something
}

Pros:

  1. Easier to implement and understand at this point, when compared with overriding Spring Security’s implementation classes

  2. Arguably, easier to understand because it’ll only contain what it necessary for our application (as opposed to Spring which is always more complicated because it can handle anything, including future requirements).

...

Take the example of AuthUtils.checkSelfStudyResearcherOrAdmin check for enrollments:

Code Block
public class EnrollmentService {

    @GetMapping("/v5/studies/{studyId}/enrollments")
    public PagedResourceList<EnrollmentDetail> getEnrollments(...) {
    }
    
    @GetMapping("/v3/participants/self
POST /enrollments")
    public PagedResourceList<EnrollmentDetail> getSelfEnrollments(...) {
    }

    @PostMapping("/v5/studies/{studyId}/enrollments")
    public Enrollment enroll(...) {
    }

    @PostMapping("/v3/participants/self/enrollments")
    public Enrollment enrollSelf(...) {
    }

    @PostMapping("/v5/studies/{studyId}/enrollments/ study researcher or admin
POST /v3/studies/enrollments{userId}")
    public void updateEnrollment(...) {
    }
    
    @DeleteMapping("/v5/studies/{studyId}/enrollments/{userId}")
    public Enrollment unenroll(...) {
    }

    @DeleteMapping("/v3/participants/self/enrollments/{userId}")
    public Enrollment unenrollSelf(...) {
    }
}

Another example are org administrators who can list, read, create, and delete administrative accounts in their organizations:

...