Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 12 Next »

Summary

Designing authorization rules within an Authorization OSID Provider can provide visibility in who has access to what and simplify base service implementations. Working from the authorization evaluation perspective can solve the puzzle that is difficult to see through data attributes. This is a case study of a project that tackles this issue.

The Student System Project

The Student System Project is using the Hold OSID as a means of restricting registration access to students. The registration process uses the Rules.Check OSID as a means of managing what hold Blocks will be checked. 

The product owner understands that one organization may place a Hold on a student while another organization is responsible for expiring it. The Issue has a single responsible Resource? The product owner asks that a list of Organizations, not Resources, who can place the Hold and a list of Organizations who can remove the Hold be added to the Issue.

Work Begins

The application programmer and OSID implementor collaborate to define an OsidRecord for these extra lists of Organizations. The application populates them from user input on a hold administrative screen. 

Holds are tested and they can be created or removed by anyone. The product owner tells the application programmer that these organizations should be checked so that only people inside the organization are allowed to perform these operations.

The application programmer scratches his head, and looks to see how he can figure out who belongs to what organization. He looks to the Personnel OSID to answer this question and sees that Persons are related to Organizations via Appointments and Positions. Dismayed at the bizarre complexity of the situation, shovels out the following code:

boolean checkPlaceHold(org.osid.id.Id issueId, org.osid.id.Id agentId)
    throws org.osid.NotFoundException,
           org.osid.OperationFailedException,
           org.osid.PermissionDeniedException {
    org.osid.resource.ResourceAgentSession resourceAgentSession = resourceMgr.getResourceAgentSession();
 
    // I'll assume the resourceId is the same as the personId
    org.osid.id.Id resourceId = resourceAgentSession.getResourceIdByAgent(agentId);
 
    org.osid.hold.IssueLookupSession issueLookupSession = holdMgr.getIssueLookupSession();
    org.osid.hold.Issue issue = issueLookupSession.getIssue(issueId);
    
    // our local org data
    OrganizationHoldRecord record = (OrganizationHoldRecord) issue.getIssueRecord(organizationHoldRecordType);
 
    // could they have made this any more difficult!
    org.osid.personnel.AppointmentLookupSession appointmentLookupSession = personnelMgr.getAppointmentLookupSession();
    appointmentLookupSession.useEffectiveAppointmentView();
    org.osid.personnel.PositionLookupSession positionLookupSession = personnelMgr.getPositionLookupSession();
    positionLookupSession.useEffectivePositionView();
 
    // get the positions of an org - blasted there's no way to get a list of people in an org!
    try (org.osid.id.IdList orgIds = record.getOrgIdsWhoCanPlaceHold()) {
        while (orgIds.hasNext()) {
            org.osid.id.Id orgId = orgIds.getNextId();
            try (org.osid.personnel.PositionList positions = positionLookupSession.getPositionsForOrganization(orgId)) {
                while (positions.hasNext()) {
                    org.osid.personnel.Position position = positions.getNextPosition();
                    try (org.osid.personnel.AppintmentList appointments = appointmentLookupSession.getAppointmentsForPersonAndPosition(resourceId, position.getNextId()) {
                        if (appointments.hasNext()) {
                            return (true);
                        }
                    }
                }
            }
        }
    }
 
    return (false);
}            

Performance

It may come as a shock but the product owner complains that it takes too long to create a hold. Hundreds of database queries are spawned from these looping calls. Both the application programmer and OSID implementation programmer are in agreement on this one. They complain that these APIs were designed to their requirements. They first consider retrieving all the organization data in bulk and filtering through the results, but this seems wasteful. They conclude that if they can have a simple method:

boolean isAgentInAnyOfTheseOrgs(agentId, orgIds)

then they can optimize for this case in a single call and implement it in a direct SQL query. They put such a method in their own Java interface and wire it to the db via an SQL query that joins the Organization, Appointment, Position, and Resource tables. It's now lightening fast.

The Inquiry

The service architect inquires as to why these services have been joined together and she is told that the services do not meet their needs. She is informed that if this new method was put into the OSIDs, then it would be compliant.  There isn't much she can do to affect the OSIDs within the time frame of this project's milestone. Not yet knowing the details of the problem she talks in generalities that this is usually sign of a factoring issue. This is not is received well as she was already given the solution to the problem.

On other projects, the service architect can generally align with one of the project roles to help get the others on board. She can speak to the product owner's vision or simplify the work of an OSID implementation developer. When it comes to performance issues, she is alone to defend the methodology that appears to fly in the face of efficiency.

Back in The Lair

The service architect returns to her think tank to ponder the problem. She traces the problem starting from the requirement of discerning among the organizations who can do what with Holds of various Issues. Issues do constrain Holds and that seems like the place to do it. She eventually arrives at the same place the developers on the project did.

Knowing that hacking up cross-service methods made to look like legititmate service operations is akin to putting lipstick on a pig, she takes a different approach. She decides to work the problem backwards. 

Why are they capturing this data? To enforce a policy.

Authorization

At the end of the day, it's all about saying yes or no to an Agent. The service architect looks at authorization without concerning herself with how it got there. Immediately she notices something disturbing. The application is performing its own authorization in the checkPlaceHold() method and not even allowing the Hold OSID Provider to perform its own authorization enforcement. The enforcement must occur within the provider and the Authorization OSID can be brought in to help it out. 

insert picture

An Authorization check based on an Agent, Function, and Qualifier. The Function is "can create Hold." 

 

 

 

 



 

 

  • No labels