Creating External Authorization Handlers

You can create external authorization handlers for the Rights Management service. External authorization handlers provide centralized access control for documents in your organization. The Rights Management service controls access to policy-protected documents by performing a policy evaluation when determining whether a user can access a policy-protected document. For example, the Rights Management service decides whether a user can print a policy-protected document.

By creating an external authorization handler, you can use an access control mechanism that your content management system uses, in addition to the standard policy evaluation process. As a result, document access can be controlled by the same control mechanism that your content management system uses. For example, when the Rights Management service determines whether a user can print a policy-protected document, it uses the standard policy evaluation process and the access control mechanism that your content management system uses.

As part of the policy evaluation process, the Rights Management service requires the identifier value of both the principal that is requesting access to the policy-protected document and the policy-protected document. After the Rights Management service receives these values, it generates a set of permissions. When an external authorization handler is registered with the Rights Management service, it passes the set of permissions to the external authorization handler. The external authorization handler can then add permissions to or remove permissions from the set of permissions.

After an external authorization handler removes or adds permissions, it returns the set of permissions and an optional expiration date to the Rights Management service. The Rights Management service then creates a voucher that specifies the permissions that control access to a policy-protected document. If the voucher contains an expiration date, then the voucher is returned to the client, where it is stored and used. If the voucher located on the client has expired, the Rights Management service generates the appropriate permissions that control access to the policy-protected document.

Although it is possible to completely replace the Rights Management service policy evaluation process with an external authorization handler, it is recommended that you use an external authorization handler in conjunction with the policy evaluation process.

After you deploy a component to LiveCycle, you can use it to create a process using Workbench or you can invoke the component’s service using an invocation method. For example, you can invoke the service using the Java API. (See Invoking LiveCycle using the Java API.)

Note: An External Authorization Handler is a LiveCycle component. Before you create an External Authorization Handler, it is recommended that you become familiar with creating components. (See Creating Your First Component.)

Summary of steps

To develop an external authorization handler, you must perform the following steps:

  1. Set up your development environment.

  2. Define the external authorization handler implementation.

  3. Define the component XML file.

  4. Deploy your component.

  5. Test your component.

Sample files

This section creates a Java class that corresponds to the PrintServiceSPISample.java file that can be located in the [install directory]\Adobe\Adobe LiveCycle ES3\sdk\samples\RightsManagement\ExternalAuthorization\Java\PrintOnce folder, where [install directory] is the LiveCycle installation location. As you are reading through this section, it is recommended that you also refer to this JAVA file.

Setting up your development environment

To set up your development environment, you must create a new Java project, such as an Eclipse project. The version of Eclipse that is supported is 3.2.1 or later.

The Rights Management SPI requires the edc-server-spi.jar file to be set in your project’s class path. If you do not reference this JAR file, you cannot use the Rights Management SPI in your Java project. This JAR file is installed with the LiveCycle SDK in the [install directory]\Adobe\Adobe LiveCycle ES3\sdk\spi folder.

In addition to adding the edc-server-spi.jar file to your project’s class path, you must also add the JAR files that are required to use the Rights Management service API. These files are needed to use the Rights Management API within the external authorization handler. For example, you must use an EventManager object to search for events. (See Searching for events.)

Defining the external authorization handler implementation

To develop an external authorization handler, you must create a Java class that implements the com.adobe.edc.server.spi.authorization.ExternalAuthorizer interface. This class contains a method named evaluate, which the Rights Management service invokes when a client application, such as Acrobat, attempts to open a policy-protected document.

The evaluate method accepts a single parameter, which is an ExternalAuthDTO object. This object contains the following data members:

  • context: Specifies the context.

  • LicenseId: Specifies the license identifier of the policy-protected document.

  • policyId: Specifies the identifier of the policy that is protecting the document.

  • ClientIPaddress: Specifies the IP address of the client that is attempting to view the policy-protected document.

  • Anonymous: Specifies whether or not the client has anonymous access to the policy-protected document.

  • permissions: A java.util.ArrayList object that contains the initial permissions that were determined by the Rights Management service’s policy evaluation process.

  • policyProps: A java.util.Map object that describes policy properties. Each policy can be a single string or an array of strings.

  • operationType: An ExternalAuthOperationType object that represents an operation.

  • locale: A string value that specifies the locale of the policy-protected document.

  • alternateId: A string value that specifies the alternate identifier of the policy-protected document.

