Creating Certificate Identity Resolver Providers

You can create a Certificate Identity Resolver (CIR) Provider for User Management that is used while performing certificate-based authentication. Using a CIR provider, you can map a custom certificate attribute to the user instead of the default ones supported by User Management. By default, User Management supports mapping from e-mail, DN, common name (CN) and name. For example, consider the following attribute map.

CN = TONY BLUE 
G = Tony 
SN = Blue 
Serial Number = 33532809M 
C = ES

Assume that you want to use the serial number attribute of Subject to perform the mapping. You can use its value to map to the user's canonical name. To perform this task, create a CIR provider that performs the custom mapping. A CIR provider is used in addition the User Management authentication logic that validates the certificate.

To create a CIR provider, you use the User Management IdentityResolver SPI to create a LiveCycle custom component. An IdentityResolver resolves a set of data and returns a user.

Note: The IdentityResolver SPI was added in LiveCycle ES2.5.

Summary of steps

To develop a CIR provider, perform the following steps:

  1. Set up your development environment.

  2. Define your application logic.

  3. Define the component XML file.

  4. Register the CIR provider with User Management. (This step is only required for the CIR provider and not required for other component types.)

  5. Package the CIR provider.

  6. Deploy and test your CIR provider.

Setting up your development environment

To create a CIR Provider, create an Eclipse Java project. The version of Eclipse that is supported is 3.2.1 or later. The User Management SPI requires the um-spi.jar file to exist in your project’s class path. If you do not reference this JAR file, you cannot use the User Management SPI in your Java project. This JAR file is installed with the LiveCycle SDK in the <install directory>/Adobe/Adobe LiveCycle ES4/sdk/spi folder.

The following JAR files must be added to your project’s classpath:

  • adobe-livecycle-client.jar

  • adobe-usermanager-client.jar

  • um-spi.jar

Defining your application logic

To define a CIR Provider, create a Java class that implements com.adobe.idp.um.spi.authentication.IdentityResolver. The Java class that implements IdentityResolver contains a method named resolve, which resolves passed in data and returns a user. In the following example, notice that the resolve method accepts a Map instance as a parameter. The Map instance contains a user's certificate list that is stored against the key UMConstants.AuthenticationOptions.USER_CERTIFICATE. The Map object’s get method returns ajava.util.List instance that contains an element that stores the certificate. The data type of the certificate element is java.security.cert.X509Certificate.

To obtain a certificate, invoke the java.util.List instance’s get method and pass a numeric value that corresponds to the index value. The first entry in the certificate list contains the user's certificate. From the certificate, you can obtain the serial number. In the following example, the java.security.cert.X509Certificate instance is passed to a user-defined method named getSerialNumber. This method accepts a java.security.cert.X509Certificate instance as a parameter and returns a string value that represents the user’s serial number.

The following application logic represents the CertIdentityResolver class that implements com.adobe.idp.um.spi.authentication.IdentityResolver.

package com.adobe.livecycle.sample; 
 
import java.security.cert.X509Certificate; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
 
import javax.naming.InvalidNameException; 
import javax.naming.ldap.LdapName; 
import javax.naming.ldap.Rdn; 
import javax.security.auth.x500.X500Principal; 
 
import com.adobe.idp.dsc.clientsdk.ServiceClientFactory; 
import com.adobe.idp.um.api.DirectoryManager; 
import com.adobe.idp.um.api.UMAuthenticationUtil; 
import com.adobe.idp.um.api.UMConstants; 
import com.adobe.idp.um.api.UMException; 
import com.adobe.idp.um.api.infomodel.PrincipalSearchFilter; 
import com.adobe.idp.um.api.infomodel.User; 
import com.adobe.idp.um.spi.authentication.IdentityResolver; 
import com.adobe.livecycle.usermanager.client.DirectoryManagerServiceClient; 
import com.adobe.logging.AdobeLogger; 
 
 
public class CertIdentityResolver implements IdentityResolver { 
    private static final AdobeLogger logger = AdobeLogger.getAdobeLogger(CertIdentityResolver.class); 
     
    private static final String SERIAL_NUMBER = "serialnumber"; 
 
    public User resolve(Map<String, Object> credential) { 
        List<X509Certificate> javaCerts = 
            (List<X509Certificate>) credential.get(UMConstants.AuthenticationOptions.USER_CERTIFICATE); 
        if(javaCerts == null || javaCerts.isEmpty()){ 
            throw new IllegalArgumentException("No certificate list passed"); 
        } 
         
        //The first certificate in the list contains the user certificate. Others are the part of Trust Chain 
        X509Certificate userCert = javaCerts.get(0); 
        String serialNumber = getSerialNumber(userCert); 
        if(serialNumber == null){ 
            logger.warning("Serial number not found with the certificate"); 
            return null; 
        } 
         
        DirectoryManager dm = new DirectoryManagerServiceClient(ServiceClientFactory.createInstance()); 
        User u = findPrincipal(serialNumber,dm); 
         
        //Due to a bug in UM need to set User against this key. It should be required by the Resolvers to set it 
        //But setting it let it work for now 
        if(u != null){ 
            credential.put(UMAuthenticationUtil.authenticatedUserKey, u); 
        } 
        return u; 
    } 
     
