CAC and Mutual Authentication

Introduction

Adobe® LiveCycle® Enterprise Suite 4 (ES4) provides support for Mutual Authentication to login into the LiveCycle servers. The following are supported:

  • All LC user interfaces, except WorkBench
  • Adobe Acrobat and Adobe Reader
  • Microsoft Office

In the case of authentication using CAC (Common Access Cards), the embedded certificates can be used like certificates in the Microsoft® Windows® Certificate store. When mutual authentication occurs and the certificate in CAC is selected, the client is authenticated.

LiveCycle support for Mutual Authentication

Mutual authentication support in LiveCycle is available for:

  • Opening a policy protected documents using Adobe Reader or Adobe Acrobat.
  • LiveCycle Web user interfaces. All end-user user interfaces and administrator user interfaces are supported.
  • Authentication via SharePoint Connector. The LiveCycle SharePoint Connector Web can be configured to authenticate via a system user certificate instead of a pre-configured username and password.
  • Indexing of Rights Management Protected documents in LiveCycle iFilter.
  • Rights Management Extensions for Microsoft® Office®.
Note:

Mutual Authentication is not supported for:

  • LiveCycle Java Client SDK
  • LiveCycle Workbench

Configuration

Application Server Configuration

Enabling mutual authentication depends on the application server used.

Follow the application server-specific guidelines to enable 2-way Mutual Authentication.

LiveCycle Server Configuration

To enable mutual authentication on the LiveCycle server, a custom UM AuthProvider SPI needs to be implemented and configured with a LiveCycle domain.

For details on now to create authentication providers, see Creating Authentication Providers.

The following is a sample of the Auth Provider SPI to enable Mutual Authentication:

package com.adobe.livecycle.usermanager.sslauthprovider;

import com.adobe.idp.um.spi.authentication.*;
import com.adobe.logging.AdobeLogger;
 
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import javax.security.auth.x500.X500Principal;
import javax.servlet.http.HttpServletRequest;
import java.security.cert.X509Certificate;
import java.util.*;
import org.apache.commons.codec.binary.Base64;
 
public class SSLMutualAuthProvider implements AuthProvider{
    private static AdobeLogger logger = AdobeLogger.getAdobeLogger(SSLMutualAuthProvider.class);
 
    public AuthResponse authenticate(Map credentials, List passedAuthConfigs) {
 
        ...
        //Extract the client certificate from the request
        X509Certificate[] certs = extractCertificate(request);
        if(certs == null || certs.length == 0){
            return null;
        }
 
        AuthResponse ar = new AuthResponseImpl();
    ar.setAuthStatus(AuthResponse.AUTH_SUCCESS);
        ar.setDomain(authConfigs.get(0).getDomainName()); //Assuming config is single domain and using its domainName
 
        Map<String,String> oidMap = new HashMap<String, String>();
        String name = certs[0].getSubjectX500Principal().getName();
        logger.info("Got Subject DN as "+name);
        LdapName ldapName = null;
        try{
            ldapName = new LdapName(name);
        }catch(InvalidNameException e){
            throw new RuntimeException(e);
        }
 
    //In this sample the CN of the Subject Name maps to user's loginid, however this can be changed to meet your requirements.
        for(Rdn rdn : ldapName.getRdns()){
            String type = rdn.getType();
            if("CN".equals(type)){
                String cn = (String) rdn.getValue();
                ar.setUsername(cn);
                return ar;
            }
        }
        return null;
    }
 