The evaluate method returns an ExternalAuthResultDTO object that contains the following information:

  • A java.util.ArrayList object that contains the permissions that are applied to the policy-protected document.

  • An expiration key that specifies the time at which the voucher expires. If an expiration time is not specified, the voucher is considered a one-time-only voucher that is used only for the current operation.

Unless a policy-protected document has been revoked, an external authorization handler is invoked, regardless of the permissions that are returned by the policy evaluation process. Sometimes the policy evaluation process determines that access to a policy-protected document is denied. In this situation, the set of permissions passed within the java.util.Map object is a zero-length string array.

Retrieving permissions

You can retrieve the permissions that the Rights Management service’s policy evaluation process generated and passed to the external authorization handler. To retrieve permissions, invoke the ExternalAuthDTO object’s getPermissions method, which returns a java.util.ArrayList that contains the permissions.

    //Get the permissions passed to the external authorization handler 
    ArrayList permissions = (ArrayList)auth_info.getPermissions();

The following table specifies the permissions that can be passed to the an external authorization handler:

Permission Name

Description

pdrl-ex:com.adobe.aps.onlineOpen

Enables the document to be opened while online.

pdrl-ex:com.adobe.aps.offlineOpen

Enables the document to be opened while offline.

pdrl-ex:com.adobe.aps.revoke

Enables the document to be revoked.

pdrl-ex:com.adobe.aps.policySwitch

Enables a policy change on the document.

pdrl-ex:com.adobe.aps.pdf.printHigh

Enables the document to be printed at high resolution.

pdrl-ex:com.adobe.aps.pdf.printLow

Enables the document to be printed.

pdrl-ex:com.adobe.aps.pdf.edit

Enables the document to be edited. For example, if the PDF document is an interactive form, you can modify the document’s fields.

pdrl-ex:com.adobe.aps.pdf.docAssembly

Enables the document to be assembled using the Assembler service.

pdrl-ex:com.adobe.aps.pdf.editNotes

Enables comments to be applied to the document.

pdrl-ex:com.adobe.aps.pdf.fillAndSign

Enables the document to be signed.

pdrl-ex:com.adobe.aps.pdf.copy

Enables the document’s contents to be copied.

pdrl-ex:com.adobe.aps.pdf.accessible

Enables the document to be assessable using accessible software.

After you retrieve the permissions that were passed to the external authorization handler, you can either remove permissions or add new permissions. For example, to add a permission, you can invoke the java.util.ArrayList object’s add method. The following code example removes the print permission. That is, all permissions except for the print permission are added to the java.util.ArrayList object.

Retrieving permissions

