KNS Authorization

In most client applications, there’s going to be a need to guard certain end users from certain functionality. Certain documents may be locked down and only accessible to a small group of users. A tab on a certain document may only be visible based on if a System Parameter is turned on. KNS provides a standard way to turn on and off functionality based on conditions like these.

There are two sides to this functionality. One side is that these authorizations are integrated with KIM. KNS provides a number of contexts where KIM permissions are called and checked, to see if the current user is permitted to perform the action. Examples of such actions are looking up business objects, initiating documents, adding notes to a document, using a screen, or viewing a field on an inquiry or a maintenance document.

The other side is business logic associated with such authorizations. For instance, KIM permissions may be set up to allow any user of the client application to initiate a given document. However, there may be a business requirement that the document can only be initiated in the month of June. Since KIM permissions cannot capture that kind of logic, KNS provides point where programmers can create such logic.

When building KNS documents, there are two classes associated with the document which make these authorizations: the Document Presentation Controller and the Document Authorizer.

The Document Presentation Controller is where business logic authorizations are handled. These classes must implement the org.kuali.rice.kns.document.authorization.DocumentPresentationController. There are also interfaces for MaintenanceDocumentPresentationController and TransactionalDocumentPresentationController, each tailored to their respective document families.

The Document Authorizer is the class that does the KIM permission checks. Once again, there is an interface, org.kuali.rice.kns.document.authorization.DocumentAuthorizer, which all document authorizers must implement, and it also has two sub-interfaces, MaintenanceDocumentAuthorizer and TransactionalDocumentAuthorizer.

In cases where an authorization is checked by both presentation controller and authorizer, the presentation controller is called first, and then it’s result is somehow sent to the authorizer. For instance, DocumentPresentationController has a method, getActions(), which returns a Set of Strings, each representing a standard document action (for instance, the Route document action). That Set is then sent as an argument to the DocumentAuthorizer; the DocumentAuthorizer only performs KIM checks for the actions that have been handed to it.

The classes for both the document authorizer and presentation controller are set in the document in the data dictionary. Here’s an example, from the sample travel application:

<bean id="TravelRequest" parent="TravelRequest-parentBean"/>

<bean id="TravelRequest-parentBean" abstract="true" parent="TransactionalDocumentEntry">
    <property name="documentTypeName" value="TravelRequest"/>
    <property name="documentClass" value="edu.sampleu.travel.document.TravelDocument2"/>
    <property name="documentAuthorizerClass" value="edu.sampleu.travel.document.authorizer.TravelDocumentAuthorizer"/>
    <property name="documentPresentationControllerClass" value="edu.sampleu.travel.document.authorizer.TravelDocumentPresentationController"/>
        ...
</bean>

The classes for the authorizer is given to the documentAuthorizerClass property of the main document bean, and the presentation controller class is specified in the documentPresentationControllerClass property. This is the same for maintenance documents as well. Once these are specified, the proper classes will be constructed at authorization invocation contexts automatically.

Common Document Authorizations

There are two authorizations which are common to all documents. In both cases, the document presentation controller is called and then the authorizer if needed.

The first common authorization is the document initialization authorization. DocumentPresentationController has this method to be overridden for business logic about when a document can be initialized:

public boolean canInitiate(String documentTypeName);

The DocumentAuthorizer also has a:

public boolean canInitiate(String documentTypeName, Person user);

The DocumentAuthorizer checks the KR-SYS Initiate Document permission.

The second common authorization is handled by DocumentPresentationController#getDocumentActions:

public Set<String> getDocumentActions(Document document, Person user, Set<String> documentActions);

It passes its result to DocumentAuthorizer#getDocumentActions:

This authorization actually handles many common authorizations which need to be passed to the document presentation layer. The Set returned by the DocumentAuthorizer is converted into a Map, where each element in the Set becomes a key of the Map. That Map can then be accessed in any web page or tag through the KualiForm.documentActions variable.

org.kuali.rice.kns.document.authorization.DocumentPresentationControllerBase defines a number of protected methods which are inquired when the Set returned by getDocumentActions is built. Builders of client applications are far more likely to override one of those helper methods than override getDocumentActions from scratch.

Table 5.5. Document Presentation Controller Methods

