[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Pki-devel] [PATCH] Ticket#1028 Phase1:TPS rewrite: provide externalReg functionality



attached please find the Phase 1 code for
https://fedorahosted.org/pki/ticket/1028
 Ticket#1028 TPS rewrite: provide externalReg functionality

Due to a recent change of task priorities, I am to check in this feature in two phases (coming back to phase 2 at a later time). In this Phase 1, the code for this feature is in place, but may not be in the most optimal condition.
The goal for Phase 1 is to:

1. not break existing functionality (non ExternalReg -- which is default)
2. when ExternalReg is turned on, it works for the basic case (didn't
test for more complicated cases)... e.g. I don't know if say an existing
cert on the token is missing from the externalReg user record, whether
it will be removed or not.
3. it is not guaranteed to work with more complicated scenario
4. code has been run through and cleaned up in Eclipse

Later, for Phase 2:

1. really clean up and add bells and whistles (more error checkings, more efficient code,
proper logging, etc.)
2. test/cover all cases

Jack has already helped testing it with a real token with ExternalReg turned off (didn't seem to break the existing functionalities);
Jack has also helped testing it with a real token with ExternalReg turned on for simple enrollment/recovery

and Jack is going to review this Phase 1 code.  Thank you Jack!

Christina


>From 5398895ba1148f1ca9d53d080a9ba92c64c4ff6c Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu redhat com>
Date: Fri, 30 Jan 2015 10:36:45 -0800
Subject: [PATCH] Ticket#1028 Phase1:TPS rewrite: provide externalReg
 functionality

---
 .../dogtagpki/server/connector/IRemoteRequest.java |   4 +-
 base/server/cmsbundle/src/UserMessages.properties  |   2 +
 .../src/com/netscape/cmscore/dbs/DBRegistry.java   |   3 +-
 base/tps/shared/conf/CS.cfg.in                     | 475 ++++++++++++++++++
 .../src/org/dogtagpki/server/tps/TPSSession.java   |  10 +
 .../server/tps/cms/CARemoteRequestHandler.java     | 110 ++++-
 .../server/tps/cms/KRARemoteRequestHandler.java    |  31 +-
 .../dogtagpki/server/tps/dbs/ActivityDatabase.java |   1 +
 .../org/dogtagpki/server/tps/engine/TPSEngine.java |   1 +
 .../server/tps/main/ExternalRegAttrs.java          |  93 ++++
 .../server/tps/main/ExternalRegCertToRecover.java  |  54 +++
 .../server/tps/processor/TPSEnrollProcessor.java   | 530 +++++++++++++++++++--
 .../server/tps/processor/TPSProcessor.java         | 407 +++++++++++++---
 13 files changed, 1572 insertions(+), 149 deletions(-)
 create mode 100644 base/tps/src/org/dogtagpki/server/tps/main/ExternalRegAttrs.java
 create mode 100644 base/tps/src/org/dogtagpki/server/tps/main/ExternalRegCertToRecover.java

diff --git a/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java b/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java
index 24aa767d593ce6851d7d4c6edaa0133da9acfdcb..a383a4b0fac3b18014b1de51ac42d1d613071c2d 100644
--- a/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java
+++ b/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java
@@ -49,7 +49,7 @@ public interface IRemoteRequest {
     public static final String TKS_RESPONSE_SessionKey = "sessionKey";
     public static final String TKS_RESPONSE_EncSessionKey = "encSessionKey";
     public static final String TKS_RESPONSE_KEK_DesKey = "kek_wrapped_desKey";
-    public static final String TKS_RESPONSE_DRM_Trans_DesKey = "drm_trans_wrapped_desKey";
+    public static final String TKS_RESPONSE_DRM_Trans_DesKey = "drm_trans_desKey";
     public static final String TKS_RESPONSE_KeyCheck = "keycheck";
     public static final String TKS_RESPONSE_HostCryptogram = "hostCryptogram";
 
@@ -66,6 +66,8 @@ public interface IRemoteRequest {
     public static final String CA_ProfileId = "profileId";
     public static final String CA_ENROLL_screenname = "screenname";
     public static final String CA_ENROLL_publickey = "publickey";
+    public static final String CA_ENROLL_subjectdn = "subject";
+    public static final String CA_ENROLL_san_num = "req_san_entries";
     public static final String CA_RenewedCertificate = "renewedCertificate";
     public static final String CA_RENEWAL_SerialNum = "serial_num";
     public static final String CA_RENEWAL= "renewal";
diff --git a/base/server/cmsbundle/src/UserMessages.properties b/base/server/cmsbundle/src/UserMessages.properties
index 2dc1f268c844d742328c0c9a94c5625b1b5f264b..4861f2da556dd87147aa4840033078f4e7833350 100644
--- a/base/server/cmsbundle/src/UserMessages.properties
+++ b/base/server/cmsbundle/src/UserMessages.properties
@@ -1030,6 +1030,8 @@ CMS_PROFILE_INPUT_FILE_SIGNING_NAME=File Signing Input
 CMS_PROFILE_INPUT_FILE_SIGNING_TEXT=File Signing Input
 CMS_PROFILE_INPUT_FILE_SIGNING_URL=URL Of File Being Signed
 CMS_PROFILE_INPUT_FILE_SIGNING_TEXT=Text Being Signed
+CMS_PROFILE_INPUT_SUBJECT_ALT_NAME_EXT_NAME=Subject Alternative Name Extension Information
+CMS_PROFILE_INPUT_SUBJECT_ALT_NAME_EXT_TEXT=Subject Alternative Name Extension Information
 CMS_PROFILE_IMAGE=Image
 CMS_PROFILE_INPUT_IMAGE_NAME=Image
 CMS_PROFILE_INPUT_IMAGE_TEXT=Image
diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/DBRegistry.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/DBRegistry.java
index cd475cd56a8484b1844f06997e5712ac366f6cda..db2ce7af468bd6b58930a808138e09b6ae078634 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/DBRegistry.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/DBRegistry.java
@@ -460,7 +460,8 @@ public class DBRegistry implements IDBRegistry, ISubsystem {
             throw new EDBException(CMS.getLogMessage("CMS_DBS_MISSING_OBJECT_CLASS"));
         }
 
-        CMS.debug("createObject: attrs " + attrs);
+        // this generates way too many messages;
+        //CMS.debug("createObject: attrs " + attrs);
 
         attrs.remove("objectclass");
 
diff --git a/base/tps/shared/conf/CS.cfg.in b/base/tps/shared/conf/CS.cfg.in
index 52b3174f33704b92c6b66b6153e05a80b4abd6bc..e363ba3df69da5d94f927585504b2c04752379e9 100644
--- a/base/tps/shared/conf/CS.cfg.in
+++ b/base/tps/shared/conf/CS.cfg.in
@@ -51,8 +51,18 @@ auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred.extlogin=PASSWORD
 auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred.login=password
 auths.instance.ldap1.dnpattern=
 auths.instance.ldap1.ldapByteAttributes=
+auths.instance.ldap1.ldapStringAttributes._000=##############################################
+auths.instance.ldap1.ldapStringAttributes._001=# For isExternalReg
+auths.instance.ldap1.ldapStringAttributes._002=#   attributes will be available as
+auths.instance.ldap1.ldapStringAttributes._003=#       $<attribute>$
+auths.instance.ldap1.ldapStringAttributes._004=#   attributes example:
+auths.instance.ldap1.ldapStringAttributes._005=#mail,cn,uid,exec-edipi,firstname,lastname,exec-pcc,exec-mail,certsToAdd,tokenCUID,tokenType
+auths.instance.ldap1.attributes._006=################################# #############
 auths.instance.ldap1.ldapStringAttributes=mail,cn,uid
 auths.instance.ldap1.ldap.basedn=[LDAP_ROOT]
+auths.instance.ldap1.externalReg.certs.recoverAttributeName=certsToAdd
+auths.instance.ldap1.externalReg.cuidAttributeName=tokenCUID
+auths.instance.ldap1.externalReg.tokenTypeAttributeName=tokenType
 auths.instance.ldap1.ldap.maxConns=15
 auths.instance.ldap1.ldap.minConns=3
 auths.instance.ldap1.ldap.ldapauth.authtype=BasicAuth
@@ -118,6 +128,25 @@ debug.filename=[PKI_INSTANCE_PATH]/logs/[PKI_SUBSYSTEM_TYPE]/debug
 debug.hashkeytypes=
 debug.level=0
 debug.showcaller=false
+externalReg._000=#########################################
+externalReg._001=#External Registration
+externalReg._002=#    Design: http://pki.fedoraproject.org/wiki/TPS_-_New_Recovery_Option:_External_Registration_DS
+externalReg._003=#
+externalReg._004=# enable - is user external registration DB enabled?
+externalReg._005=# authId - auth id of the user external registration DB
+externalReg._006=# delegation.enable - is delegation enabled?
+externalReg._007=#
+externalReg._008=#
+externalReg._009=# format.loginRequest.enable - login required for format?
+externalReg._010=#                   1. requires no login to format
+externalReg._011=#                     or
+externalReg._012=#                   2. user record does not contain tokenType
+externalReg._013=#########################################
+externalReg.authId=ldap1
+externalReg.default.tokenType=externalRegAddToToken
+externalReg.delegation.enable=false
+externalReg.enable=false
+externalReg.format.loginRequest.enable=true
 failover.pod.enable=false
 general.applet_ext=ijc
 general.pwlength.min=16
@@ -221,6 +250,452 @@ multiroles.enable=true
 multiroles.false.groupEnforceList=Administrators,Auditors,Trusted Managers,Certificate Manager Agents,Registration Manager Agents,Data Recovery Manager Agents,Online Certificate Status Manager Agents,Token Key Service Manager Agents,Enterprise CA Administrators,Enterprise KRA Administrators,Enterprise OCSP Administrators,Enterprise RA Administrators,Enterprise TKS Administrators,Enterprise TPS Administrators,Security Domain Administrators,Subsystem Group,ClonedSubsystems
 multiroles.false.groupEnforceList=Administrators,Auditors,Trusted Managers,Certificate Manager Agents,Registration Manager Agents,Data Recovery Manager Agents,Online Certificate Status Manager Agents,Token Key Service Manager Agents,Enterprise CA Administrators,Enterprise KRA Adminstrators,Enterprise OCSP Administrators,Enterprise RA Administrators,Enterprise TKS Administrators,Enterprise TPS Administrators,Security Domain Administrators,Subsystem Group
 multiroles=true
+op.enroll.delegateIEtoken._000=#########################################
+op.enroll.delegateIEtoken._001=# Enrollment for externalReg 
+op.enroll.delegateIEtoken._002=#     ID, Encryption
+op.enroll.delegateIEtoken._003=#    where Encryption cert/keys are "recovered"
+op.enroll.delegateIEtoken._004=#    is controlled by registration user record
+op.enroll.delegateIEtoken._005=#########################################
+op.enroll.delegateIEtoken.auth.enable=true
+op.enroll.delegateIEtoken.auth.id=ldap1
+op.enroll.delegateIEtoken.cardmgr_instance=A0000000030000
+op.enroll.delegateIEtoken.issuerinfo.enable=true
+op.enroll.delegateIEtoken.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
+op enroll delegateIEtoken keyGen authentication SANpattern=$auth exec-edipi$ $auth exec-pcc$ EXAMPLE com
+op.enroll.delegateIEtoken.keyGen.authentication.ca.conn=ca1
+op.enroll.delegateIEtoken.keyGen.authentication.ca.profileId=caTokenUserDelegateAuthKeyEnrollment
+op.enroll.delegateIEtoken.keyGen.authentication.certAttrId=c3
+op.enroll.delegateIEtoken.keyGen.authentication.certId=C3
+op.enroll.delegateIEtoken.keyGen.authentication.cuid_label=$cuid$
+op.enroll.delegateIEtoken.keyGen.authentication.dnpattern=cn=$auth.firstname$.$auth.lastname$.$auth.exec-edipi$,e=$auth.mail$,o=TMS Org
+op.enroll.delegateIEtoken.keyGen.authentication.keySize=1024
+op.enroll.delegateIEtoken.keyGen.authentication.keyUsage=0
+op.enroll.delegateIEtoken.keyGen.authentication.keyUser=0
+op.enroll.delegateIEtoken.keyGen.authentication.label=authentication key for $userid$
+op.enroll.delegateIEtoken.keyGen.authentication.overwrite=true
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.decrypt=false
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.derive=false
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.encrypt=false
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.private=true
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.sensitive=true
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.sign=true
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.signRecover=true
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.token=true
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.unwrap=false
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.verify=false
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.verifyRecover=false
+op.enroll.delegateIEtoken.keyGen.authentication.private.keyCapabilities.wrap=false
+op.enroll.delegateIEtoken.keyGen.authentication.privateKeyAttrId=k6
+op.enroll.delegateIEtoken.keyGen.authentication.privateKeyNumber=6
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.decrypt=false
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.derive=false
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.encrypt=false
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.private=false
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.sensitive=false
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.sign=false
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.signRecover=false
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.token=true
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.unwrap=false
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.verify=true
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.verifyRecover=true
+op.enroll.delegateIEtoken.keyGen.authentication.public.keyCapabilities.wrap=false
+op.enroll.delegateIEtoken.keyGen.authentication.publicKeyAttrId=k7
+op.enroll.delegateIEtoken.keyGen.authentication.publicKeyNumber=7
+op.enroll.delegateIEtoken.keyGen.authentication.recovery.destroyed.revokeCert=false
+op.enroll.delegateIEtoken.keyGen.authentication.recovery.destroyed.revokeCert.reason=0
+op.enroll.delegateIEtoken.keyGen.authentication.recovery.destroyed.scheme=GenerateNewKey
+op.enroll.delegateIEtoken.keyGen.authentication.recovery.keyCompromise.revokeCert=false
+op.enroll.delegateIEtoken.keyGen.authentication.recovery.keyCompromise.revokeCert.reason=1
+op.enroll.delegateIEtoken.keyGen.authentication.recovery.keyCompromise.scheme=GenerateNewKey
+op.enroll.delegateIEtoken.keyGen.authentication.recovery.onHold.revokeCert=false
+op.enroll.delegateIEtoken.keyGen.authentication.recovery.onHold.revokeCert.reason=6
+op.enroll.delegateIEtoken.keyGen.authentication.recovery.onHold.scheme=GenerateNewKey
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.decrypt=true
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.derive=false
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.encrypt=false
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.private=true
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.sensitive=true
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.sign=false
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.signRecover=false
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.token=true
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.unwrap=true
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.verify=false
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.verifyRecover=false
+op.enroll.delegateIEtoken.keyGen.encryption.private.keyCapabilities.wrap=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.decrypt=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.derive=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.encrypt=true
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.private=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.sensitive=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.sign=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.signRecover=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.token=true
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.unwrap=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.verify=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.verifyRecover=false
+op.enroll.delegateIEtoken.keyGen.encryption.public.keyCapabilities.wrap=true
+op.enroll.delegateIEtoken.keyGen.encryption.serverKeygen.archive=true
+op.enroll.delegateIEtoken.keyGen.encryption.serverKeygen.drm.conn=kra1
+op.enroll.delegateIEtoken.keyGen.encryption.serverKeygen.enable=true
+op.enroll.delegateIEtoken.keyGen.keyType.num=1
+op.enroll.delegateIEtoken.keyGen.keyType.value.0=authentication
+op.enroll.delegateIEtoken.keyGen.recovery.destroyed.keyType.num=1
+op.enroll.delegateIEtoken.keyGen.recovery.destroyed.keyType.value.0=authentication
+op.enroll.delegateIEtoken.keyGen.recovery.keyCompromise.keyType.num=1
+op.enroll.delegateIEtoken.keyGen.recovery.keyCompromise.keyType.value.0=authentication
+op.enroll.delegateIEtoken.keyGen.recovery.onHold.keyType.num=1
+op.enroll.delegateIEtoken.keyGen.recovery.onHold.keyType.value.0=authentication
+op.enroll.delegateIEtoken.keyGen.tokenName=$auth.cn$
+op.enroll.delegateIEtoken.loginRequest.enable=true
+op.enroll.delegateIEtoken.pinReset.enable=true
+op.enroll.delegateIEtoken.pinReset.pin.maxLen=10
+op.enroll.delegateIEtoken.pinReset.pin.maxRetries=127
+op.enroll.delegateIEtoken.pinReset.pin.minLen=4
+op.enroll.delegateIEtoken.pkcs11obj.compress.enable=true
+op.enroll.delegateIEtoken.pkcs11obj.enable=true
+op.enroll.delegateIEtoken.renewal._000=#########################################
+op.enroll.delegateIEtoken.renewal._001=# Token Renewal.
+op.enroll.delegateIEtoken.renewal._002=#
+op.enroll.delegateIEtoken.renewal._003=# For each token in TPS UI, set the
+op.enroll.delegateIEtoken.renewal._004=# following to trigger renewal
+op.enroll.delegateIEtoken.renewal._005=# operations:
+op.enroll.delegateIEtoken.renewal._006=#
+op.enroll.delegateIEtoken.renewal._007=#     RENEW=YES
+op.enroll.delegateIEtoken.renewal._008=#
+op.enroll.delegateIEtoken.renewal._009=# Optional grace period enforcement
+op.enroll.delegateIEtoken.renewal._010=# must coincide exactly with what
+op.enroll.delegateIEtoken.renewal._011=# the CA enforces.
+op.enroll.delegateIEtoken.renewal._012=#
+op.enroll.delegateIEtoken.renewal._013=# In case of renewal, encryption certId
+op.enroll.delegateIEtoken.renewal._014=# values are for completeness only, server
+op.enroll.delegateIEtoken.renewal._015=# code calculates actual values used.
+op.enroll.delegateIEtoken.renewal._016=#
+op.enroll.delegateIEtoken.renewal._017=#########################################
+op.enroll.delegateIEtoken.renewal.authentication.ca.conn=ca1
+op.enroll.delegateIEtoken.renewal.authentication.ca.profileId=caTokenUserAuthKeyRenewal
+op.enroll.delegateIEtoken.renewal.authentication.certAttrId=c3
+op.enroll.delegateIEtoken.renewal.authentication.certId=C3
+op.enroll.delegateIEtoken.renewal.authentication.enable=true
+op.enroll.delegateIEtoken.renewal.authentication.gracePeriod.after=30
+op.enroll.delegateIEtoken.renewal.authentication.gracePeriod.before=30
+op.enroll.delegateIEtoken.renewal.authentication.gracePeriod.enable=false
+op.enroll.delegateIEtoken.renewal.keyType.num=1
+op.enroll.delegateIEtoken.renewal.keyType.value.0=authentication
+op.enroll.delegateIEtoken.temporaryToken.tokenType=delegateIEtokenTemporary
+op.enroll.delegateIEtoken.tks.conn=tks1
+op.enroll.delegateIEtoken.update.applet.directory=/usr/share/pki/tps/applets
+op.enroll.delegateIEtoken.update.applet.emptyToken.enable=true
+op.enroll.delegateIEtoken.update.applet.enable=true
+op.enroll.delegateIEtoken.update.applet.encryption=true
+op.enroll.delegateIEtoken.update.applet.requiredVersion=1.4.4d40a449
+op.enroll.delegateIEtoken.update.symmetricKeys.enable=false
+op.enroll.delegateIEtoken.update.symmetricKeys.requiredVersion=1
+op.format.delegateIEtoken.auth.enable=true
+op.format.delegateIEtoken.auth.id=ldap3
+op.format.delegateIEtoken.ca.conn=ca1
+op.format.delegateIEtoken.cardmgr_instance=A0000000030000
+op.format.delegateIEtoken.issuerinfo.enable=true
+op.format.delegateIEtoken.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
+op.format.delegateIEtoken.loginRequest.enable=true
+op.format.delegateIEtoken.revokeCert=false
+op.format.delegateIEtoken.tks.conn=tks1
+op.format.delegateIEtoken.update.applet.directory=/usr/share/pki/tps/applets
+op.format.delegateIEtoken.update.applet.emptyToken.enable=true
+op.format.delegateIEtoken.update.applet.encryption=true
+op.format.delegateIEtoken.update.applet.requiredVersion=1.4.4d40a449
+op.format.delegateIEtoken.update.symmetricKeys.enable=false
+op.format.delegateIEtoken.update.symmetricKeys.requiredVersion=1
+op.enroll.delegateISEtoken._000=#########################################
+op.enroll.delegateISEtoken._001=# Enrollment for externalReg 
+op.enroll.delegateISEtoken._002=#     ID, Signing, Encryption
+op.enroll.delegateISEtoken._003=#    where Encryption cert/keys is "recovered" 
+op.enroll.delegateISEtoken._004=#    is controlled by registration user record
+op.enroll.delegateISEtoken._005=#########################################
+op.enroll.delegateISEtoken.auth.enable=true
+op.enroll.delegateISEtoken.auth.id=ldap1
+op.enroll.delegateISEtoken.cardmgr_instance=A0000000030000
+op.enroll.delegateISEtoken.issuerinfo.enable=true
+op.enroll.delegateISEtoken.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
+op enroll delegateISEtoken keyGen authentication SANpattern=$auth exec-edipi$ $auth exec-pcc$ EXAMPLE com
+op.enroll.delegateISEtoken.keyGen.authentication.ca.conn=ca1
+op.enroll.delegateISEtoken.keyGen.authentication.ca.profileId=caTokenUserDelegateAuthKeyEnrollment
+op.enroll.delegateISEtoken.keyGen.authentication.certAttrId=c3
+op.enroll.delegateISEtoken.keyGen.authentication.certId=C3
+op.enroll.delegateISEtoken.keyGen.authentication.cuid_label=$cuid$
+op.enroll.delegateISEtoken.keyGen.authentication.dnpattern=cn=$auth.firstname$.$auth.lastname$.$auth.exec-edipi$,e=$auth.mail$,o=TMS Org
+op.enroll.delegateISEtoken.keyGen.authentication.keySize=1024
+op.enroll.delegateISEtoken.keyGen.authentication.keyUsage=0
+op.enroll.delegateISEtoken.keyGen.authentication.keyUser=0
+op.enroll.delegateISEtoken.keyGen.authentication.label=authentication key for $userid$
+op.enroll.delegateISEtoken.keyGen.authentication.overwrite=true
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.decrypt=false
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.derive=false
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.encrypt=false
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.private=true
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.sensitive=true
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.sign=true
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.signRecover=true
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.token=true
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.unwrap=false
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.verify=false
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.verifyRecover=false
+op.enroll.delegateISEtoken.keyGen.authentication.private.keyCapabilities.wrap=false
+op.enroll.delegateISEtoken.keyGen.authentication.privateKeyAttrId=k6
+op.enroll.delegateISEtoken.keyGen.authentication.privateKeyNumber=6
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.decrypt=false
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.derive=false
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.encrypt=false
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.private=false
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.sensitive=false
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.sign=false
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.signRecover=false
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.token=true
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.unwrap=false
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.verify=true
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.verifyRecover=true
+op.enroll.delegateISEtoken.keyGen.authentication.public.keyCapabilities.wrap=false
+op.enroll.delegateISEtoken.keyGen.authentication.publicKeyAttrId=k7
+op.enroll.delegateISEtoken.keyGen.authentication.publicKeyNumber=7
+op.enroll.delegateISEtoken.keyGen.authentication.recovery.destroyed.revokeCert=false
+op.enroll.delegateISEtoken.keyGen.authentication.recovery.destroyed.revokeCert.reason=0
+op.enroll.delegateISEtoken.keyGen.authentication.recovery.destroyed.scheme=GenerateNewKey
+op.enroll.delegateISEtoken.keyGen.authentication.recovery.keyCompromise.revokeCert=false
+op.enroll.delegateISEtoken.keyGen.authentication.recovery.keyCompromise.revokeCert.reason=1
+op.enroll.delegateISEtoken.keyGen.authentication.recovery.keyCompromise.scheme=GenerateNewKey
+op.enroll.delegateISEtoken.keyGen.authentication.recovery.onHold.revokeCert=false
+op.enroll.delegateISEtoken.keyGen.authentication.recovery.onHold.revokeCert.reason=6
+op.enroll.delegateISEtoken.keyGen.authentication.recovery.onHold.scheme=GenerateNewKey
+op.enroll.delegateISEtoken.keyGen.encryption.SANpattern=$auth.mail$,$auth exec-edipi$ $auth exec-pcc$ EXAMPLE com
+op.enroll.delegateISEtoken.keyGen.encryption._000=#########################################
+op.enroll.delegateISEtoken.keyGen.encryption._001=# encryption cert/keys are "recovered" for this profile
+op.enroll.delegateISEtoken.keyGen.encryption._002=# controlled from User Registartion db
+op.enroll.delegateISEtoken.keyGen.encryption._003=#########################################
+op.enroll.delegateISEtoken.keyGen.encryption.ca.conn=ca1
+op.enroll.delegateISEtoken.keyGen.encryption.ca.profileId=caTokenUserAuthenticationKeyEnrollment
+op.enroll.delegateISEtoken.keyGen.encryption.certAttrId=c2
+op.enroll.delegateISEtoken.keyGen.encryption.certId=C2
+op.enroll.delegateISEtoken.keyGen.encryption.cuid_label=$cuid$
+op.enroll.delegateISEtoken.keyGen.encryption.dnpattern=cn=$auth.firstname$.$auth.lastname$.$auth.exec-edipi$,e=$auth.mail$,o=TMS Org
+op.enroll.delegateISEtoken.keyGen.encryption.keySize=1024
+op.enroll.delegateISEtoken.keyGen.encryption.keyUsage=0
+op.enroll.delegateISEtoken.keyGen.encryption.keyUser=0
+op.enroll.delegateISEtoken.keyGen.encryption.label=encryption key for $userid$
+op.enroll.delegateISEtoken.keyGen.encryption.overwrite=true
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.decrypt=true
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.derive=false
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.encrypt=false
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.private=true
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.sensitive=true
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.sign=false
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.signRecover=false
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.token=true
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.unwrap=true
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.verify=false
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.verifyRecover=false
+op.enroll.delegateISEtoken.keyGen.encryption.private.keyCapabilities.wrap=false
+op.enroll.delegateISEtoken.keyGen.encryption.privateKeyAttrId=k4
+op.enroll.delegateISEtoken.keyGen.encryption.privateKeyNumber=4
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.decrypt=false
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.derive=false
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.encrypt=true
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.private=false
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.sensitive=false
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.sign=false
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.signRecover=false
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.token=true
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.unwrap=false
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.verify=false
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.verifyRecover=false
+op.enroll.delegateISEtoken.keyGen.encryption.public.keyCapabilities.wrap=true
+op.enroll.delegateISEtoken.keyGen.encryption.publicKeyAttrId=k5
+op.enroll.delegateISEtoken.keyGen.encryption.publicKeyNumber=5
+op.enroll.delegateISEtoken.keyGen.encryption.recovery.destroyed.revokeCert=false
+op.enroll.delegateISEtoken.keyGen.encryption.recovery.destroyed.revokeCert.reason=0
+op.enroll.delegateISEtoken.keyGen.encryption.recovery.destroyed.scheme=RecoverLast
+op.enroll.delegateISEtoken.keyGen.encryption.recovery.keyCompromise.revokeCert=false
+op.enroll.delegateISEtoken.keyGen.encryption.recovery.keyCompromise.revokeCert.reason=1
+op.enroll.delegateISEtoken.keyGen.encryption.recovery.keyCompromise.scheme=GenerateNewKey
+op.enroll.delegateISEtoken.keyGen.encryption.recovery.onHold.revokeCert=false
+op.enroll.delegateISEtoken.keyGen.encryption.recovery.onHold.revokeCert.reason=6
+op.enroll.delegateISEtoken.keyGen.encryption.recovery.onHold.scheme=GenerateNewKey
+op.enroll.delegateISEtoken.keyGen.encryption.serverKeygen.archive=true
+op.enroll.delegateISEtoken.keyGen.encryption.serverKeygen.drm.conn=kra1
+op.enroll.delegateISEtoken.keyGen.encryption.serverKeygen.enable=true
+op.enroll.delegateISEtoken.keyGen.keyType.num=2
+op.enroll.delegateISEtoken.keyGen.keyType.value.0=signing
+op.enroll.delegateISEtoken.keyGen.keyType.value.1=authentication
+op.enroll.delegateISEtoken.keyGen.recovery.destroyed.keyType.num=2
+op.enroll.delegateISEtoken.keyGen.recovery.destroyed.keyType.value.0=signing
+op.enroll.delegateISEtoken.keyGen.recovery.destroyed.keyType.value.1=authentication
+op.enroll.delegateISEtoken.keyGen.recovery.keyCompromise.keyType.num=2
+op.enroll.delegateISEtoken.keyGen.recovery.keyCompromise.keyType.value.0=signing
+op.enroll.delegateISEtoken.keyGen.recovery.keyCompromise.keyType.value.1=authentication
+op.enroll.delegateISEtoken.keyGen.recovery.onHold.keyType.num=2
+op.enroll.delegateISEtoken.keyGen.recovery.onHold.keyType.value.0=signing
+op.enroll.delegateISEtoken.keyGen.recovery.onHold.keyType.value.1=authentication
+op.enroll.delegateISEtoken.keyGen.signing.SANpattern=$auth.exec-mail$
+op.enroll.delegateISEtoken.keyGen.signing.ca.conn=ca1
+op.enroll.delegateISEtoken.keyGen.signing.ca.profileId=caTokenUserDelegateSigningKeyEnrollment
+op.enroll.delegateISEtoken.keyGen.signing.certAttrId=c1
+op.enroll.delegateISEtoken.keyGen.signing.certId=C1
+op.enroll.delegateISEtoken.keyGen.signing.cuid_label=$cuid$
+op.enroll.delegateISEtoken.keyGen.signing.dnpattern=cn=$auth.firstname$.$auth.lastname$.$auth.exec-edipi$,e=$auth.mail$,o=TMS Org
+op.enroll.delegateISEtoken.keyGen.signing.keySize=1024
+op.enroll.delegateISEtoken.keyGen.signing.keyUsage=0
+op.enroll.delegateISEtoken.keyGen.signing.keyUser=0
+op.enroll.delegateISEtoken.keyGen.signing.label=signing key for $userid$
+op.enroll.delegateISEtoken.keyGen.signing.overwrite=true
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.decrypt=false
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.derive=false
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.encrypt=false
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.private=true
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.sensitive=true
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.sign=true
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.signRecover=true
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.token=true
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.unwrap=false
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.verify=false
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.verifyRecover=false
+op.enroll.delegateISEtoken.keyGen.signing.private.keyCapabilities.wrap=false
+op.enroll.delegateISEtoken.keyGen.signing.privateKeyAttrId=k2
+op.enroll.delegateISEtoken.keyGen.signing.privateKeyNumber=2
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.decrypt=false
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.derive=false
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.encrypt=false
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.private=false
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.sensitive=false
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.sign=false
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.signRecover=false
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.token=true
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.unwrap=false
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.verify=true
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.verifyRecover=true
+op.enroll.delegateISEtoken.keyGen.signing.public.keyCapabilities.wrap=false
+op.enroll.delegateISEtoken.keyGen.signing.publicKeyAttrId=k3
+op.enroll.delegateISEtoken.keyGen.signing.publicKeyNumber=3
+op.enroll.delegateISEtoken.keyGen.signing.recovery.destroyed.revokeCert=false
+op.enroll.delegateISEtoken.keyGen.signing.recovery.destroyed.revokeCert.reason=0
+op.enroll.delegateISEtoken.keyGen.signing.recovery.destroyed.scheme=GenerateNewKey
+op.enroll.delegateISEtoken.keyGen.signing.recovery.keyCompromise.revokeCert=false
+op.enroll.delegateISEtoken.keyGen.signing.recovery.keyCompromise.revokeCert.reason=1
+op.enroll.delegateISEtoken.keyGen.signing.recovery.keyCompromise.scheme=GenerateNewKey
+op.enroll.delegateISEtoken.keyGen.signing.recovery.onHold.revokeCert=false
+op.enroll.delegateISEtoken.keyGen.signing.recovery.onHold.revokeCert.reason=6
+op.enroll.delegateISEtoken.keyGen.signing.recovery.onHold.scheme=GenerateNewKey
+op.enroll.delegateISEtoken.keyGen.tokenName=$auth.cn$
+op.enroll.delegateISEtoken.loginRequest.enable=true
+op.enroll.delegateISEtoken.pinReset.enable=true
+op.enroll.delegateISEtoken.pinReset.pin.maxLen=10
+op.enroll.delegateISEtoken.pinReset.pin.maxRetries=127
+op.enroll.delegateISEtoken.pinReset.pin.minLen=4
+op.enroll.delegateISEtoken.pkcs11obj.compress.enable=true
+op.enroll.delegateISEtoken.pkcs11obj.enable=true
+op.enroll.delegateISEtoken.renewal._000=#########################################
+op.enroll.delegateISEtoken.renewal._001=# Token Renewal.
+op.enroll.delegateISEtoken.renewal._002=#
+op.enroll.delegateISEtoken.renewal._003=# For each token in TPS UI, set the
+op.enroll.delegateISEtoken.renewal._004=# following to trigger renewal
+op.enroll.delegateISEtoken.renewal._005=# operations:
+op.enroll.delegateISEtoken.renewal._006=#
+op.enroll.delegateISEtoken.renewal._007=#     RENEW=YES
+op.enroll.delegateISEtoken.renewal._008=#
+op.enroll.delegateISEtoken.renewal._009=# Optional grace period enforcement
+op.enroll.delegateISEtoken.renewal._010=# must coincide exactly with what
+op.enroll.delegateISEtoken.renewal._011=# the CA enforces.
+op.enroll.delegateISEtoken.renewal._012=#
+op.enroll.delegateISEtoken.renewal._013=# In case of renewal, encryption certId
+op.enroll.delegateISEtoken.renewal._014=# values are for completeness only, server
+op.enroll.delegateISEtoken.renewal._015=# code calculates actual values used.
+op.enroll.delegateISEtoken.renewal._016=#
+op.enroll.delegateISEtoken.renewal._017=#########################################
+op.enroll.delegateISEtoken.renewal.authentication.ca.conn=ca1
+op.enroll.delegateISEtoken.renewal.authentication.ca.profileId=caTokenUserDelegateAuthKeyRenewal
+op.enroll.delegateISEtoken.renewal.authentication.certAttrId=c3
+op.enroll.delegateISEtoken.renewal.authentication.certId=C3
+op.enroll.delegateISEtoken.renewal.authentication.enable=true
+op.enroll.delegateISEtoken.renewal.authentication.gracePeriod.after=30
+op.enroll.delegateISEtoken.renewal.authentication.gracePeriod.before=30
+op.enroll.delegateISEtoken.renewal.authentication.gracePeriod.enable=false
+op.enroll.delegateISEtoken.renewal.keyType.num=2
+op.enroll.delegateISEtoken.renewal.keyType.value.0=signing
+op.enroll.delegateISEtoken.renewal.keyType.value.1=authentication
+op.enroll.delegateISEtoken.renewal.signing.ca.conn=ca1
+op.enroll.delegateISEtoken.renewal.signing.ca.profileId=caTokenUserSigningKeyRenewal
+op.enroll.delegateISEtoken.renewal.signing.certAttrId=c1
+op.enroll.delegateISEtoken.renewal.signing.certId=C1
+op.enroll.delegateISEtoken.renewal.signing.enable=true
+op.enroll.delegateISEtoken.renewal.signing.gracePeriod.after=30
+op.enroll.delegateISEtoken.renewal.signing.gracePeriod.before=30
+op.enroll.delegateISEtoken.renewal.signing.gracePeriod.enable=false
+op.enroll.delegateISEtoken.temporaryToken.tokenType=delegateISEtokenTemporary
+op.enroll.delegateISEtoken.tks.conn=tks1
+op.enroll.delegateISEtoken.update.applet.directory=/usr/share/pki/tps/applets
+op.enroll.delegateISEtoken.update.applet.emptyToken.enable=true
+op.enroll.delegateISEtoken.update.applet.enable=true
+op.enroll.delegateISEtoken.update.applet.encryption=true
+op.enroll.delegateISEtoken.update.applet.requiredVersion=1.4.4d40a449
+op.enroll.delegateISEtoken.update.symmetricKeys.enable=false
+op.enroll.delegateISEtoken.update.symmetricKeys.requiredVersion=1
+op.enroll.externalRegAddToToken._000=#########################################
+op.enroll.externalRegAddToToken._001=# for externalReg recovering certs/keys only
+op.enroll.externalRegAddToToken._002=#########################################
+op.enroll.externalRegAddToToken.auth.enable=true
+op.enroll.externalRegAddToToken.auth.id=ldap1
+op.enroll.externalRegAddToToken.cardmgr_instance=A0000000030000
+op.enroll.externalRegAddToToken.issuerinfo.enable=true
+op.enroll.externalRegAddToToken.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.decrypt=true
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.derive=false
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.encrypt=false
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.private=true
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.sensitive=true
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.sign=false
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.signRecover=false
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.token=true
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.unwrap=true
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.verify=false
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.verifyRecover=false
+op.enroll.externalRegAddToToken.keyGen.encryption.private.keyCapabilities.wrap=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.decrypt=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.derive=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.encrypt=true
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.private=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.sensitive=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.sign=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.signRecover=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.token=true
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.unwrap=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.verify=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.verifyRecover=false
+op.enroll.externalRegAddToToken.keyGen.encryption.public.keyCapabilities.wrap=true
+op.enroll.externalRegAddToToken.keyGen.encryption.recovery.destroyed.revokeCert=false
+op.enroll.externalRegAddToToken.keyGen.encryption.recovery.keyCompromise.revokeCert=false
+op.enroll.externalRegAddToToken.keyGen.encryption.recovery.onHold.revokeCert=false
+op.enroll.externalRegAddToToken.keyGen.signing.recovery.destroyed.revokeCert=false
+op.enroll.externalRegAddToToken.keyGen.signing.recovery.keyCompromise.revokeCert=false
+op.enroll.externalRegAddToToken.keyGen.signing.recovery.onHold.revokeCert=false
+op.enroll.externalRegAddToToken.keyGen.tokenName=$auth.cn$
+op.enroll.externalRegAddToToken.loginRequest.enable=true
+op.enroll.externalRegAddToToken.pkcs11obj.compress.enable=true
+op.enroll.externalRegAddToToken.pkcs11obj.enable=true
+op.enroll.externalRegAddToToken.tks.conn=tks1
+op.enroll.externalRegAddToToken.update.applet.directory=/usr/share/pki/tps/applets
+op.enroll.externalRegAddToToken.update.applet.emptyToken.enable=true
+op.enroll.externalRegAddToToken.update.applet.enable=false
+op.enroll.externalRegAddToToken.update.applet.encryption=true
+op.enroll.externalRegAddToToken.update.applet.requiredVersion=1.4.4d40a449
+op.enroll.externalRegAddToToken.update.symmetricKeys.enable=false
+op.enroll.externalRegAddToToken.update.symmetricKeys.requiredVersion=1
+op.format.externalRegAddToToken.auth.enable=true
+op.format.externalRegAddToToken.cardmgr_instance=A0000000030000
+op.format.externalRegAddToToken.issuerinfo.enable=true
+op.format.externalRegAddToToken.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
+op.format.externalRegAddToToken.update.applet.directory=/usr/share/pki/tps/applets
+op.format.externalRegAddToToken.update.applet.emptyToken.enable=true
+op.format.externalRegAddToToken.update.applet.encryption=true
+op.format.externalRegAddToToken.update.applet.requiredVersion=1.4.4d40a449
+op.format.externalRegAddToToken.update.symmetricKeys.enable=true
+op.format.externalRegAddToToken.update.symmetricKeys.requiredVersion=2
 op.enroll._000=#########################################
 op.enroll._001=# Default Operations
 op.enroll._002=#
diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSSession.java b/base/tps/src/org/dogtagpki/server/tps/TPSSession.java
index 4a175e6980ef26416b033ad138eb53d74f61db4a..507a5d8e3d27d4414a688d3506dddcfc543269e1 100644
--- a/base/tps/src/org/dogtagpki/server/tps/TPSSession.java
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSSession.java
@@ -20,6 +20,7 @@ package org.dogtagpki.server.tps;
 import java.io.IOException;
 
 import org.dogtagpki.server.tps.dbs.TokenRecord;
+import org.dogtagpki.server.tps.main.ExternalRegAttrs;
 import org.dogtagpki.server.tps.processor.TPSEnrollProcessor;
 import org.dogtagpki.server.tps.processor.TPSPinResetProcessor;
 import org.dogtagpki.server.tps.processor.TPSProcessor;
@@ -37,6 +38,8 @@ public class TPSSession {
     private String ipAddress; /* remote IP */
     private TokenRecord tokenRecord;
 
+    private ExternalRegAttrs extRegAttrs;
+
     public TPSSession(TPSConnection conn, String ip) {
 
         if (conn == null) {
@@ -171,4 +174,11 @@ public class TPSSession {
         this.ipAddress = ipAddress;
     }
 
+    public void setExternalRegAttrs(ExternalRegAttrs erAttrs) {
+        this.extRegAttrs = erAttrs;
+    }
+
+    public ExternalRegAttrs getExternalRegAttrs() {
+        return extRegAttrs;
+    }
 }
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java
index 5851d2f696f1e03c59c8b4c5dd3718c90ca1956d..5e2bfc724bcb469173e6451bfd9839c051ff33b5 100644
--- a/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java
@@ -77,6 +77,21 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
             String tokenType,
             String keyType)
             throws EBaseException {
+        return enrollCertificate(pubKeybuf, uid, null /*subjectdn*/,
+                0/*sanNum*/, null /*urlSANext*/,
+                cuid, tokenType, keyType);
+    }
+
+    public CAEnrollCertResponse enrollCertificate(
+            TPSBuffer pubKeybuf,
+            String uid,
+            String subjectdn,
+            int sanNum,
+            String urlSANext,
+            String cuid,
+            String tokenType,
+            String keyType)
+            throws EBaseException {
 
         CMS.debug("CARemoteRequestHandler: enrollCertificate(): begins.");
         if (pubKeybuf == null || uid == null || cuid == null) {
@@ -101,18 +116,82 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
             CMS.debug("CARemoteRequestHandler: enrollCertificate(): uriEncode of pubkey failed: " + e);
             throw new EBaseException("CARemoteRequestHandler: enrollCertificate(): uriEncode of pubkey failed: " + e);
         }
+        String sendMsg = null;
+        if (subjectdn == null)
+            CMS.debug("CARemoteRequestHandler: enrollCertificate():subjectdn null");
+        if (sanNum == 0)
+            CMS.debug("CARemoteRequestHandler: enrollCertificate():sanNum 0");
+        if (subjectdn == null && sanNum == 0) {
+            sendMsg = IRemoteRequest.GET_XML + "=" +
+                    true +
+                    "&" + IRemoteRequest.TOKEN_CUID + "=" +
+                    cuid +
+                    "&" + IRemoteRequest.CA_ENROLL_screenname + "=" +
+                    uid +
+                    "&" + IRemoteRequest.CA_ENROLL_publickey + "=" +
+                    encodedPubKey +
+                    "&" + IRemoteRequest.CA_ProfileId + "=" +
+                    profileId;
+        } else {
+            CMS.debug("CARemoteRequestHandler: enrollCertificate(): before send() with subjectdn and/or url_SAN_ext");
+            if (subjectdn != null && sanNum == 0) {
+                try {
+                    String urlSubjectdn = Util.uriEncode(subjectdn);
+                    sendMsg = IRemoteRequest.GET_XML + "=" +
+                            true +
+                            "&" + IRemoteRequest.TOKEN_CUID + "=" +
+                            cuid +
+                            "&" + IRemoteRequest.CA_ENROLL_screenname + "=" +
+                            uid +
+                            "&" + IRemoteRequest.CA_ENROLL_publickey + "=" +
+                            encodedPubKey +
+                            "&" + IRemoteRequest.CA_ProfileId + "=" +
+                            profileId +
+                            "&" + IRemoteRequest.CA_ENROLL_subjectdn + "=" +
+                            urlSubjectdn;
+                } catch (Exception e) {
+                    CMS.debug("CARemoteRequestHandler: enrollCertificate(): uriEncode of pubkey failed: " + e);
+                    throw new EBaseException(
+                            "CARemoteRequestHandler: enrollCertificate(): uriEncode of subjectdn failed: " + e);
+                }
+            } else if (subjectdn == null && sanNum != 0) {
+                sendMsg = IRemoteRequest.GET_XML + "=" +
+                        true +
+                        "&" + IRemoteRequest.TOKEN_CUID + "=" +
+                        cuid +
+                        "&" + IRemoteRequest.CA_ENROLL_screenname + "=" +
+                        uid +
+                        "&" + IRemoteRequest.CA_ENROLL_publickey + "=" +
+                        encodedPubKey +
+                        "&" + IRemoteRequest.CA_ProfileId + "=" +
+                        profileId +
+                        "&" + urlSANext;
+            } else if (subjectdn != null && sanNum != 0) {
+                try {
+                    String urlSubjectdn = Util.uriEncode(subjectdn);
+                    sendMsg = IRemoteRequest.GET_XML + "=" +
+                            true +
+                            "&" + IRemoteRequest.TOKEN_CUID + "=" +
+                            cuid +
+                            "&" + IRemoteRequest.CA_ENROLL_screenname + "=" +
+                            uid +
+                            "&" + IRemoteRequest.CA_ENROLL_publickey + "=" +
+                            encodedPubKey +
+                            "&" + IRemoteRequest.CA_ProfileId + "=" +
+                            profileId +
+                            "&" + IRemoteRequest.CA_ENROLL_subjectdn + "=" +
+                            urlSubjectdn +
+                            "&" + urlSANext;
+                } catch (Exception e) {
+                    CMS.debug("CARemoteRequestHandler: enrollCertificate(): uriEncode of pubkey failed: " + e);
+                    throw new EBaseException(
+                            "CARemoteRequestHandler: enrollCertificate(): uriEncode of subjectdn failed: " + e);
+                }
+            }
+        }
+        CMS.debug("CARemoteRequestHandler: enrollCertificate(): sendMsg =" + sendMsg);
         HttpResponse resp =
-                conn.send("enrollment",
-                        IRemoteRequest.GET_XML + "=" +
-                                true +
-                                "&" + IRemoteRequest.TOKEN_CUID + "=" +
-                                cuid +
-                                "&" + IRemoteRequest.CA_ENROLL_screenname + "=" +
-                                uid +
-                                "&" + IRemoteRequest.CA_ENROLL_publickey + "=" +
-                                encodedPubKey +
-                                "&" + IRemoteRequest.CA_ProfileId + "=" +
-                                profileId);
+                conn.send("enrollment", sendMsg);
 
         String content = resp.getContent();
 
@@ -215,7 +294,6 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
         String servlet = conf.getString(configName, "/ca/ee/ca/displayBySerial");
         */
 
-
         TPSSubsystem subsystem =
                 (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
         HttpConnector conn =
@@ -404,7 +482,7 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
             RevocationReason reason)
             throws EBaseException {
 
-        CMS.debug("CARemoteRequestHandler: revokeCertificate(): begins on serial#:"+ serialno);
+        CMS.debug("CARemoteRequestHandler: revokeCertificate(): begins on serial#:" + serialno);
         if (serialno == null || reason == null) {
             throw new EBaseException("CARemoteRequestHandler: revokeCertificate(): input parameter null.");
         }
@@ -473,7 +551,7 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
             String serialno)
             throws EBaseException {
 
-        CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): begins on serial#:"+ serialno);
+        CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): begins on serial#:" + serialno);
         if (serialno == null) {
             throw new EBaseException("CARemoteRequestHandler: unrevokeCertificate(): input parameter null.");
         }
@@ -554,7 +632,6 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
         return revokeFromOtherCA(revoke, cert.getSerialNumber().toString(), certAkiString, reason);
     }
 
-
     private CARevokeCertResponse revokeFromOtherCA(
             boolean revoke, // true==revoke; false==unrevoke
             String serialno,
@@ -562,7 +639,6 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
             RevocationReason reason)
             throws EBaseException {
 
-
         CMS.debug("CARemoteRequestHandler: revokeFromOtherCA: begins");
 
         TPSSubsystem subsystem =
@@ -673,8 +749,6 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
         return caSkiString;
     }
 
-
-
     /**
      * revokeCertificate() supports revocation routing by providing
      * CA discovery. When needed, it searchs through all listed ca
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java
index 87388ff994ac104a3f941ba70431a49ebc7877c9..aea41a29c59d6143496e13ffe217987ee88ef2ec 100644
--- a/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java
@@ -94,19 +94,19 @@ public class KRARemoteRequestHandler extends RemoteRequestHandler
             }
 
             request = IRemoteRequest.KRA_KEYGEN_Archive + "=" +
-            archive +
-            "&" + IRemoteRequest.TOKEN_CUID + "=" +
-            cuid +
-            "&" + IRemoteRequest.KRA_UserId + "=" +
-            userid +
-            "&" + IRemoteRequest.KRA_KEYGEN_KeyType + "=" +
-            "EC" +
-            "&" + IRemoteRequest.KRA_KEYGEN_EC_KeyCurve + "=" +
-            eckeycurve +
-            "&" + IRemoteRequest.KRA_Trans_DesKey + "=" +
-            sDesKey;
+                    archive +
+                    "&" + IRemoteRequest.TOKEN_CUID + "=" +
+                    cuid +
+                    "&" + IRemoteRequest.KRA_UserId + "=" +
+                    userid +
+                    "&" + IRemoteRequest.KRA_KEYGEN_KeyType + "=" +
+                    "EC" +
+                    "&" + IRemoteRequest.KRA_KEYGEN_EC_KeyCurve + "=" +
+                    eckeycurve +
+                    "&" + IRemoteRequest.KRA_Trans_DesKey + "=" +
+                    sDesKey;
 
-           CMS.debug("KRARemoteRequestHandler: outgoing request for ECC: " + request);
+            CMS.debug("KRARemoteRequestHandler: outgoing request for ECC: " + request);
 
             resp =
                     conn.send("GenerateKeyPair",
@@ -136,8 +136,9 @@ public class KRARemoteRequestHandler extends RemoteRequestHandler
         //For some reason the send method can return null and not throw an exception.
         // Check here;
 
-        if(resp == null) {
-            throw new EBaseException("KRARemoteRequestHandler: serverSideKeyGen(): No response object returned from connection.");
+        if (resp == null) {
+            throw new EBaseException(
+                    "KRARemoteRequestHandler: serverSideKeyGen(): No response object returned from connection.");
         }
 
         String content = resp.getContent();
@@ -155,7 +156,7 @@ public class KRARemoteRequestHandler extends RemoteRequestHandler
             Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
             String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS);
 
-            if(value == null) {
+            if (value == null) {
                 throw new EBaseException("KRARemoteRequestHandler: serverSideKeyGen(): Invalide status returned!");
             }
 
diff --git a/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityDatabase.java b/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityDatabase.java
index 9b4a4b28da6ab82743e6ccb8044172d1335c7d7b..4eb3e11e756a73475cc306cde42d7fe9937424dc 100644
--- a/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityDatabase.java
+++ b/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityDatabase.java
@@ -41,6 +41,7 @@ public class ActivityDatabase extends LDAPDatabase<ActivityRecord> {
     public final static String OP_DELETE = "delete"; // delete a token
     //public final static String OP_MODIFY_AUDIT_SIGNING = "modify_audit_signing";
     public final static String OP_ENROLLMENT = "enrollment";
+    public final static String OP_RECOVERY = "recovery";
     public final static String OP_RENEWAL = "renewal";
     public final static String OP_PIN_RESET = "pin_reset";
     public final static String OP_FORMAT = "format";
diff --git a/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java b/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java
index 8783e48ef211e74b4471b530be16633efa8b6898..9221d1ba0564a18c476dc20fb69fd30c4c65291e 100644
--- a/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java
+++ b/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java
@@ -152,6 +152,7 @@ public class TPSEngine {
     /* External reg values */
 
     public static final String CFG_EXTERNAL_REG = "externalReg";
+    public static final String CFG_ER_DELEGATION = "delegation";
 
     /* misc values */
 
diff --git a/base/tps/src/org/dogtagpki/server/tps/main/ExternalRegAttrs.java b/base/tps/src/org/dogtagpki/server/tps/main/ExternalRegAttrs.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae65a73b0bd85a7de75773914a9b57305dcd2973
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/main/ExternalRegAttrs.java
@@ -0,0 +1,93 @@
+package org.dogtagpki.server.tps.main;
+
+import java.util.ArrayList;
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+
+public class ExternalRegAttrs {
+    public String ldapAttrNameTokenType;
+    public String ldapAttrNameTokenCUID;
+    public String ldapAttrNameCertsToRecover;
+
+    String tokenCUID;
+    String tokenType;
+    String tokenUserId;
+    String tokenMSN;
+
+    ArrayList<ExternalRegCertToRecover> certsToRecover;
+
+    public ExternalRegAttrs(String authId) {
+        String method = "ExternalRegAttrs";
+        IConfigStore configStore = CMS.getConfigStore();
+        String configName = null;
+
+        try {
+        configName = "auths.instance." + authId + ".externalReg.tokenTypeAttributeName";
+        CMS.debug(method + ": getting config: " + configName);
+        ldapAttrNameTokenType = configStore.getString(configName,
+            "tokenType");
+
+        configName = "auths.instance." + authId + ".externalReg.cuidAttributeName";
+        CMS.debug(method + ": getting config: " + configName);
+        ldapAttrNameTokenCUID = configStore.getString(configName,
+            "tokenCUID");
+
+        configName = "auths.instance." + authId + ".externalReg.certs.recoverAttributeName";
+        CMS.debug(method + ": getting config: " + configName);
+        ldapAttrNameCertsToRecover = configStore.getString(configName,
+            "certsToRecover");
+
+        } catch (EBaseException e) {
+            CMS.debug("ExternalRegAttrs: unable to obtain certain config values.  Default to be used");
+        }
+        
+        certsToRecover = new ArrayList<ExternalRegCertToRecover>();
+    }
+
+    public void setTokenType(String type) {
+        tokenType = type;
+    }
+
+    public String getTokenType() {
+        return tokenType;
+    }
+
+    public void setTokenCUID(String cuid) {
+        tokenCUID = cuid;
+    }
+
+    public String getTokenCUID() {
+        return tokenCUID;
+    }
+
+    public void setTokenUserId(String uid) {
+        tokenUserId = uid;
+    }
+
+    public String getTokenUserId() {
+        return tokenUserId;
+    }
+
+    public void setTokenMSN(String msn) {
+        tokenMSN = msn;
+    }
+
+    public String getTokenMSN() {
+        return tokenMSN;
+    }
+
+    public int getCertsToRecoverCount()
+    {
+        return certsToRecover.size();
+    }
+
+    public void addCertToRecover(ExternalRegCertToRecover cert)
+    {
+        certsToRecover.add(cert);
+    }
+
+    public ArrayList<ExternalRegCertToRecover> getCertsToRecover() {
+        return certsToRecover;
+    }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/main/ExternalRegCertToRecover.java b/base/tps/src/org/dogtagpki/server/tps/main/ExternalRegCertToRecover.java
new file mode 100644
index 0000000000000000000000000000000000000000..69585849ba76210f1fc422ed0fe3cdba5fe97dc0
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/main/ExternalRegCertToRecover.java
@@ -0,0 +1,54 @@
+package org.dogtagpki.server.tps.main;
+
+import java.math.BigInteger;
+
+public class ExternalRegCertToRecover {
+    BigInteger keyid;
+    BigInteger serial;
+    String caConn;
+    String kraConn;
+    boolean ignoreForUpdateCerts;
+
+    public ExternalRegCertToRecover() {
+    }
+
+    public void setKeyid(BigInteger keyid) {
+        this.keyid = keyid;
+    }
+
+    public BigInteger getKeyid() {
+        return keyid;
+    }
+
+    public void setSerial(BigInteger serial) {
+        this.serial = serial;
+    }
+
+    public BigInteger getSerial() {
+        return serial;
+    }
+
+    public void setCaConn(String conn) {
+        caConn = conn;
+    }
+
+    public String getCaConn() {
+        return caConn;
+    }
+
+    public void setKraConn(String conn) {
+        kraConn = conn;
+    }
+
+    public String getKraConn() {
+        return kraConn;
+    }
+
+    public void setIgnoreForUpdateCerts(boolean ignore) {
+        ignoreForUpdateCerts = ignore;
+    }
+
+    public boolean getIgnoreForUpdateCerts() {
+        return ignoreForUpdateCerts;
+    }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
index dde24e49699edaa9bcf23bbfa9faa7bae9990217..402f58bcd81b9714d0e1eb779f343608a0e2a37b 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
@@ -6,6 +6,7 @@ import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.Enumeration;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Random;
@@ -19,6 +20,7 @@ import netscape.security.x509.X509CertImpl;
 import org.dogtagpki.server.tps.TPSSession;
 import org.dogtagpki.server.tps.TPSSubsystem;
 import org.dogtagpki.server.tps.TPSTokenPolicy;
+import org.dogtagpki.server.tps.authentication.TPSAuthenticator;
 import org.dogtagpki.server.tps.channel.SecureChannel;
 import org.dogtagpki.server.tps.channel.SecureChannel.TokenKeyType;
 import org.dogtagpki.server.tps.cms.CAEnrollCertResponse;
@@ -27,12 +29,15 @@ import org.dogtagpki.server.tps.cms.CARenewCertResponse;
 import org.dogtagpki.server.tps.cms.CARetrieveCertResponse;
 import org.dogtagpki.server.tps.cms.CARevokeCertResponse;
 import org.dogtagpki.server.tps.cms.KRARecoverKeyResponse;
+import org.dogtagpki.server.tps.cms.KRARemoteRequestHandler;
 import org.dogtagpki.server.tps.cms.KRAServerSideKeyGenResponse;
 import org.dogtagpki.server.tps.dbs.ActivityDatabase;
 import org.dogtagpki.server.tps.dbs.TPSCertRecord;
 import org.dogtagpki.server.tps.dbs.TokenRecord;
 import org.dogtagpki.server.tps.engine.TPSEngine;
 import org.dogtagpki.server.tps.engine.TPSEngine.ENROLL_MODES;
+import org.dogtagpki.server.tps.main.ExternalRegAttrs;
+import org.dogtagpki.server.tps.main.ExternalRegCertToRecover;
 import org.dogtagpki.server.tps.main.ObjectSpec;
 import org.dogtagpki.server.tps.main.PKCS11Obj;
 import org.dogtagpki.tps.main.TPSBuffer;
@@ -48,6 +53,7 @@ import org.mozilla.jss.pkcs11.PK11RSAPublicKey;
 import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
 
 import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthCredentials;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.EPropertyNotFound;
 import com.netscape.certsrv.base.IConfigStore;
@@ -56,12 +62,15 @@ import com.netscape.cmsutil.util.Utils;
 
 public class TPSEnrollProcessor extends TPSProcessor {
 
+    protected boolean isDelegation;
+
     public TPSEnrollProcessor(TPSSession session) {
         super(session);
     }
 
     @Override
     public void process(BeginOpMsg beginMsg) throws TPSException, IOException {
+
         if (beginMsg == null) {
             throw new TPSException("TPSEnrollrocessor.process: invalid input data, not beginMsg provided.",
                     TPSStatus.STATUS_ERROR_CONTACT_ADMIN);
@@ -69,6 +78,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
         setBeginMessage(beginMsg);
         setCurrentTokenOperation("enroll");
         checkIsExternalReg();
+        if (isExternalReg)
+            checkIsDelegation();
 
         enroll();
 
@@ -79,6 +90,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
         String auditMsg = null;
         TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
         TPSTokenPolicy tokenPolicy = new TPSTokenPolicy(tps);
+        IConfigStore configStore = CMS.getConfigStore();
+        String configName;
 
         AppletInfo appletInfo = null;
         TokenRecord tokenRecord = null;
@@ -108,18 +121,131 @@ public class TPSEnrollProcessor extends TPSProcessor {
         }
 
         fillTokenRecord(tokenRecord, appletInfo);
+        String cuid = appletInfo.getCUIDhexStringPlain();
         session.setTokenRecord(tokenRecord);
-
-        String resolverInstName = getResolverInstanceName();
-
         String tokenType = null;
 
-        tokenType = resolveTokenProfile(resolverInstName, appletInfo.getCUIDhexString(), appletInfo.getMSNString(),
-                appletInfo.getMajorVersion(), appletInfo.getMinorVersion());
-        CMS.debug("TPSEnrollProcessor.enroll: resolved tokenType: " + tokenType);
+        if (isExternalReg) {
+            CMS.debug("In TPSEnrollProcessor.enroll isExternalReg: ON");
+            /*
+             * need to reach out to the Registration DB (authid)
+             * Entire user entry should be retrieved and parsed, if needed
+             * The following are retrieved, e.g.:
+             *     externalReg.tokenTypeAttributeName=tokenType
+             *     externalReg.certs.recoverAttributeName=certsToRecover
+             *     externalReg.tokenCuidName=userKey
+             */
+            configName = "externalReg.authId";
+            String authId;
+            try {
+                authId = configStore.getString(configName);
+            } catch (EBaseException e) {
+                CMS.debug("TPSEnrollProcessor.enroll: Internal Error obtaining mandatory config values. Error: " + e);
+                auditMsg = "TPS error getting config values from config store." + e.toString();
+                tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                        "failure");
+
+                throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+            }
+
+            /* get user login and password - set in "login" */
+            IAuthCredentials userCred;
+            try {
+                CMS.debug("In TPSEnrollProcessor.enroll: isExternalReg: calling requestUserId");
+                TPSAuthenticator userAuth =
+                        getAuthentication(authId);
+
+                userCred = requestUserId("enroll", cuid, userAuth, beginMsg.getExtensions());
+                userid = (String) userCred.get(userAuth.getAuthCredName());
+                CMS.debug("TPSEnrollProcessor.enroll: isExternalReg: userCred (attempted) userid=" + userid);
+                tokenRecord.setUserID(userid);
+                authToken = authenticateUser("enroll", userAuth, userCred);
+                userid = authToken.getInString("userid");
+                tokenRecord.setUserID(userid);
+                CMS.debug("TPSEnrollProcessor.enroll:: auth token userid=" + userid);
+            } catch (Exception e) {
+                // all exceptions are considered login failure
+                CMS.debug("TPSEnrollProcessor.enroll:: authentication exception thrown: " + e);
+                auditMsg = "ExternalReg authentication failed, status = STATUS_ERROR_LOGIN";
+
+                tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                        "failure");
+
+                throw new TPSException(auditMsg,
+                        TPSStatus.STATUS_ERROR_LOGIN);
+            }
+
+            ExternalRegAttrs erAttrs;
+            try {
+                erAttrs = processExternalRegAttrs(/*authToken,*/authId);
+            } catch (EBaseException ee) {
+                auditMsg = "after processExternalRegAttrs: " + ee.toString();
+                tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                        "failure");
+
+                throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+            }
+
+            /*
+             * If cuid is provided on the user registration record, then
+             * we have to compare that with the current token cuid;
+             *
+             * If, the cuid is not provided on the user registration record,
+             * then any token can be used.
+             */
+            if (erAttrs.getTokenCUID() != null) {
+                CMS.debug("TPSEnrollProcessor.enroll: erAttrs.getTokenCUID()=" + erAttrs.getTokenCUID());
+                CMS.debug("TPSEnrollProcessor.enroll: tokenRecord.getId()=" + tokenRecord.getId());
+                if (!tokenRecord.getId().equals(erAttrs.getTokenCUID())) {
+                    auditMsg = "isExternalReg: token CUID not matching record:" + erAttrs.getTokenCUID();
+                    CMS.debug("TPSEnrollProcessor.enroll:" + auditMsg);
+                    tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                            "failure");
+                    throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_NOT_TOKEN_OWNER);
+                }
+            }
+
+            session.setExternalRegAttrs(erAttrs);
+            if (erAttrs.getTokenType() != null) {
+                CMS.debug("In TPSEnrollProcessor.enroll: isExternalReg: setting tokenType to tokenType attribute of user entry:"
+                        +
+                        erAttrs.getTokenType());
+                setSelectedTokenType(erAttrs.getTokenType());
+            } else {
+                // get the default externalReg tokenType
+                configName = "externalReg.default.tokenType";
+                CMS.debug("TPSEnrollProcessor.enroll: externalReg user entry does not contain tokenType...setting to config: "
+                        + configName);
+                try {
+                    tokenType = configStore.getString(configName,
+                            "externalRegAddToToken");
+                    CMS.debug("In TPSEnrollProcessor.enroll: isExternalReg: setting tokenType to default:" +
+                            tokenType);
+                    setSelectedTokenType(tokenType);
+                } catch (EBaseException e) {
+                    CMS.debug("TPSEnrollProcessor.enroll: Internal Error obtaining mandatory config values. Error: "
+                            + e);
+                    auditMsg = "TPS error getting config values from config store." + e.toString();
+                    tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                            "failure");
+
+                    throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+                }
+            }
+        } else {
+            CMS.debug("In TPSEnrollProcessor.enroll isExternalReg: OFF");
+            /*
+             * Note: op.enroll.tokenProfileResolver=none indicates no resolver
+             *    plugin used (tokenType resolved perhaps via authentication)
+             */
+            String resolverInstName = getResolverInstanceName();
+
+            tokenType = resolveTokenProfile(resolverInstName, appletInfo.getCUIDhexString(), appletInfo.getMSNString(),
+                    appletInfo.getMajorVersion(), appletInfo.getMinorVersion());
+            CMS.debug("TPSEnrollProcessor.enroll: resolved tokenType: " + tokenType);
+        }
 
         checkProfileStateOK();
-        String cuid = appletInfo.getCUIDhexStringPlain();
 
         boolean do_force_format = false;
         if (isTokenPresent) {
@@ -148,7 +274,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
             do_force_format = tokenPolicy.isForceTokenFormat(cuid);
 
-            if (!tokenPolicy.isAllowdTokenReenroll(cuid) &&
+            if (!isExternalReg &&
+                    !tokenPolicy.isAllowdTokenReenroll(cuid) &&
                     !tokenPolicy.isAllowdTokenRenew(cuid)) {
                 CMS.debug("TPSEnrollProcessor.enroll: token renewal or reEnroll disallowed ");
                 auditMsg = "Operation renewal or reEnroll for CUID " + cuid +
@@ -158,6 +285,9 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
                 throw new TPSException(auditMsg,
                         TPSStatus.STATUS_ERROR_DISABLED_TOKEN);
+            } else {
+                auditMsg = "isExternalReg: skip token policy (reenroll, renewal) check";
+                CMS.debug("TPSEnrollProcessor.enroll:" + auditMsg);
             }
         } else {
             CMS.debug("TPSEnrollProcessor.enroll: token does not exist");
@@ -165,7 +295,10 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
             checkAllowUnknownToken(TPSEngine.OP_FORMAT_PREFIX);
         }
-        checkAndAuthenticateUser(appletInfo, tokenType);
+
+        // isExternalReg : user already authenticated earlier
+        if (!isExternalReg)
+            checkAndAuthenticateUser(appletInfo, tokenType);
 
         if (do_force_format) {
             CMS.debug("TPSEnrollProcessor.enroll: About to force format first due to policy.");
@@ -213,6 +346,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
             } catch (Exception e) {
                 String failMsg = "add token failure";
                 auditMsg = failMsg + ":" + e.toString();
+                tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                        "failure");
                 throw new TPSException(auditMsg);
             }
         }
@@ -227,38 +362,95 @@ public class TPSEnrollProcessor extends TPSProcessor {
         certsInfo.setEndProgress(90);
 
         boolean renewed = false;
-        TPSStatus status = generateCertsAfterRenewalRecoveryPolicy(certsInfo, channel, appletInfo);
+        boolean recovered = false;
+        TPSStatus status = TPSStatus.STATUS_NO_ERROR;
+
+        if (!isExternalReg) {
+            status = generateCertsAfterRenewalRecoveryPolicy(certsInfo, channel, appletInfo);
+        }
+
         //most failed would have thrown an exception
         String statusString = "Unknown"; // gives some meaningful debug message
         if (status == TPSStatus.STATUS_NO_ERROR)
             statusString = "Enrollment to follow";
-        else if (status == TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED)
+        else if (status == TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED) {
             statusString = "Recovery processed";
-        else if (status == TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED)
+            recovered = true;
+            //TODO:
+            //tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(), auditMsg, "success");
+        } else if (status == TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED) {
             statusString = "Renewal processed";
-        else {
+            renewed = true;
+            //TODO:
+            //tps.tdb.tdbActivity(ActivityDatabase.OP_RENEWAL, tokenRecord, session.getIpAddress(), auditMsg, "success");
+        } else {
             auditMsg = " generateCertsAfterRenewalRecoveryPolicy returned status=" + status;
             CMS.debug("TPSEnrollProcessor.enroll:" + auditMsg);
+            tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                    "failure");
             throw new TPSException(auditMsg);
         }
-        auditMsg = "generateCertsAfterRenewalRecoveryPolicy returns status:"
-                + EndOpMsg.statusToInt(status) + " : " + statusString;
-        CMS.debug("TPSEnrollProcessor.enroll: " + auditMsg);
+        if (!isExternalReg) {
+            auditMsg = "generateCertsAfterRenewalRecoveryPolicy returns status:"
+                    + EndOpMsg.statusToInt(status) + " : " + statusString;
+            CMS.debug("TPSEnrollProcessor.enroll: " + auditMsg);
+        }
         if (status == TPSStatus.STATUS_NO_ERROR) {
             if (!generateCertificates(certsInfo, channel, appletInfo)) {
-                CMS.debug("TPSEnrollProcessor.enroll:generateCertificates returned false means some certs failed enrollment;  clean up (format) the token");
-                format(true /*skipAuth*/);
+                // in case isExternalReg, leave the token alone, do not format
+                if (!isExternalReg) {
+                    CMS.debug("TPSEnrollProcessor.enroll:generateCertificates returned false means some certs failed enrollment;  clean up (format) the token");
+                    format(true /*skipAuth*/);
+                }
+                tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                        "failure");
                 throw new TPSException("generateCertificates failed");
             } else {
                 CMS.debug("TPSEnrollProcessor.enroll:generateCertificates returned true means cert enrollment successful");
+                /*
+                 * isExternalReg -
+                 * ??  Renew if token has "RENEW=YES" set by admin
+                 *   recovery and delete/revoke happens:
+                 *       recover certsToRecover
+                 *       delete/revoke certsToDelete
+                 *       (per latest design, delete is implied for certs
+                 *       not existing in the recover list)
+                 */
+
+                if (isExternalReg) {
+                    try {
+                        TPSStatus recoverStatus = externalRegRecover(cuid, userid, channel, certsInfo, appletInfo,
+                                tokenRecord);
+                        CMS.debug("TPSEnrollProcessor.enroll: after externalRegRecover status is:" + recoverStatus);
+                        if (recoverStatus == TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED) {
+                            recovered = true;
+                            //TODO:
+                            //tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(), auditMsg, "success");
+                        }
+                    } catch (EBaseException e) {
+                        auditMsg = "TPSEnrollProcessor.enroll: externalRegRecover: " + e;
+                        CMS.debug(auditMsg);
+                        tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(),
+                                auditMsg,
+                                "failure");
+
+                        throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_BAD_STATUS);
+                    }
+                } else {
+                    //TODO:
+                    //tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                    //"success");
+                }
             }
         }
         // at this point, enrollment, renewal, or recovery have been processed accordingly;