private ArrayList removePrintFromPermissions( ArrayList permissions_list ) 
{ 
    ArrayList ret_val = new ArrayList(); 
     
    for( int i = 0; i < permissions_list.size(); i++ ) 
    { 
        String current_permission = (String)permissions_list.get(i); 
        if( !( current_permission.indexOf( "print" ) >= 0 ) ) 
        { 
            ret_val.add( current_permission ); 
     } 
}

Searching for events

An external authorization handler can search the Rights Management database and query information that specifies the number of times a user performed a specific operation during a specified time interval. For example, an external authorization handler can query the database to determine how many times a policy-protected document has been printed since midnight. (See Searching for Events.)

To query the Rights Management service database, invoke the EventManager object’s searchForEvents method and pass an EventSearchFilter object. You can specify the search criteria, such as the event name, by invoking methods that belong to the EventSearchFilter object, as shown in the following code example.

Searching for events

    EventSearchFilter print_search = new EventSearchFilter();  
    //  Configure an event search for the print event. 
    print_search.setDocumentId( license_id ); 
    print_search.setEventNamespace( "com.adobe.edc.documentevent" ); 
    print_search.setEventName( "Print High Resolution" ); 
    print_search.setFirstTime( new Date( 100, 1, 1 ) ); 
    print_search.setLastTime( new Date( ) ); 
    print_search.setWasAllowed( new Boolean(true) ); 
    print_search.setUserOid( user_id ); 
             
    Event[] out_events = _evt_manager.searchForEvents( print_search, 10 );

The searchForEvents method returns an array of com.adobe.livecycle.rightsmanagement.client.infomodel.Event objects matching the search filter. Before you can query the Rights Management database, you must set connection properties. (See Setting connection properties.)

Defining the external authorization handler implementation

The following external authorization handler implementation enables a policy-protected document to be printed only once.

package com.adobe.livecycle.samples.externalauthorization.provider; 
 
import com.adobe.edc.server.spi.authorization.*; 
import com.adobe.idp.Context; 
import com.adobe.idp.dsc.clientsdk.ServiceClientFactory; 
import com.adobe.livecycle.rightsmanagement.client.RightsManagementClient; 
import com.adobe.livecycle.rightsmanagement.client.EventManager; 
import com.adobe.livecycle.rightsmanagement.client.infomodel.Event; 
import com.adobe.livecycle.rightsmanagement.client.infomodel.EventSearchFilter; 
 
import java.util.ArrayList; 
import java.util.Date; 
 
/** 
    *  The PrintServiceSPISample allows a given policy-protected document to be printed only once. 
    */ 
 
public class PrintServiceSPISample implements ExternalAuthorizer 
{ 
       private EventManager           _evt_manager = null; 
       private ServiceClientFactory   _sc_factory  = null; 
       private RightsManagementClient _rm_client   = null; 
     
       public ExternalAuthPropertyDTO[] getProviderProperties() 
       { 
    return new ExternalAuthPropertyDTO[0]; 
       } 
     
       public ExternalAuthResultDTO evaluate( ExternalAuthDTO auth_info ) 
       { 
    ExternalAuthResultDTO ret_val = new ExternalAuthResultDTO(); 
         
    if( auth_info.getOperationType().isOperationSecureDocument() ) 
    { 
        ret_val.setPermissions( auth_info.getPermissions() ); 
        return ret_val; 
    } 
 
    //  Determine if the document has been printed. If so,  
    //    remove the print permission. 
        System.out.println( this.getClass().getName() + ": --- VIEWING DOCUMENT WITH LICENSE ID " + auth_info.getLicenseId() ); 
    try 
    { 
        //Set connection properties         
        initializeRightsManagementAPI(); 
             
        //Set the user context 
        Context context = (Context)auth_info.getContext(); 
        String auth_user_id = context.getAuthenticatedUser().getOid(); 
         
        // If the document was printed, then reset the permissions that are  
        // returned to the server 
            // so they do not include print. 
        if( hasDocumentBeenPrinted( auth_info.getLicenseId(), auth_user_id ) ) 
        { 
        System.out.println( this.getClass().getName() + ": --- REMOVING PRINT PERMISSION FOR DOCUMENT WITH LICENSE ID " + auth_info.getLicenseId() ); 
                 
        //Get the final permissions 
        ArrayList final_permissions = removePrintFromPermissions( auth_info.getPermissions() ); 
         
        //Set the final permissions 
        ret_val.setPermissions(final_permissions); 
        }             
        else 
        { 
        ret_val.setPermissions( auth_info.getPermissions() ); 
        } 
    } 
    catch( Exception e ) 
    { 
        ret_val.setPermissions( auth_info.getPermissions() );             
    } 
    return ret_val; 
       } 
     
       //Remove print permissions 
       private ArrayList removePrintFromPermissions( ArrayList permissions_list ) 
       { 
    ArrayList ret_val = new ArrayList(); 
     
         
    for( int i = 0; i < permissions_list.size(); i++ ) 
    { 
        String current_permission = (String)permissions_list.get(i); 
             
        if( !( current_permission.indexOf( "print" ) >= 0 ) ) 
        { 
        ret_val.add( current_permission ); 
        } 
    } 
    return ret_val; 
       } 
     
       //Determine if the document has been printed 
       private boolean hasDocumentBeenPrinted( String license_id, String user_id ) 
       { 
    try 
    {         
        //Create EventSearchFilter object 
        EventSearchFilter print_search = new EventSearchFilter();  
         
        //Configure an event search for the print event. 
        print_search.setDocumentId( license_id ); 
        print_search.setEventNamespace( "com.adobe.edc.documentevent" ); 
        print_search.setEventName( "Print High Resolution" ); 
        print_search.setFirstTime( new Date( 100, 1, 1 ) ); 
        print_search.setLastTime( new Date( ) ); 
        print_search.setWasAllowed( new Boolean(true) ); 
        print_search.setUserOid( user_id ); 
             
        System.out.println( "SEARCHING FOR PRINT EVENTS FOR DOCUMENT " + license_id + " AND USER " + user_id ); 
 
        //Find print events for this policy-protected document 
        Event[] out_events = _evt_manager.searchForEvents( print_search, 10 ); 
 
        boolean was_printed = false; 
             
        if( out_events != null ) 
        { 
        int n_print_events = out_events.length; 
 
        was_printed = ( n_print_events > 0 ); 
                 
        if( was_printed ) 
        { 
            System.out.println( "DOCUMENT WAS PRINTED: " + n_print_events  + " TIMES" ); 
        } 
        } 
             
        return was_printed; 
    } 
    catch( Exception e ) 
    { 
        e.printStackTrace(); 
     
        return false; 
    } 
       } 
     
       //Set connection properties 
       private void initializeRightsManagementAPI() throws Exception 
       { 
    try 
    {     
        _sc_factory  = ServiceClientFactory.createInstance(); 
        _rm_client   = new RightsManagementClient( _sc_factory );         
        _evt_manager = _rm_client.getEventManager(); 
    } 
    catch( Exception e ) 
    { 
        System.out.println( this.getClass().getName() + ": --- failed to initialize Rights Management API" );                 
             
        throw e;             
    }         
       } 
} 
Note: This Java class is saved as a JAVA file named PrintServiceSPISample.java.

Defining the component XML file for the authorization handler

You must define a component XML file in order to deploy the external authorization handler component. A component XML file exists for each component and provides metadata about the component.

The following component.xml file is used for the external authorization handler. Notice that the service name is PrintControlSPISample and the operation this service exposes is named evaluate. The input parameter is com.adobe.edc.server.spi.authorization.ExternalAuthDTO and the output value is com.adobe.edc.server.spi.authorization.ExternalAuthResultDTO.

Defining the component XML file for the external authorization handler

<component xmlns="http://adobe.com/idp/dsc/component/document"> 
    <component-id>com.adobe.livecycle.samples.externalauthorization</component-id> 
    <version>1.0</version> 
    <class-path>adobe-livecycle-client.jar edc-server-spi.jar adobe-rightsmanagement-client.jar adobe-usermanager-client.jar</class-path> 
    <services> 
        <service name="PrintControlSPISample"> 
        <specifications> 
        <specification spec-id="com.adobe.edc.server.spi.authorization.ExternalAuthorizer"/> 
        </specifications>     
        <specification-version>1.0</specification-version> 
        <implementation-class>com.adobe.livecycle.samples.externalauthorization.provider.PrintServiceSPISample</implementation-class> 
        <auto-deploy category-id="Samples" service-id="PrintControlSPISample" major-version="1" minor-version="0"/> 
        <operations> 
            <operation name="evaluate"> 
            <input-parameter name="input" type="com.adobe.edc.server.spi.authorization.ExternalAuthDTO" required="true"/> 
            <output-parameter name="result" type="com.adobe.edc.server.spi.authorization.ExternalAuthResultDTO"/> 
        </operation> 
        <operation name="getProviderProperties"> 
            <output-parameter name="result" type="com.adobe.edc.server.spi.authorization.ExternalAuthPropertyDTO"/> 
        </operation> 
    </operations> 
    </service> 
    </services> 
</component>

Packaging the authorization handler

To deploy the external authorization handler to LiveCycle, you must package your Java project into a JAR file. You must ensure that the external JAR files on which the authorization handler’s business logic depends, such as the edc-server-spi.jar and adobe-rightsmanagement-client.jar files, are also included in the JAR file. As well, the component XML file must be present. The component.xml file and external JAR files must be located at the root of the JAR file.

The following illustration shows the Java project’s content that is packaged into the external authorization handler’s JAR file.

View full size graphic
A.
External JAR files required by the component

B.
JAVA file

You must package the external authorization handler into a JAR file. In the previous diagram, notice that .JAVA files are listed. Once packaged into a JAR file, the corresponding .CLASS files must also be specified. Without the .CLASS files, the authorization handler does not work.

Note: After you package the external authorization handler into a JAR file, you can deploy the component to LiveCycle. After you deploy the component, ensure that you restart the J2EE application server on which LiveCycle is deployed. (See Deploying your component.)
Note: You can also programmatically deploy a component. (See Programmatically Deploying Components.)

Testing the authorization handler

To test the external authorization handler, you can create a policy that uses it. For example, if you create a policy that uses the external authorization handler created in this section and apply the policy to a document, you are then only able to print the document once. That is, once you print the policy-protected document, the print menu option is not enabled.

Note: After the document is printed, the print permission is removed provided that the PDF document is closed and then opened again.

After you create a policy that uses the external authorization handler, you can secure a PDF document with the policy. (See Applying Policies to PDF Documents.)

PDF document that are secured with a policy that contains an external authorization handler can no longer be opened when the external authorization handler is stopped or uninstalled. When attempting to open the PDF document, you will receive an error message and the PDF document is not opened. You can open the PDF document by restarting the external authorization handler (or reinstalling and then starting it).

To create a policy that uses the external authorization handler:

  1. Deploy the external authorization handler’s JAR file using Workbench. (See Deploying your component.)

  2. Restart the application server.

  3. Log in to Administration Console.

  4. Click Services > Rights Management ES3 > Policies.

  5. Click on a given policy set.

  6. Click the Policies tab and click New.

  7. In the Name field, specify a name for the policy.

  8. In the External Authorization Providers section, click PrintControlSPISample.

  9. Click Save. A green check mark will appear next to the PrintControlSPISample item indicating that it is active.

  10. Finish creating the policy and save it.

Note: After you create a policy that uses the external authorization handler, you can protect a PDF document with the policy. (See Applying Policies to PDF Documents.)

Programmatically adding an external authorization handler

You can programmatically add an external authorization handler to a policy by using the Rights Management Service API. To programmatically add an external authorization handler, perform the following tasks:

  1. Create a Policy object. For example, when modifying a policy, you create a Policy object. (See Modify existing policies using the Java API.)

  2. Invoke the Policy object’s setPolicyProperties method.

When invoking the setPolicyProperties method, pass a java.io.Map object. The key (property name), in the java.io.Map object is the external authorizer handler. The following example is the key and value pair of a policy that contains an external authorizer handler and is printed in XML format (assuming the handler name is RemovePrintPerms):

<Property PropertyName="external authorizer"><PropertyValue>RemovePrintPerms</PropertyValue>

The following code fragment shows how to programmatically add an external authorization handler to a policy.

Programmatically adding an external authorization handler

addExtAuthHandlerToPolicy(String handlerName) 
{ 
    try 
    { 
      // The key which will be added to the Map (the property name) 
      String handlerTag = "external authorizer"; 
      Map<String,String> policyProps = new HashMap<String,String>(); 
      policyProps.put(handlerTag, handlerName); 
      this.policy.setPolicyProperties(policyProps); 
} 
    catch(Exception e) 
    { 
      fail("addExtAuthHandlerToPolicy(): The method " + 
      "threw an unexpected exception.\n " + e.getMessage()); 
    }         
}

// Ethnio survey code removed