   private X509Certificate[] extractCertificate(HttpServletRequest request) {
        X509Certificate[] certs =  (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
        if(certs != null){
            logger.debug("No certificate found in the HTTP Header javax.servlet.request.X509Certificate");
            return certs;
        }
 
        //Check for certificate value passed in HTTP header which is the case with proxy
        String certDataInPemFormat = request.getHeader("SSL_CLIENT_CERT");
        if(certDataInPemFormat == null){
            logger.debug("No certificate found in the HTTP Header SSL_CLIENT_CERT ");
            return null;
        }
        String PREFIX = "-----BEGIN CERTIFICATE----- ";
        String SUFFIX = " -----END CERTIFICATE-----";
        int dataLength =  certDataInPemFormat.length();
        String encodedData = certDataInPemFormat.substring(PREFIX.length(), dataLength - SUFFIX.length() - 1);
 
        Certificate c = null;
        try {
            byte[] certData = Base64.decodeBase64(encodedData.getBytes("utf-8"));
            //Certificate factory would take care of removing the prefixes and suffixes
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            c = cf.generateCertificate(new ByteArrayInputStream(certData));
        } catch (CertificateException e) {
            throw new RuntimeException(e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return new X509Certificate[]{(X509Certificate) c};
    }
 
}

This Auth Provider needs to be included in a hybrid domain in LiveCycle. Users from that domain would then be enabled for Mutual Authentication.

After building the Auth Provider SPI DSC follow the steps described below to deploy and configure in the LiveCycle server:

  1. Deploy and start the Auth Provider SPI DSC using Workbench.

  2. Go to Home > Settings > User Management > Domain Management.

  3. Click on New Hybrid Domain.

  4. Add authentication.

    Select Custom from Authentication Provider list.

  5. Select the name of the SPI which is deployed in Step 1 above from the list of custom SPIs shown.

  6. Click Save.

To configure Rights Management follow the steps described below:

  1. In Admin UI, go to: Services > Rights Management > Configuration.

  2. Check and confirm the base URL matches the server certificate.

  3. Enable Extended Authentication.

    Note:

    Extended Authentication does not apply in the case of Rights Management Extension for Microsoft Office.

  4. Click Save.

  5. Restart the LiveCycle Server.

Note:

This Authentication SPI can also be used for creating the user Just in time.

SharePoint Connector Web part changes

For web part to access an SSL configured LiveCycle server, the following changes need to be made in the web.config file of SharePoint server:

To enable mutual authentication, replace the following:

<system.serviceModel>
    <bindings>
      ...
    </bindings>
    <client>
      ...
    </client>
  </system.serviceModel>

With:

<system.serviceModel>
    <behaviors>
        <endpointBehaviors>
          <behavior name="MutualSslBehavior">
            <clientCredentials>
              <clientCertificate storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" findValue="chetanm" />
            </clientCredentials>
          </behavior>
        </endpointBehaviors>
      </behaviors>
    <bindings>
      <basicHttpBinding>
        <binding name="ReaderExtensionsServiceSoapBinding" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:05:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="81920000"
            maxArrayLength="16384000" maxBytesPerRead="40960000" maxNameTableCharCount="16384" />
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Certificate" proxyCredentialType="None"
              realm="" />
          </security>
        </binding>
        <binding name="TaskManagerServiceSoapBinding" closeTimeout="00:01:00"
            openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:05:00"
            allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
            maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
            messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
            useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="81920000" maxArrayLength="16384000"
              maxBytesPerRead="40960000" maxNameTableCharCount="16384" />
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Certificate" proxyCredentialType="None"
              realm="" />
          </security>
        </binding>
        <binding name="TaskManagerQueryServiceSoapBinding" closeTimeout="00:01:00"
            openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:05:00"
            allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
            maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
            messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
            useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="81920000" maxArrayLength="16384000"
              maxBytesPerRead="40960000" maxNameTableCharCount="16384" />
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Certificate" proxyCredentialType="None"
              realm="" />
          </security>
        </binding>
        <binding name="FormsServiceSoapBinding" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:05:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="81920000"
            maxArrayLength="16384000" maxBytesPerRead="40960000" maxNameTableCharCount="16384" />
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Certificate" proxyCredentialType="None"
              realm="" />
          </security>
        </binding>
        <binding name="DirectoryManagerServiceSoapBinding" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:05:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="81920000"
            maxArrayLength="16384000" maxBytesPerRead="40960000" maxNameTableCharCount="16384" />
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Certificate" proxyCredentialType="None"
              realm="" />
          </security>
        </binding>
        <binding name="MSSharePointConfigServiceSoapBinding" closeTimeout="00:01:00"
        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:05:00"
         allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
         maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
         messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
         useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="81920000"
            maxArrayLength="16384000" maxBytesPerRead="40960000" maxNameTableCharCount="16384" />
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Certificate" proxyCredentialType="None"
              realm="" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://<AdobeLiveCycleServer>:<port>/soap/services/ReaderExtensionsService"
        binding="basicHttpBinding" bindingConfiguration="ReaderExtensionsServiceSoapBinding" behaviorConfiguration="MutualSslBehavior"
        contract="LiveCycleReaderExtensions.ReaderExtensionsService"
        name="ReaderExtensionsService" />
      <endpoint address="https://<AdobeLiveCycleServer>:<port>/soap/services/FormsService"
        binding="basicHttpBinding" bindingConfiguration="FormsServiceSoapBinding" behaviorConfiguration="MutualSslBehavior"
        contract="FormsService.FormsService" name="FormsService" />
      <endpoint address="https://<AdobeLiveCycleServer>:<port>/soap/services/TaskManagerService"
        binding="basicHttpBinding" bindingConfiguration="TaskManagerServiceSoapBinding" behaviorConfiguration="MutualSslBehavior"
        contract="TaskManagerService.TaskManagerService" name="TaskManagerService" />
      <endpoint address="https://<AdobeLiveCycleServer>:<port>/soap/services/TaskManagerQueryService"
        binding="basicHttpBinding" bindingConfiguration="TaskManagerQueryServiceSoapBinding" behaviorConfiguration="MutualSslBehavior"
        contract="TaskManagerQueryService.TaskManagerQueryService" name="TaskManagerQueryService" />
      <endpoint address="https://<alfresco-server>:<port>/soap/services/DirectoryManagerService"
        binding="basicHttpBinding" bindingConfiguration="DirectoryManagerServiceSoapBinding" behaviorConfiguration="MutualSslBehavior"
        contract="DirectoryManagerService.DirectoryManagerService" name="DirectoryManagerService" />
      <endpoint address="https://<AdobeLiveCycleServer>:<port>/soap/services/MSSharePointConfigService"
        binding="basicHttpBinding" bindingConfiguration="MSSharePointConfigServiceSoapBinding"
        contract="MSSharePointConfigService.MSSharePointConfigService" behaviorConfiguration="MutualSslBehavior"
        name="MSSharePointConfigService" />
    </client>
  </system.serviceModel>
The certificate specification sections needs to be changed according to the certificate and its location of installation.
<clientCertificate storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" findValue="<subject-name>" />

Follow the resources and instructions below, as necessary for your environment.

Resource

Instructions

In the sharepoint-site-Settings section of the LiveCycle settings page, specify <subject-name> (the subject name in the certificate) as User Name and check the Enable Https check box.

Note: Webpart assumes there is only one certificate with a specific subject name.

After installing the web part, make the changes to the web.config (as described above).

Note: During activation, if an Access denied error occurs, then run the powershell script available at http://support.microsoft.com/kb/2564009.

In case webpart is previously installed, first uninstall it using the script available here.

PDF iFilter Changes

Note:

The self-signed certificates are not supported. Use CA issued certificates for Mutual Authentication.

Changes for access to HTML Workspace through CAC authentication

For your users to be able to log in to HTML Workspace with Common Access Cards (CAC) certificates, you need to make the following change in the server: 

  1. Go to http://[server]:[port]/lc/libs/granite/security/content/useradmin.html and log in as admin.

  2. Tap Administrator. Edit User Settings page opens.

  3. Tap Create trustStore and set an access password for trustStore. For more information, see Add the IdP Certificate to the AEM TrustStore.

  4. Tap Create keyStore and set a password for keyStore. For more information, see Add the Service Provider key and certificate chain to the AEM keystore.

  5. Logout and try to access the workspace with port :8443 and you should be able to reach the workspace with CAC card.

 Adobe

Get help faster and easier

New user?

Adobe MAX 2024

Adobe MAX
The Creativity Conference

Oct 14–16 Miami Beach and online

Adobe MAX

The Creativity Conference

Oct 14–16 Miami Beach and online

Adobe MAX 2024

Adobe MAX
The Creativity Conference

Oct 14–16 Miami Beach and online

Adobe MAX

The Creativity Conference

Oct 14–16 Miami Beach and online