-        if (status == TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED &&
+        if (!isExternalReg &&
+                status == TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED &&
                 tokenPolicy.isAllowdTokenRenew(cuid)) {
             renewed = true;
             CMS.debug("TPSEnrollProcessor.enroll: renewal happened.. ");
         }
+
         /*
          * TODO:
          * find the point to do the following...
@@ -306,7 +498,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
         } catch (Exception e) {
             String failMsg = "update token failure";
             auditMsg = failMsg + ":" + e.toString();
-            tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), failMsg,
+            tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
                     "failure");
             throw new TPSException(auditMsg);
         }
@@ -316,7 +508,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
             // clean up the cert records used to belong to this token in tokendb
             tps.tdb.tdbRemoveCertificatesByCUID(tokenRecord.getId());
         } catch (Exception e) {
-            auditMsg = "Attempt to clean up record with tdbRemoveCertificatesByCUID failed; token probably clean; continue anyway:" + e;
+            auditMsg = "Attempt to clean up record with tdbRemoveCertificatesByCUID failed; token probably clean; continue anyway:"
+                    + e;
             CMS.debug("TPSEnrollProcessor.enroll:" + auditMsg);
         }
         CMS.debug("TPSEnrollProcessor.enroll: adding certs to token with tdbAddCertificatesForCUID...");
@@ -325,18 +518,36 @@ public class TPSEnrollProcessor extends TPSProcessor {
         CMS.debug("TPSEnrollProcessor.enroll: tokendb updated with certs to the cuid so that it reflects what's on the token");
 
         auditMsg = "appletVersion=" + lastObjVer + "; tokenType =" + selectedTokenType + "; userid =" + userid;
-        if (renewed) {
-            tps.tdb.tdbActivity(ActivityDatabase.OP_RENEWAL, tokenRecord, session.getIpAddress(), auditMsg, "success");
-        } else {
-            tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
-                    "success");
-        }
+        tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+                "success");
 
         CMS.debug("TPSEnrollProcessor.enroll: leaving ...");
 
         statusUpdate(100, "PROGRESS_DONE_ENROLLMENT");
     }
 
+    protected void checkIsDelegation() throws TPSException {
+        String method = "TPSEnrollProcessor.checkIsDelegation:";
+        String auditMsg;
+
+        IConfigStore configStore = CMS.getConfigStore();
+        CMS.debug(method + "begins");
+        String RH_Delegation_Cfg = TPSEngine.CFG_EXTERNAL_REG + "." +
+                TPSEngine.CFG_ER_DELEGATION + ".enable";
+
+        try {
+            //These defaults are well known, it is safe to use them.
+
+            this.isDelegation = configStore.getBoolean(RH_Delegation_Cfg, false);
+            CMS.debug(method + " isDelegation: " + isDelegation);
+        } catch (EBaseException e1) {
+            auditMsg = "Internal Error obtaining config values. Error: " + e1;
+            CMS.debug(method + auditMsg);
+            throw new TPSException(method + auditMsg);
+        }
+
+    }
+
     private void writeFinalPKCS11ObjectToToken(PKCS11Obj pkcs11objx, AppletInfo ainfo, SecureChannel channel)
             throws TPSException, IOException {
         if (pkcs11objx == null || ainfo == null || channel == null) {
@@ -482,6 +693,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
         String auditMsg;
         final String method = "TPSEnrollProcessor.generateCertsAfterRenewalRecoveryPolicy";
         CMS.debug(method + ": begins");
+        IConfigStore configStore = CMS.getConfigStore();
+        String configName;
         TPSSubsystem tps =
                 (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
         TPSTokenPolicy tokenPolicy = new TPSTokenPolicy(tps);
@@ -625,8 +838,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
                     // ToDo: This section has not been tested to work.. Make sure this works.
 
-                    IConfigStore configStore = CMS.getConfigStore();
-                    String configName = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType()
+                    configStore = CMS.getConfigStore();
+                    configName = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType()
                             + ".temporaryToken.tokenType";
                     try {
                         String tmpTokenType = configStore.getString(configName);
@@ -657,6 +870,113 @@ public class TPSEnrollProcessor extends TPSProcessor {
     }
 
     /*
+     * (for isExternalReg)
+     * externalRegRecover
+     *    reaches out to CA for retrieving cert to recover
+     *    reaches out to KRA for key recovery.
+     *    All the certs to have keys recovered are in
+     *    session.getExternalRegAttrs().getCertsToRecover()
+     *
+     * when returned successfully, externalRegCertToRecover should have
+     * completed externalReg recovery
+     */
+    private TPSStatus externalRegRecover(
+            String cuid,
+            String userid,
+            SecureChannel channel,
+            EnrolledCertsInfo certsInfo,
+            AppletInfo appletInfo,
+            TokenRecord tokenRecord)
+            throws EBaseException, IOException {
+
+        String method = "TPSEnrollProcessor.externalRegRecover:";
+        String auditMsg;
+        CMS.debug(method + "begins");
+        TPSStatus status = TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED;
+        if (session == null || session.getExternalRegAttrs() == null ||
+                session.getExternalRegAttrs().getCertsToRecover() == null) {
+            CMS.debug(method + "nothing to recover...");
+        }
+        CMS.debug(method + "number of certs to recover=" +
+                session.getExternalRegAttrs().getCertsToRecoverCount());
+        ArrayList<ExternalRegCertToRecover> erCertsToRecover =
+                session.getExternalRegAttrs().getCertsToRecover();
+
+        for (ExternalRegCertToRecover erCert : erCertsToRecover) {
+            BigInteger keyid = erCert.getKeyid();
+            BigInteger serial = erCert.getSerial();
+            String caConn = erCert.getCaConn();
+            String kraConn = erCert.getKraConn();
+
+            auditMsg = "ExternalReg cert record: serial=" +
+                    serial.toString();
+
+            // recover cert
+            CARemoteRequestHandler caRH = new CARemoteRequestHandler(caConn);
+            CARetrieveCertResponse certResp = caRH.retrieveCertificate(serial);
+            if (certResp == null) {
+                auditMsg = "In recovery mode, CARetieveCertResponse object not found!";
+                CMS.debug(method + auditMsg);
+                return TPSStatus.STATUS_ERROR_RECOVERY_FAILED;
+            }
+
+            String retCertB64 = certResp.getCertB64();
+            CMS.debug(method + "recovering:  retCertB64: " + retCertB64);
+            byte[] cert_bytes = Utils.base64decode(retCertB64);
+
+            TPSBuffer cert_bytes_buf = new TPSBuffer(cert_bytes);
+            CMS.debug(method + "recovering: retCertB64: "
+                    + cert_bytes_buf.toHexString());
+            if (retCertB64 != null)
+                CMS.debug(method + "recovering: cert b64 =" + retCertB64);
+            else {
+                auditMsg = "recovering cert b64 not found";
+                CMS.debug(method + auditMsg);
+                return TPSStatus.STATUS_ERROR_RECOVERY_FAILED;
+            }
+
+            // recover keys
+            KRARecoverKeyResponse keyResp = null;
+            if (kraConn != null) {
+                auditMsg = "kraConn not null";
+                CMS.debug(method + auditMsg);
+                KRARemoteRequestHandler kraRH = new KRARemoteRequestHandler(kraConn);
+                if (channel.getDRMWrappedDesKey() == null) {
+                    auditMsg = "channel.getDRMWrappedDesKey() null";
+                    CMS.debug(method + auditMsg);
+                    return TPSStatus.STATUS_ERROR_RECOVERY_FAILED;
+                } else {
+                    auditMsg = "channel.getDRMWrappedDesKey() not null";
+                    CMS.debug(method + auditMsg);
+                }
+                keyResp = kraRH.recoverKey(cuid, userid, Util.specialURLEncode(channel.getDRMWrappedDesKey()),
+                        Util.uriEncode(retCertB64));
+                if (keyResp == null) {
+                    auditMsg = "recovering key not found";
+                    CMS.debug(method + auditMsg);
+                    return TPSStatus.STATUS_ERROR_RECOVERY_FAILED;
+                }
+            }
+
+            CertEnrollInfo cEnrollInfo = new CertEnrollInfo();
+
+            cEnrollInfo.setTokenToBeRecovered(tokenRecord);
+            cEnrollInfo.setRecoveredCertData(certResp);
+            cEnrollInfo.setRecoveredKeyData(keyResp);
+
+            generateCertificate(certsInfo, channel, appletInfo,
+                    "encryption",
+                    TPSEngine.ENROLL_MODES.MODE_RECOVERY,
+                    certsInfo.getCurrentCertIndex() + 1, cEnrollInfo);
+
+            CMS.debug(method + "after generateCertificate() with MODE_RECOVERY");
+        }
+
+        CMS.debug(method + "ends");
+        return status;
+    }
+
+    /*
     * Renewal logic
     *  1. Create Optional local TPS grace period per token profile,
     *     per token type, such as signing or encryption.
@@ -1077,7 +1397,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 if (serialToRecover != null) {
                     // get recovery conn id
                     String caConnId;
-                    String config = "op.enroll." + certToRecover.getType() + ".keyGen." + certToRecover.getKeyType() + ".ca.conn";
+                    String config = "op.enroll." + certToRecover.getType() + ".keyGen." + certToRecover.getKeyType()
+                            + ".ca.conn";
                     try {
                         caConnId = configStore.getString(config);
                     } catch (Exception e) {
@@ -1170,6 +1491,12 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
         int keyTypeNum = getNumberCertsToEnroll();
 
+        if (isExternalReg && keyTypeNum == 0) {
+            CMS.debug("TPSEnrollProcess.generateCertificates: isExternalReg with tokenType:" + selectedTokenType
+                    + "; no certs to enroll per configuration");
+            return noFailedCerts;
+        }
+
         certsInfo.setNumCertsToEnroll(keyTypeNum);
 
         CMS.debug("TPSEnrollProcessor.generateCertificate: Number of certs to enroll: " + keyTypeNum);
@@ -1254,7 +1581,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
         CMS.debug("TPSEnrollProcessor.generateCertificate: entering ... certIdNumOverride: " + certIdNumOverride
                 + " mode: " + mode);
 
-        if (certsInfo == null || aInfo == null || channel == null || aInfo == null) {
+        if (certsInfo == null || aInfo == null || channel == null) {
             throw new TPSException("TPSEnrollProcessor.generateCertificate: Bad Input data!",
                     TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
         }
@@ -1283,8 +1610,13 @@ public class TPSEnrollProcessor extends TPSProcessor {
             CMS.debug("TPSEnrollProcessor.generateCertificate: keyTypePrefix: " + keyTypePrefix);
 
             String configName = keyTypePrefix + ".ca.profileId";
-            String profileId = configStore.getString(configName);
-            CMS.debug("TPSEnrollProcessor.generateCertificate: profileId: " + profileId);
+            String profileId = null;
+            if (isExternalReg) {
+                profileId = configStore.getString(configName, "NA"); // if not supplied then does not apply due to recovery
+            } else {
+                profileId = configStore.getString(configName);
+                CMS.debug("TPSEnrollProcessor.generateCertificate: profileId: " + profileId);
+            }
 
             configName = keyTypePrefix + ".certId";
             String certId = configStore.getString(configName, "C0");
@@ -1587,9 +1919,115 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
                 CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: userid =" + userid + ", cuid="
                         + aInfo.getCUIDhexString());
-                CAEnrollCertResponse caEnrollResp = caRH.enrollCertificate(encodedParsedPubKey, userid,
-                        aInfo.getCUIDhexString(), getSelectedTokenType(),
-                        cEnrollInfo.getKeyType());
+
+                CAEnrollCertResponse caEnrollResp;
+                if (isDelegation) {
+                    int sanNum = 0;
+                    String urlSanExt = null;
+                    CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: isDelegation true");
+                    /*
+                     * build up name/value pairs for pattern mapping
+                     */
+                    LinkedHashMap<String, String> nv = new LinkedHashMap<String, String>();
+
+                    nv.put("cuid", aInfo.getCUIDhexStringPlain());
+                    nv.put("msn", aInfo.getMSNString());
+                    nv.put("userid", userid);
+                    nv.put("auth.cn", userid);
+                    nv.put("profileId", getSelectedTokenType());
+
+                    CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: fill in nv with authToken name/value pairs");
+                    Enumeration<String> n = authToken.getElements();
+                    while (n.hasMoreElements()) {
+                        String name = n.nextElement();
+                        CMS.debug("TPSEnrollProcessor.enrollOneCertificate::name =" + name);
+                        if (ldapStringAttrs != null && ldapStringAttrs.contains(name)) {
+                            String[] vals = authToken.getInStringArray(name);
+                            if (vals != null) {
+                                CMS.debug("TPSEnrollProcessor.enrollOneCertificate::val =" + vals[0]);
+                                nv.put("auth." + name, vals[0]);
+                            } else {
+                                CMS.debug("TPSEnrollProcessor.enrollOneCertificate::name not found in authToken:"
+                                        + name);
+                            }
+                        }
+                    }
+
+                    String subjectdn = "";
+                    /*
+                     * isDelegate: process subjectdn
+                     * e.g.
+                     *     op.enroll.delegateISEtoken.keyGen.encryption.dnpattern=
+                     *         cn=$auth.firstname$.$auth.lastname$.$auth.edipi$,e=$auth.mail$,o=TMS Org
+                     *     becomes:
+                     *       CN=Jane.Doe.0123456789,E=jdoe redhat com,O=TMS Org
+                     */
+                    IConfigStore configStore = CMS.getConfigStore();
+                    String configName;
+                    configName = TPSEngine.OP_ENROLL_PREFIX + "." +
+                            getSelectedTokenType() + ".keyGen." +
+                            cEnrollInfo.getKeyType() + ".dnpattern";
+                    try {
+                        String dnpattern = configStore.getString(configName);
+                        subjectdn = mapPattern(nv, dnpattern);
+                    } catch (EBaseException e) {
+                        CMS.debug("TPSEnrollProcessor.enrollOneCertificate: isDelegation dnpattern not set");
+                    }
+
+                    /*
+                     * isDelegate: process SAN_ext
+                     * e.g.
+                     *     op.enroll.delegateISEtoken.keyGen.encryption.SANpattern=
+                     *         $auth edipi$ abc redhat com
+                     *     becomes:
+                     *       0123456789 abc redhat com
+                     */
+                    configName = TPSEngine.OP_ENROLL_PREFIX + "." +
+                            getSelectedTokenType() + ".keyGen." +
+                            cEnrollInfo.getKeyType() + ".SANpattern";
+                    try {
+                        String sanPattern = configStore.getString(configName);
+                        String[] sanToks = sanPattern.split(",");
+                        for (String sanToken : sanToks) {
+                            /*
+                             * for every "tok" in pattern,
+                             * 1. mapPattern
+                             * 2. uriEncode
+                             * 3. append
+                             * url_san_ext will look like san1&san2&san3...&
+                             */
+                            CMS.debug("TPSEnrollProcessor.enrollOneCertificate: isDeletation: sanToken:" + sanToken);
+                            String sanExt = mapPattern(nv, sanToken);
+                            String urlSanExt1 = Util.uriEncode(sanExt);
+                            if (urlSanExt == null) { // first one
+                                urlSanExt = "req_san_pattern_" +
+                                        sanNum + "=" + urlSanExt1;
+                            } else {
+                                urlSanExt = urlSanExt +
+                                        "&req_san_pattern_" + sanNum +
+                                        "=" + urlSanExt1;
+                            }
+                            CMS.debug("TPSEnrollProcessor.enrollOneCertificate: isDelegation: urlSanExt1:" + urlSanExt1);
+
+                            sanNum++;
+                        }
+                    } catch (EBaseException e) {
+                        CMS.debug("TPSEnrollProcessor.enrollOneCertificate: isDeletation sanPattern not set");
+                    }
+
+                    CMS.debug("TPSEnrollProcessor.enrollOneCertificate: isDelegation: Before calling enrolCertificate");
+                    caEnrollResp =
+                            caRH.enrollCertificate(encodedParsedPubKey, userid,
+                                    subjectdn, sanNum, urlSanExt,
+                                    aInfo.getCUIDhexString(), getSelectedTokenType(),
+                                    cEnrollInfo.getKeyType());
+                } else {
+                    CMS.debug("TPSEnrollProcessor.enrollOneCertificate: not isDelegation: Before calling enrolCertificate");
+                    caEnrollResp = caRH.enrollCertificate(encodedParsedPubKey, userid,
+                            aInfo.getCUIDhexString(), getSelectedTokenType(),
+                            cEnrollInfo.getKeyType());
+                }
+
                 String retCertB64 = caEnrollResp.getCertB64();
 
                 CMS.debug("TPSEnrollProcessor.enrollOneCertificate: retCertB64: " + retCertB64);