DocumentPresentationControllerBase methodPurposeRelated Authorizer Permission
protected boolean canEdit(Document document)Determines if the document can be edited; if false is returned, then all fields are in a read only stateKR-NS Edit Document
protected boolean canAnnotate(Document document)Determines if any ad hoc requests can be added to the document. 
protected boolean canReload(Document document)Determines if the document can be reloaded from the database. 
protected boolean canClose(Document document)Determines if the document can be closed, returning the end user to the portal. 
protected boolean canSave(Document document)Determines if the document can be saved.KR-WKFLW Save Document
protected boolean canRoute(Document document)Determines if the document can be routed to workflow.KR-WKFLW Route Document
protected boolean canCancel(Document document)Determines if the document can be canceled.KR-WKFLW Cancel Document
protected boolean canCopy(Document document)Determines if the document can be used as the template for a new document.KR-NS Copy Document
protected boolean canPerformRouteReport(Document document)Determines if the future requests workflow report can be viewed. 
protected boolean canAddAdhocRequests(Document document)Determines if the document can have ad hoc routing requests added to it.KR-NS Send Ad Hoc Request
protected boolean canBlanketApprove(Document document)Determines if the document can be blanket approved.KR-WKFLW Blanket Approve Document
protected boolean canApprove(Document document)Determines if the document can be approved.KR-NS Take Requested Action
protected boolean canDisapprove(Document document)Determines if the document can be disapproved.KR-NS Take Requested Action
protected boolean canSendAdhocRequests(Document document)Determines whether the document will be allowed to send itself to KEW to fulfill ad hoc requests.KR-NS Send Ad Hoc Request
protected boolean canSendNoteFyi(Document document)Sends an FYI to previous approvers if a note is added.KR-NS Send Ad Hoc Request
protected boolean canEditDocumentOverview(Document document)Determines if the fields in the document overview (title, etc) can be edited.KR-NS Edit Document
protected boolean canFyi(Document document)Determines if the document can be FYI’d.KR-NS Take Requested Action
protected boolean canAcknowledge(Document document)Determines if the document can be acknowledged.KR-NS Take Requested Action


DocumentAuthorizer also contains a number of methods which are not subject to document presentation controller input. These are:

Table 5.6. Document Authorizer Methods

Document Authorizer methodDescriptionKIM Permission Checked
public boolean canOpen(Document document, Person user);Determines if the current user can open the documentKR-NS Open Document
public boolean canReceiveAdHoc(Document document, Person user, String actionRequestCode);Determines if the person, for whom there is a proposal to add an ad hoc routing request, can receive that ad hoc routing requestKR-WKFLW Ad Hoc Review Document
public boolean canAddNoteAttachment(Document document, String attachmentTypeCode, Person user);Determines if the current user can add a note to the document.KR-NS Add Note / Attachment
public boolean canDeleteNoteAttachment(Document document, String attachmentTypeCode, String createdBySelfOnly, Person user);Determines if the current user can delete a note on a document.KR-NS Delete Note / Attachment
public boolean canViewNoteAttachment(Document document, String attachmentTypeCode, Person user);Determines if the current user can view a note on the document.KR-NS View Note / Attachment


Maintenance Document Authorizations

A couple of authorizations are specific to maintenance documents. The document presentation controller and document authorizer diverge somewhat on which methods they support to control authorizations in documents, so each will be treated separately, save for the one method they do share.

That one method is canCreate. Here is MaintenanceDocumentPresentationController’s declaration of the method:

public boolean canCreate(Class boClass);

It takes the class of the business object, of which the end user is attempting to create a new record of through a maintenance document. Business logic can be written to determine if new records of the given class can be created through a maintenance document.

MaintenanceDocumentAuthorizerBase checks the KR-NS Create / Maintain Record(s) to see if a new business object of the type can be created for its corresponding check.

MaintenanceDocumentPresentationController has two methods which do not have parallels in the MaintenanceDocumentAuthorizer. They are:

public Set<String> getConditionallyReadOnlyPropertyNames(MaintenanceDocument document);

public Set<String> getConditionallyReadOnlySectionIds(MaintenanceDocument document);

To understand this, recall that if there is a field on a maintenance document which is unconditionally read only, that is set within the data dictionary file for that maintenance document. Of course, it brings up the question of what to do if a field or a section is read only some times based on certain business logic and editable at others.

The answer to this has been provided by the MaintenanceDocumentPresentationController. A Set of the property names of the fields or names of the sections which are, given the current condition of the MaintenanceDocument argument, currently read only is returned from the method.

MaintenanceDocumentAuthorizer’s separate methods are similar to canCreate. The first is canMaintain, which determines if the current user can edit an already existing business object. There is also canCreateOrMaintain, which combines the KIM permission checks when the document is routed to make sure the routing is valid.

Finally, MaintenanceDocumentAuthorizer has a method:

public Set<String> getSecurePotentiallyReadOnlySectionIds();

Unlike most methods in MaintenanceDocumentAuthorizer, this method was actually specified to be overridden. It returns a Set of the names of sections on a maintenance document which may be read only based on the user.

Maintenance Document/Inquiry Authorizations

Because maintenance documents and inquiries are rendered using the same code, authorizations which control that rendering are shared between the two. There are two such permissions: KR-NS View Inquiry or Maintenance Document Field and KR-NS View Inquiry or Maintenance Document Section. Since maintenance documents allow editing in addition to viewing, there are two other permissions which control the ability of end users to edit: KR-NS Modify Maintenance Document Field and KR-NS Modify Maintenance Document Section.

