Versions Compared

Key

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

...

The product owner understands that one organization may place a Hold on a student while another organization is responsible for expiring it. The However, the Issue has defines 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.

...

Code Block
title2. Authorization In The Hold OSID Provider
public class HoldAdminSession
    extends net.okapia.osid.jamocha.adapter.hold.spi.AbatractAdapterHoldAdminSession
    implements org.osid.hold.HoldAdminSession
 
    private final org.osid.authorization.AuthorizationSession authzSession;
    private static final org.osid.id.Id CREATEHOLD_FUNCTION_ID;
    private static final org.osid.id.Id UPDATEHOLD_FUNCTION_ID;
    private static final org.osid.id.Id DELETEHOLD_FUNCTION_ID;
 
    HoldAdminSession(org.osid.hold.HoldAdminSession session, org.osid.authorization.AuthorizationSession authzSession) {
        super(session);
        this.authzSession = authzSession;
        return;
    }
    public org.osid.hold.HoldForm getHoldFormForCreate(org.osid.id.Id issueId, org.osid.id.Id resourceId, org.osid.type.Type[] recordTypes) {
        if (this.authzSession.isAuthorized(getAuthenticatedAgentId(), CREATEHOLD_FUNCTION_ID, issueId) {
            throw org.osid.PermissionDeniedException();
        }
        
        // wrap the form so we need can get the issueId on the way back in
        return (new HoldFormAdapter(super.getHoldFormForCreate(issueId, resourceId, recordTypes), issueId);
    }
 
    public org.osid.hold.Hold createHold(org.osid.hold.HoldForm form) {
        if (this.authzSession.isAuthorized(getAuthenticatedAgentId(), CREATEHOLD_FUNCTION_ID, getIssueId(form)) {
            throw org.osid.PermissionDeniedException();
        }
 
        return (super.createHold(form));
    }
    public org.osid.hold.HoldForm getHoldFormForUpdate(org.osid.id.Id holdId) {
        if (this.authzSession.isAuthorized(getAuthenticatedAgentId(), UPDATEHOLD_FUNCTION_ID, holdId) {
            throw org.osid.PermissionDeniedException();
        }
    
        // wrap the form so we need can get the issueId on the way back in
        return (new HoldFormAdapter(super.getHoldFormForUpdate(holdId), holdId);
    }
 
    public org.osid.hold.Hold updateHold(org.osid.hold.HoldForm form) {
        if (this.authzSession.isAuthorized(getAuthenticatedAgentId(), UPDATEHOLD_FUNCTION_ID, getIssueIdgetHoldId(form)) {
            throw org.osid.PermissionDeniedException();
        }

        return (super.updateHold(form));
    }
    public void deleteHold(org.osid.id.Id holdId) {
        if (this.authzSession.isAuthorized(getAuthenticatedAgentId(), DELETEHOLD_FUNCTION_ID, holdId) {
            throw org.osid.PermissionDeniedException();
        }
    
        return (super.deleteHold(holdId));
    }
 
    private static org.osid.id.Id getIssueId(org.osid.hold.HoldForm form) {
        if (!(form instance of HoldFormAdapter)) {
            throw new org.osid.InvalidArgumentException("not my form!");
        }
 
        return (((HoldFormAdapter) form).getIssueId());
    }
}

...

  1. Know the difference between a functional requirement and a solution. It's easy to be led by the nose into a clumsy solution. Many people think in terms of capturing and moving data. They also believe that any application responsibility means the end-user has to do more work. Service design is a different paradigm. It is about assigning responsibilities among blocks of code.
  2. Gnarly code (Example 1) and poor performance are signs of a factoring problem. Performance can always be increased incrementally by breaking things up and leveraging bulk operations. However, more study is warranted when performance is very off base and developers look to couple merge services together. 
  3. Some functional requirements are short sighted. Tightly coupling organizational affiliations with authorizations is not necessary in small environments and never holds up well in an enterprise (changing hold authorization requirements will never cause an institution to do a re-org).
  4. Squirreling through a problem creates new problems to be solved, and solving those creates more problems, and so on. Sometimes it helps to go back to the very beginning and find that one initial assumption on which everything else was based. It's so much easier to do this on a whiteboard rather than wait until the code was written. 
  5. People have trouble with the asymmetry of services. How a consumer uses stuff coming out of a service and how that stuff gets in there are two different problems. In simpler designs, the data object goes in, the data object comes out. In a service paradigm, approach these two aspects independently. 
  6. Generally speaking, encapsulation is good. But here, it made more sense to surface the management of authorizations but in such a way as to carefully manage assumptions between the application and the Authorization OSID.
  7. This case study avoided the use of the word "Role." Roles are often used in other frameworks to manage sets of people on the periphery of an authorization service. A role should describes the action one can perform on something. In the OSID world, it is the Agent, Function, and Qualifier. This is the Authorization itself. A Role is not an attribute of a Person nor is it a group. An Agent doesn't have a role until it is joined with a Function and Qualifier. The slipperiness of Resources allows for creating Authorizations using groups or other rules to cut down on the explicit Authorizations that need to be managed. These composite Resources can be aligned with Functions and Qualifiers ("the group of people who can create Holds in the Bursar's Office") but the role isn't realized until the explicit Authorization is created. This semantic detail helps clarify how the enforcement point works and pays off when applying this principle to Workflow. OSIDs avoid the word altogether. 
  8. A litmus test for a good authorization design is to have the ability to ask the question "who has access to perform this Function on Qualifier?" In order to answer this question, there needs to be the ability to expand explicitly managed authorizations into a list of implicit authorizations based on expansion of the Resources or Qualifier hierarchy. This helps keep authorization logic clear and out in the open.

...