@@ -1689,7 +2127,6 @@ public class TPSEnrollProcessor extends TPSProcessor {
                                 TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
                     }
 
-
                     TPSBuffer cert_bytes_buf = new TPSBuffer(cert_bytes);
                     CMS.debug("TPSEnrollProcessor.enrollOneCertificate: renewing: retCertB64: "
                             + cert_bytes_buf.toHexString());
@@ -2367,27 +2804,32 @@ public class TPSEnrollProcessor extends TPSProcessor {
     }
 
     protected int getNumberCertsToEnroll() throws TPSException {
+        String method = "TPSEnrollProcessor.getNumberCertsToEnroll:";
+        String auditMsg;
         IConfigStore configStore = CMS.getConfigStore();
         int keyTypeNum = 0;
         try {
             String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "."
                     + TPSEngine.CFG_KEYGEN_KEYTYPE_NUM;
+            CMS.debug(method + "getting config value for:" + configValue);
             keyTypeNum = configStore.getInteger(
                     configValue, 0);
 
         } catch (EBaseException e) {
-            throw new TPSException("TPSEnrollProcessor.getNumberCertsToEnroll: Internal error finding config value: "
-                    + e,
+            auditMsg = "Internal error finding config value: " + e;
+            throw new TPSException(method + auditMsg,
                     TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
 
         }
 
-        if (keyTypeNum == 0) {
-            throw new TPSException(
-                    "TPSEnrollProcessor.getNumberCertsToEnroll: invalid number of certificates configured!",
-                    TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+        if (!isExternalReg) {
+            if (keyTypeNum == 0) {
+                throw new TPSException(
+                        method + " invalid number of certificates configured!",
+                        TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+            }
         }
-        CMS.debug("TPSProcess.getNumberCertsToEnroll: returning: " + keyTypeNum);
+        CMS.debug(method + " returning: " + keyTypeNum);
 
         return keyTypeNum;
     }
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
index c37a17c11db2ef09cfc3530c606f7122130d4e09..295ce4f19ebe61cff46aaf926c3e99db780f1243 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
@@ -24,9 +24,12 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -47,6 +50,9 @@ import org.dogtagpki.server.tps.dbs.ActivityDatabase;
 import org.dogtagpki.server.tps.dbs.TPSCertRecord;
 import org.dogtagpki.server.tps.dbs.TokenRecord;
 import org.dogtagpki.server.tps.engine.TPSEngine;
+import org.dogtagpki.server.tps.main.ExternalRegAttrs;
+//import org.dogtagpki.server.tps.main.ExternalRegCertToDelete;
+import org.dogtagpki.server.tps.main.ExternalRegCertToRecover;
 import org.dogtagpki.server.tps.profile.BaseTokenProfileResolver;
 import org.dogtagpki.server.tps.profile.TokenProfileParams;
 import org.dogtagpki.tps.apdu.APDU;
@@ -106,6 +112,8 @@ public class TPSProcessor {
     protected TPSSession session;
     //protected TokenRecord tokenRecord;
     protected String selectedTokenType;
+    IAuthToken authToken;
+    List<String> ldapStringAttrs;
 
     protected String userid = null;
     protected String currentTokenOperation;
@@ -155,7 +163,7 @@ public class TPSProcessor {
 
         TokenRecord tokenRecord = getTokenRecord();
 
-        if(tokenRecord == null) {
+        if (tokenRecord == null) {
             throw new NullPointerException("TPSProcessor.setSelectedTokenType: Can't find token record for token!");
         }
         tokenRecord.setType(selectedTokenType);
@@ -750,6 +758,20 @@ public class TPSProcessor {
             CMS.debug(auditMsg);
             throw new EBaseException(auditMsg);
         }
+        return getAuthentication(authId);
+    }
+
+    public TPSAuthenticator getAuthentication(String authId)
+            throws EBaseException {
+        CMS.debug("TPSProcessor.getAuthentication");
+        String auditMsg = null;
+
+        if (authId.isEmpty()) {
+            auditMsg = "TPSProcessor.getAuthentication: missing parameters: authId";
+            CMS.debug(auditMsg);
+            throw new EBaseException(auditMsg);
+        }
+        IConfigStore configStore = CMS.getConfigStore();
 
         TPSSubsystem subsystem =
                 (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
@@ -765,6 +787,22 @@ public class TPSProcessor {
             throw new EBaseException(auditMsg);
         }
         authInst.setAuthCredName(authCredName);
+
+        // set ldapStringAttrs for later processing
+        String authLdapStringAttrs = "auths.instance." + authId + ".ldapStringAttributes";
+        CMS.debug("TPSProcessor.getAuthentication: getting config: " +
+                authLdapStringAttrs);
+        String authLdapStringAttributes = configStore.getString(authLdapStringAttrs, "");
+        if (authLdapStringAttributes != null && !authLdapStringAttributes.equals("")) {
+            auditMsg = "TPSProcessor.getAuthentication: got ldapStringAttributes... setting up";
+            CMS.debug(auditMsg);
+            ldapStringAttrs = Arrays.asList(authLdapStringAttributes.split(","));
+        } else {
+            // not set is okay
+            auditMsg = "TPSProcessor.getAuthentication: config param not set:" + authLdapStringAttributes;
+            CMS.debug(auditMsg);
+        }
+
         return authInst;
     }
 
@@ -782,9 +820,7 @@ public class TPSProcessor {
             TPSAuthenticator userAuth,
             IAuthCredentials userCred)
             throws EBaseException, TPSException {
-        /**
-         * TODO: isExternalReg is not handled until decision made
-         */
+
         String auditMsg = null;
         CMS.debug("TPSProcessor.authenticateUser");
         if (op.isEmpty() || userAuth == null || userCred == null) {
@@ -796,12 +832,17 @@ public class TPSProcessor {
 
         try {
             // Authenticate user
-            IAuthToken aToken = auth.authenticate(userCred);
-            if (aToken != null) {
+            authToken = auth.authenticate(userCred);
+            if (authToken != null) {
                 CMS.debug("TPSProcessor.authenticateUser: authentication success");
-                return aToken;
+                Enumeration<String> n = authToken.getElements();
+                while (n.hasMoreElements()) {
+                    String name = n.nextElement();
+                    CMS.debug("TPSProcessor.authenticateUser: got authToken val name:" + name);
+                }
+                return authToken;
             } else {
-                CMS.debug("TPSProcessor.authenticateUser: authentication failure with aToken null");
+                CMS.debug("TPSProcessor.authenticateUser: authentication failure with authToken null");
                 throw new TPSException("TPS error user authentication failed.",
                         TPSStatus.STATUS_ERROR_LOGIN);
             }
@@ -1249,14 +1290,126 @@ public class TPSProcessor {
         CMS.debug(method + ": done for cuid:" + cuid);
     }
 
+    /*
+     * processExternalRegAttrs :
+     * - retrieve from authToken relevant attributes for externalReg
+     * - parse the multi-valued attributes
+     * @returns ExternalRegAttrs
+     */
+    ExternalRegAttrs processExternalRegAttrs(/*IAuthToken authToken,*/String authId) throws EBaseException {
+        String method = "processExternalRegAttrs";
+        String configName;
+        String tVal;
+        String[] vals;
+        ExternalRegAttrs erAttrs = new ExternalRegAttrs(authId);
+        IConfigStore configStore = CMS.getConfigStore();
+
+        CMS.debug(method + ": getting from authToken:"
+                + erAttrs.ldapAttrNameTokenType);
+        vals = authToken.getInStringArray(erAttrs.ldapAttrNameTokenType);
+        if (vals == null) {
+            // get the default externalReg tokenType
+            configName = "externalReg.default.tokenType";
+            tVal = configStore.getString(configName,
+                    "externalRegAddToToken");
+            CMS.debug(method + ": set default tokenType:" + tVal);
+        } else {
+            CMS.debug(method + ": retrieved tokenType:" + vals[0]);
+        }
+        erAttrs.setTokenType(vals[0]);
+
+        CMS.debug(method + ": getting from authToken:"
+                + erAttrs.ldapAttrNameTokenCUID);
+        vals = authToken.getInStringArray(erAttrs.ldapAttrNameTokenCUID);
+        if (vals != null) {
+            CMS.debug(method + ": retrieved cuid:" + vals[0]);
+            erAttrs.setTokenCUID(vals[0]);
+        }
+
+        /*
+         * certs to be recovered for this user
+         *     - multi-valued
+         */
+        CMS.debug(method + ": getting from authToken:"
+                + erAttrs.ldapAttrNameCertsToRecover);
+        vals = authToken.getInStringArray(erAttrs.ldapAttrNameCertsToRecover);
+        if (vals != null) {
+            for (String val : vals) {
+                CMS.debug(method + ": retrieved certsToRecover:" + val);
+                /*
+                 * Each cert is represented as
+                 *    (serial#, caID, keyID, drmID)
+                 * e.g.
+                 *    (1234, ca1, 81, drm1)
+                 *    note: numbers above are in decimal
+                 */
+                String[] items = val.split(",");
+                ExternalRegCertToRecover erCert =
+                        new ExternalRegCertToRecover();
+                for (int i = 0; i < items.length; i++) {
+                    if (i == 0)
+                        erCert.setSerial(new BigInteger(items[i]));
+                    else if (i == 1)
+                        erCert.setCaConn(items[i]);
+                    else if (i == 2)
+                        erCert.setKeyid(new BigInteger(items[i]));
+                    else if (i == 3)
+                        erCert.setKraConn(items[i]);
+                }
+                erAttrs.addCertToRecover(erCert);
+            }
+        }
+
+        /*
+         * certs to be deleted for this user
+         *     - multi-valued
+         * TODO: decide if we need CertsToDelete or not
+         *
+        CMS.debug(method + ": getting from authToken:"
+                + erAttrs.ldapAttrNameCertsToDelete);
+        vals = authToken.getInStringArray(erAttrs.ldapAttrNameCertsToDelete);
+        if (vals != null) {
+            for (String val : vals) {
+                CMS.debug(method + ": retrieved certsToDelete:" + val);
+                
+                //  Each cert is represented as
+                //     (serial#, caID, revokeOnDelete)
+                //  e.g.
+                //     (234, ca1, true)
+                //     note: number above is in decimal
+                 
+                String[] items = val.split(",");
+                ExternalRegCertToDelete erCert =
+                        new ExternalRegCertToDelete();
+                for (int i = 0; i < items.length; i++) {
+                    if (i == 0)
+                        erCert.setSerial(new BigInteger(items[i]));
+                    else if (i == 1)
+                        erCert.setCaConn(items[i]);
+                    else if (i == 2) {
+                        if (items[i].equals("true"))
+                            erCert.setRevoke(true);
+                        else
+                            erCert.setRevoke(false);
+                    }
+                }
+                erAttrs.addCertsToDelete(erCert);
+            }
+        }
+        */
+
+        return erAttrs;
+    }
+
     protected void format(boolean skipAuth) throws TPSException, IOException {
 
+        IConfigStore configStore = CMS.getConfigStore();
+        String configName = null;
         String auditMsg = null;
         String appletVersion = null;
 
         TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
 
-        boolean isExternalReg = false;
         AppletInfo appletInfo = null;
         TokenRecord tokenRecord = null;
         try {
@@ -1306,8 +1459,104 @@ public class TPSProcessor {
         IAuthCredentials userCred =
                 new com.netscape.certsrv.authentication.AuthCredentials();
         if (isExternalReg) {
-            //ToDo, do some external Reg stuff along with authentication
-            tokenType = "externalRegAddToToken";
+            CMS.debug("In TPSProcessor.format isExternalReg: ON");
+            /*
+              need to reach out to the Registration DB (authid)
+              Entire user entry should be retrieved and parsed, if needed
+              The following are retrieved:
+                  externalReg.tokenTypeAttributeName=tokenType
+                  externalReg.certs.recoverAttributeName=certsToRecover
+             */
+            /*
+             * - tokenType id NULL at this point for isExternalReg
+             * - loginRequest cannot be per profile(tokenType) for isExternalReg
+             *   because of the above; now it is per instance:
+             *     "externalReg.format.loginRequest.enable"
+             *     "externalReg.default.tokenType"
+             *   it is not enabled by default.
+             */
+            configName = "externalReg.format.loginRequest.enable";
+            boolean requireLoginRequest;
+            try {
+                requireLoginRequest = configStore.getBoolean(configName, false);
+            } catch (EBaseException e) {
+                CMS.debug("TPSProcessor.format: Internal Error obtaining mandatory config values. Error: " + e);
+                auditMsg = "TPS error getting config values from config store." + e.toString();
+                tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+                        "failure");
+
+                throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+            }
+            if (!requireLoginRequest) {
+                CMS.debug("In TPSProcessor.format: no Login required");
+                // get the default externalReg tokenType
+                configName = "externalReg.default.tokenType";
+                try {
+                    tokenType = configStore.getString(configName,
+                            "externalRegAddToToken");
+                    setSelectedTokenType(tokenType);
+                } catch (EBaseException e) {
+                    CMS.debug("TPSProcessor.format: Internal Error obtaining mandatory config values. Error: " + e);
+                    auditMsg = "TPS error getting config values from config store." + e.toString();
+                    tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+                            "failure");
+
+                    throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+                }
+                CMS.debug("In TPSProcessor.format: isExternalReg: setting tokenType to default first:" +
+                        tokenType);
+            } else {
+                /* get user login and password - set in "login" */
+                CMS.debug("In TPSProcessor.format: isExternalReg: calling requestUserId");
+                configName = "externalReg.authId";
+                String authId;
+                try {
+                    authId = configStore.getString(configName);
+                } catch (EBaseException e) {
+                    CMS.debug("TPSProcessor.format: Internal Error obtaining mandatory config values. Error: " + e);
+                    auditMsg = "TPS error getting config values from config store." + e.toString();
+                    tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+                            "failure");
+
+                    throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+                }
+                try {
+                    TPSAuthenticator userAuth =
+                            getAuthentication(authId);
+
+                    userCred = requestUserId("format", cuid, userAuth, beginMsg.getExtensions());
+                    userid = (String) userCred.get(userAuth.getAuthCredName());
+                    CMS.debug("TPSProcessor.format: isExternalReg: userCred (attempted) userid=" + userid);
+                    tokenRecord.setUserID(userid);
+                    authToken = authenticateUser("format", userAuth, userCred);
+                    userid = authToken.getInString("userid");
+                    tokenRecord.setUserID(userid);
+                    CMS.debug("TPSProcessor.format:: auth token userid=" + userid);
+                } catch (Exception e) {
+                    // all exceptions are considered login failure
+                    CMS.debug("TPSProcessor.format:: authentication exception thrown: " + e);
+                    auditMsg = "authentication failed, status = STATUS_ERROR_LOGIN";
+
+                    tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+                            "failure");
+
+                    throw new TPSException(auditMsg,
+                            TPSStatus.STATUS_ERROR_LOGIN);
+                }
+
+                ExternalRegAttrs erAttrs;
+                try {
+                    erAttrs = processExternalRegAttrs(/*authToken,*/authId);
+                } catch (EBaseException ee) {
+                    auditMsg = "processExternalRegAttrs: " + ee.toString();
+                    tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+                            "failure");
+
+                    throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+                }
+                session.setExternalRegAttrs(erAttrs);
+                setSelectedTokenType(erAttrs.getTokenType());
+            }
         } else {
             CMS.debug("In TPSProcessor.format isExternalReg: OFF");
             /*
@@ -1330,8 +1579,7 @@ public class TPSProcessor {
         // isExternalReg : user already authenticated earlier
         if (!isExternalReg) {
             // authenticate per profile/tokenType configuration
-            String configName = TPSEngine.OP_FORMAT_PREFIX + "." + tokenType + ".auth.enable";
-            IConfigStore configStore = CMS.getConfigStore();
+            configName = TPSEngine.OP_FORMAT_PREFIX + "." + tokenType + ".auth.enable";
             boolean isAuthRequired;
             try {
                 CMS.debug("TPSProcessor.format: getting config: " + configName);
@@ -1354,7 +1602,7 @@ public class TPSProcessor {
                     CMS.debug("TPSProcessor.format: userCred (attempted) userid=" + userid);
                     // initialize userid first for logging purposes in case authentication fails
                     tokenRecord.setUserID(userid);
-                    IAuthToken authToken = authenticateUser("format", userAuth, userCred);
+                    authToken = authenticateUser("format", userAuth, userCred);
                     userid = authToken.getInString("userid");
                     tokenRecord.setUserID(userid);
                     CMS.debug("TPSProcessor.format:: auth token userid=" + userid);
@@ -1373,13 +1621,7 @@ public class TPSProcessor {
             } // TODO: if no auth required, should wipe out existing tokenRecord entry data later?
         }
 
-        /**
-         * TODO:
-         * isExternalReg is not handled beyond this point until decided
-         */
-
         //Now check provided profile
-
         checkProfileStateOK();
 
         if (isTokenPresent) {
@@ -1538,8 +1780,10 @@ public class TPSProcessor {
 
             opDefault = TPSEngine.CFG_DEF_PIN_RESET_PROFILE_RESOLVER;
             opPrefix = TPSEngine.OP_PIN_RESET_PREFIX;
-        } else{
-            throw new TPSException("TPSProcessor.getResolverInstanceName: Invalid operation type, can not calculate resolver instance!",TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+        } else {
+            throw new TPSException(
+                    "TPSProcessor.getResolverInstanceName: Invalid operation type, can not calculate resolver instance!",
+                    TPSStatus.STATUS_ERROR_MISCONFIGURATION);
         }
 
         String config = opPrefix +
@@ -2390,61 +2634,88 @@ public class TPSProcessor {
         return newPin;
     }
 
-    protected String mapPattern(LinkedHashMap<String, String> map, String pattern) throws TPSException {
+    /*
+     * mapPattern maps pattern with $...$ tokens
+     * e.g.
+     * dnpattern=cn=$auth.firstname$.$auth.lastname$,e=$auth.mail$,o=Example Org
+     *   where from ldap,
+     *       value of firstname is John
+     *       value of lastname is Doe
+     *       value of mail is JohnDoe EXAMPLE org
+     *   then the returned value will be:
+     *       John.Doe,e=JohnDoe EXAMPLE org,o=Example Org
+     *
+     * TODO: It could be made more efficient
+     */
+    protected String mapPattern(LinkedHashMap<String, String> map, String inPattern) throws TPSException {
 
-        //Right now only support one pattern to match within pattern: for instance:
-        // "encryption key for $userid$ , not only the one "$userid$" pattern.
+        String result = "";
 
-        String result = null;
-
-        if (pattern == null || map == null) {
+        if (inPattern == null || map == null) {
             throw new TPSException("TPSProcessor.mapPattern: Illegal input paramters!",
                     TPSStatus.STATUS_ERROR_CONTACT_ADMIN);
         }
 
         final char delim = '$';
-        int firstPos = 0;
-        int nextPos = 0;
-        String patternToMap = null;
-        String patternMapped = null;
-
-        firstPos = pattern.indexOf(delim);
-        nextPos = pattern.indexOf(delim, firstPos + 1);
-
-        if ((nextPos - firstPos) <= 1) {
-            return pattern;
-        }
-
-        patternToMap = pattern.substring(firstPos + 1, nextPos);
-
-        CMS.debug("TPSProcessor.mapPattern: patternTo map: " + patternToMap);
-
-        String piece1 = "";
-        if (firstPos >= 1)
-            piece1 = pattern.substring(0, firstPos);
-
-        String piece2 = "";
-        if (nextPos < (pattern.length() - 1))
-            piece2 = pattern.substring(nextPos + 1);
-
-        for (Map.Entry<String, String> entry : map.entrySet()) {
-            String key = entry.getKey();
-
-            String value = entry.getValue();
-            CMS.debug("TPSProcessor.mapPattern: Exposed: key: " + key + " Param: " + value);
-
-            if (key.equals(patternToMap)) {
-                CMS.debug("TPSProcessor.mapPattern: found match: key: " + key + " mapped to: " + value);
-                patternMapped = value;
+        String pattern = inPattern;
+
+        while (true) {
+            String patternToMap = null;
+            int firstPos = 0;
+            int nextPos = 0;
+            CMS.debug("TPSProcessor.mapPattern: pattern =" + pattern);
+            String patternMapped = "";
+            firstPos = pattern.indexOf(delim);
+            if (firstPos == -1) {
+                //no more token
                 break;
             }
+            nextPos = pattern.indexOf(delim, firstPos + 1);
 
-        }
+            if ((nextPos - firstPos) <= 1) {
+                //  return pattern;
+                break; // no more pattern to match
+            }
+
+            patternToMap = pattern.substring(firstPos + 1, nextPos);
+
+            CMS.debug("TPSProcessor.mapPattern: patternTo map: " + patternToMap);
+
+            String piece1 = "";
+            if (firstPos >= 1)
+                piece1 = pattern.substring(0, firstPos);
+
+            String piece2 = "";
+            if (nextPos < (pattern.length() - 1))
+                piece2 = pattern.substring(nextPos + 1);
+
+            for (Map.Entry<String, String> entry : map.entrySet()) {
+                String key = entry.getKey();
 
-        result = piece1 + patternMapped + piece2;
+                String value = entry.getValue();
+                CMS.debug("TPSProcessor.mapPattern: Exposed: key: " + key + " Param: " + value);
 
-        CMS.debug("TPSProcessor.mapPattern: returning: " + result);
-        return result;
+                if (key.equalsIgnoreCase(patternToMap)) {
+                    CMS.debug("TPSProcessor.mapPattern: found match: key: " + key + " mapped to: " + value);
+                    patternMapped = value;
+                    CMS.debug("TPSProcessor.mapPattern: pattern mapped: " + patternMapped);
+                    break;
+                }
+
+            }
+
+            // if patternMapped wasn't mapped, it will be ""
+            result = (piece1 + patternMapped + piece2);
+            pattern = result;
+        }
+
+        if (result.equals("")) {
+            CMS.debug("TPSProcessor.mapPattern: returning: " + inPattern);
+            return (inPattern);
+        } else {
+            CMS.debug("TPSProcessor.mapPattern: returning: " + result);
+            return result;
+        }
 
     }
 
@@ -2540,13 +2811,12 @@ public class TPSProcessor {
 
     protected void checkAndAuthenticateUser(AppletInfo appletInfo, String tokenType) throws TPSException {
         IAuthCredentials userCred;
-        IAuthToken authToken;
         TokenRecord tokenRecord = getTokenRecord();
         String method = "checkAndAuthenticateUser";
 
         String opPrefix = null;
 
-        if(TPSEngine.ENROLL_OP.equals( currentTokenOperation)) {
+        if (TPSEngine.ENROLL_OP.equals(currentTokenOperation)) {
             opPrefix = TPSEngine.OP_ENROLL_PREFIX;
         } else if (TPSEngine.FORMAT_OP.equals(currentTokenOperation)) {
             opPrefix = TPSEngine.OP_FORMAT_PREFIX;
@@ -2554,7 +2824,6 @@ public class TPSProcessor {
             opPrefix = TPSEngine.OP_PIN_RESET_PREFIX;
         }
 
-
         if (!isExternalReg) {
             // authenticate per profile/tokenType configuration
             String configName = opPrefix + "." + tokenType + ".auth.enable";
@@ -2574,8 +2843,6 @@ public class TPSProcessor {
                         TPSStatus.STATUS_ERROR_MISCONFIGURATION);
             }
 
-
-
             CMS.debug(method + ": opPrefox: " + opPrefix);
 
             if (isAuthRequired) {
-- 
1.8.4.2


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]