    private String getSerialNumber(X509Certificate userCert){ 
        X500Principal xp = userCert.getSubjectX500Principal(); 
        Map<String,String> oidMap = new HashMap<String,String>(); 
        //This is the OID for serialnumber as per std 
        oidMap.put("2.5.4.5", SERIAL_NUMBER); 
        String subjectName = xp.getName(X500Principal.RFC2253,oidMap); 
        LdapName name = null; 
        try { 
            name = new LdapName(subjectName); 
        } catch (InvalidNameException e) { 
            throw new RuntimeException(e); 
        } 
         
        for(Rdn rdn : name.getRdns()){ 
            String attr = rdn.getType(); 
            if(SERIAL_NUMBER.equals(attr)){ 
                return rdn.getValue().toString(); 
            } 
        } 
        return null; 
    } 
     
    private User findPrincipal(String serialNumber, DirectoryManager dm) { 
        PrincipalSearchFilter psf = new PrincipalSearchFilter(); 
        psf.setSpecificDomainName(UMConstants.DEFACL_DEF_DOMAIN); 
        psf.setCanonicalName(serialNumber);  
        psf.setRetrieveOnlyActive(); 
        try { 
            //If its canonical based search only prefer using dm.findPrincipal(canonical,domain) 
            //Using filter approach for more genric approach 
            List p = dm.findPrincipals(psf);  
            return (User) (p.isEmpty() ? null : p.get(0)); 
        } catch (UMException e) { 
            throw new RuntimeException("Error invoking UM",e); 
        } 
    } 
 
} 

Defining the component XML file for the directory service provider

Create a component XML file to deploy the CIR provider. A component XML file exists for each component and provides metadata about the component. For more information about the component XML file, see the Component XML Reference.

The following component.xml file is used for the CIR provider. Notice that the service name is CertIdentityResolver and the implementation class is com.adobe.livecycle.sample.CertIdentityResolver.

Defining the component XML file for the CIR provider

<component xmlns="http://adobe.com/idp/dsc/component/document"> 
      <component-id>com.adobe.livecycle.samples.authentication.CertIdentityResolverService</component-id> 
      <version>1.0</version>     
      <supports-export>false</supports-export>  
      <services> 
          <service name="CertIdentityResolver"> 
            <implementation-class>com.adobe.livecycle.sample.CertIdentityResolver</implementation-class> 
            <auto-deploy major-version="1" /> 
        </service> 
      </services> 
</component>

Register the CIR provider with User Management

Register the CIR provider with User Management by modifying an XML configuration file by using Administration Console. For information about modifying the configuration XML file, see the Importing and exporting the configuration file topic in LiveCycle Administration Help.

Once you export the XML configuration file, search for a node named AdobeDefaultCertificate. Under this node, add a node named DefaultConfig. Under the DefaultConfig node, add an entry for the identityResolver key. Specify the name of the service specified in the component XML file. In this example, the value CertIdentityResolver is specified.

The following example shows the modified XML configuration file.

<node name="AdobeDefaultCertificate"> 
       <map> 
           <entry key="enabled" value="true"/> 
           <entry key="visibleInUI" value="false"/> 
           <entry key="order" value="5"/> 
           <entry key="configured" value="true"/> 
           <entry key="allowMultipleConfigs" value="false"/> 
           <entry key="className" value="com.adobe.idp.um.provider.authentication.CertificateAuthProviderImpl"/> 
       </map> 
       <node name="DefaultConfig"> 
           <map> 
               <entry key="identityResolver" value="CertIdentityResolver"/> 
           </map> 
       </node>   
</node>
Note: After you modify the XML configuration file, ensure that you import it into LiveCycle.

Packaging the certificate identity resolver provider

Before deploying the CIR provider to LiveCycle, package your Eclipse project into a JAR file. Also, the component XML file and external JAR files must be located at the root of the JAR file.

The following illustration shows the Eclipse project’s content that is packaged into the CIR provider’s JAR file.

Package the CIR provider into a JAR file named CIRProviderSample-dsc.jar. In the previous diagram, notice that the .JAVA file is listed. Once packaged into a JAR file, the corresponding .CLASS file must also be specified. Without the .CLASS file, the CIR provider does not work.

Note: After you package the CIR provider into a JAR file, you can deploy the component to LiveCycle. (See Deploying your component.)
Note: You can also programmatically deploy a component. (See Programmatically Deploying Components.)

Deploying and testing the certificate identity resolver provider

After you package the certificate identity resolver provider, deploy and test it.

To deploy the CIR provider:

  1. Start Workbench.

  2. Log in to Workbench.

  3. Select Window > Show Views > Components. This action adds the Components view to Workbench.

  4. Right-click the Components icon and select Install Component.

  5. Select the CIRProviderSample-dsc.jar file through the file browser and click Open.

    Notice that there is a red square next to com.adobe.livecycle.samples.authentication.CertIdentityResolverService. Expand com.adobe.livecycle.samples.authentication.CertIdentityResolverService.

  6. Select Service Descriptors, and then right-click CertIdentityResolver and select Activate Service.

  7. Right-click com.adobe.livecycle.samples.authentication.CertIdentityResolverService and select Start Component. A green arrow appears next to the name if it succeeds. Notice that CertIdentityResolver is automatically deployed and has a green arrow next to it if it succeeds.

Now you can use a certificate that contains a user’s serial number to authenticate with LiveCycle. For example, assume that you have a .P12 certificate file that contains a serial number value of 123. You can create a local user and sets its canonical name to 123. Using the certificate, you can authenticate as that user.

Note: Ensure that you place the certificate that contains the users’s serial number in Trust Store. For information, see the Managing certificates and credentials topic in LiveCycle Administration Help.

// Ethnio survey code removed