These are used only as KIM permissions, and they are invoked directly within the rendering framework. Their purpose is as follows:

  • KR-NS View Inquiry or Maintenance Document Section will only render a whole tab section to those with the permission.

    KR-NS Modify Maintenance Document Section will only allow edits for a whole tab section to those with the permission; otherwise, the fields within the section will be rendered as read only.

  • KR-NS View Inquiry or Maintenance Document Field will only render a field to entities granted this permission.

  • KR-NS Modify Maintenance Document Field will only allow edits of a field to entities granted this permission; the field will otherwise be rendered as read only.

If no KIM permission is specified for a given section or field, it is assumed that it is viewable on both the Inquiry and Maintenance Document and the field will be editable on the Maintenance Document.

There are no document presentation controller methods to override if the ability to view or edit parts of an inquiry or maintenance document based on business logic. If a client application has such a requirement, adventurous technical personnel are invited to look at Maintainable#getRows and Inquirable#getRows. The subject is otherwise outside the scope of this document.

Transactional Document Authorizations

There is only one major authorization which is added to TransactionalDocumentPresentationController and TransactionalDocumentAuthorizer: getEditModes. Much like DocumentPresentationController#getDocumentActions(), TransactionalDocumentPresentationController#getEditModes() takes as an argument the document the authorization is being asked of and returns a Set of Strings.

Unlike DocumentPresentationController#getDocumentActions(), though, TransactionalDocumentPresentationController#getEditModes() does not have a set of standard actions it returns. Instead, it is designed specifically to allow any kind of action through the web presentation layer. There, the edit modes can be checked and acted upon in document specific ways.

How is this helpful? In maintenance documents, since the KNS handles the rendering in a standard way, it is easy to turn sections on and off; KIM permissions or work through the maintainable can accomplish. In transactional documents in the other hand, rendering is more manual. However, getEditModes provides a way for the business logic layer to communicate information to the presentation layer.

To get the presentation layer to not display a section, then, a presentation controller might be written as so:

public ExampleDocumentPresentationController extends TransactionalDocumentPresentationController {
    public Set<String> getEditModes(Document document) {
        final ExampleDocument exampleDocument = (ExampleDocument)document;
        Set<String> editModes = new HashSet<String>();
        if (exampleDocument.dontShowExtraSection()) {
            editModes.add("NO_EXTRA_SECTION");
        }
		return editModes;
    }

}

Then, in Example.jsp, we may have code that looks like this:

<c:if test="${!KualiForm.editingMode['NO_EXTRA_SECTION']}">
    <kul:tab tabTitle="Extra Section" defaultOpen="true" tabErrorKey="${Constants.EXTRA_SECTION_ERRORS}">
        ...
    </kul:tab>

</c:if>

Edit Modes also go through the document authorizer, meaning that there is a permission associated with them: KR-NS Use Transactional Document. Expected permission details are the document type and the name of edit mode (in this example, “NO_EXTRA_SECTION”).

Other Authorizations

Finally, there are two permissions which do not affect documents but only business objects. They are:

  • KR-NS Look Up Records, which determines if records of the given type can be looked up by the current user. Client applications seeking to change this based on business logic would likely override the business object’s implementation of org.kuali.rice.kns.lookup.LookupableHelperService#getRows().

  • KR-NS Inquire Into Records, which determines if the current user can inquire into records of the given business object. Client applications seeking to change this based on business logic would likely override the business object’s implementation of org.kuali.rice.kns.lookup.LookupableHelperService#getInquiryUrl() or its implementation of org.kuali.rice.kns.inquiry.Inquirable#getInquiryUrl(BusinessObject businessObject, String attributeName, boolean forceInquiry), depending on the use case.

Overriding Document Authorizers

Document authorizers handle their calls to Kuali Identity Management in standard ways already. Because this side of authorizations mostly relies on KIM configuration, there is very little reason to override Document Authorizers. In fact, such overrides only occur to accommodate one of the two following situations.

The first situation is when a client application-specific KIM permission which affects documents is invoked. In this case, it is a best practice to give developers the ability to change this logic through the document presentation controller, and then do the actual KIM permission call in the document authorizer. Document authorizers were designed to be standard permission invocation contexts, and using them as such makes development much easier.

The second situation is to add extra attributes to permission detail attribute sets, role qualifier attribute sets, or to both. These extra attributes are sent on every KIM permission call performed by the authorizer. The reason for doing this is to make sure that permissions and roles can qualify properly when the document authorizer performs its call.

For example, imagine a role where the users are qualified by a client application specific field. The document authorizer does not know where or how to gather the data for that field, and yet it must be sent to KIM for the role members to be resolved correctly. Therefore, the

protected void addRoleQualification(BusinessObject businessObject, Map<String, String> attributes) 

method should be overridden, and the attributes argument should be filled with values from the businessObject (which may well be a document) to make sure the role is resolved correctly.

The same can be done for permission details:

protected void addPermissionDetails(BusinessObject businessObject, Map<String, String> attributes)

Finally, if a certain attribute is used both in finding the permission via the permission details and resolving the role, then the following method should be overridden; it will add the attribute to both:

protected void addStandardAttributes(Document document, Map<String, String> attributes)