>From 8710dccf8594eb43612e22da39be94718100aa6a Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu@redhat.com>
Date: Thu, 8 May 2014 10:04:22 -0700
Subject: [PATCH] TPS User Authenticator Framework -
 https://fedorahosted.org/pki/ticket/879

This patch provides the framework that allows people to
1. write their own authentication plugins using the authentication
   plugin framework
2. map the authenticaiton credential from client side (e.g. ESC or alike)
   in both display language characters and numbers of credential parameters
   to the specified authentication plugin required parameters.
---
 .../dogtagpki/tps/msg/ExtendedLoginRequest.java    |   2 +
 .../dogtagpki/tps/msg/ExtendedLoginResponse.java   |  10 +
 .../src/org/dogtagpki/tps/msg/TPSMessage.java      |  10 +
 .../authentication/UidPwdDirAuthentication.java    |   2 +
 base/tps-tomcat/shared/conf/CS.cfg.in              |  11 +
 .../src/org/dogtagpki/server/tps/TPSSubsystem.java |   8 +
 .../server/tps/authentication/AuthUIParameter.java |  86 ++++++
 .../tps/authentication/AuthenticationManager.java  | 269 +++++++++++++++++++
 .../tps/authentication/TPSAuthenticator.java       | 130 +++++++++
 .../server/tps/processor/TPSProcessor.java         | 290 ++++++++++++++++++++-
 10 files changed, 813 insertions(+), 5 deletions(-)
 create mode 100644 base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/AuthUIParameter.java
 create mode 100644 base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/AuthenticationManager.java
 create mode 100644 base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/TPSAuthenticator.java

diff --git a/base/common/src/org/dogtagpki/tps/msg/ExtendedLoginRequest.java b/base/common/src/org/dogtagpki/tps/msg/ExtendedLoginRequest.java
index dbc481688acb93450ba8b6e2c491af9f702cd2bb..77081654ba3729e5df84952244b730841d2cbb0b 100644
--- a/base/common/src/org/dogtagpki/tps/msg/ExtendedLoginRequest.java
+++ b/base/common/src/org/dogtagpki/tps/msg/ExtendedLoginRequest.java
@@ -33,6 +33,8 @@ public class ExtendedLoginRequest extends TPSMessage {
         put(INVALID_PWD_NAME, invalid_pw);
         put(BLOCKED_NAME, blocked);
         put(MSG_TYPE_NAME, msgTypeToInt(MsgType.MSG_EXTENDED_LOGIN_REQUEST));
+        put(TITLE_NAME, title);
+        put (DESCRIPTION_NAME, description);
         this.params = params;
 
     }
diff --git a/base/common/src/org/dogtagpki/tps/msg/ExtendedLoginResponse.java b/base/common/src/org/dogtagpki/tps/msg/ExtendedLoginResponse.java
index 8ae7ad66a74d8d0e7426d9d036d033d30c2c7a92..29e9b72afc20f8ecdfeb4ff337b861db78dddf54 100644
--- a/base/common/src/org/dogtagpki/tps/msg/ExtendedLoginResponse.java
+++ b/base/common/src/org/dogtagpki/tps/msg/ExtendedLoginResponse.java
@@ -32,6 +32,16 @@ public class ExtendedLoginResponse extends TPSMessage {
         //ToDo process the actual params
     }
 
+    public ExtendedLoginResponse(OpType theOp, String uid, String password, Map<String, String> theExtensions) {
+
+        put(OPERATION_TYPE_NAME, opTypeToInt(theOp));
+        put(MSG_TYPE_NAME, msgTypeToInt(MsgType.MSG_EXTENDED_LOGIN_RESPONSE));
+        authParams = theExtensions;
+        put(SCREEN_NAME_NAME, uid);
+        put(PASSWORD_NAME, password);
+
+    }
+
     public static void main(String[] args) {
 
     }
diff --git a/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java b/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java
index c6e7cf7a7482754e2563094c3e42e279ec6a2bb6..39af93c7dcdaeb499a1f0a2ea1bee6a9c11472cc 100644
--- a/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java
+++ b/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java
@@ -69,6 +69,8 @@ public class TPSMessage {
     public static final String SCREEN_NAME_NAME = "screen_name";
     public static final String PASSWORD_NAME = "password";
     public static final String PIN_REQUIRED_NAME = "pin_required";
+    public static final String TITLE_NAME = "title";
+    public static final String DESCRIPTION_NAME = "description";
     public static final String NEXT_VALUE_NAME = "next_value";
     public static final String VALUE_NAME = "value";
     public static final String PIN_NAME = "pin";
@@ -451,10 +453,18 @@ public class TPSMessage {
         case MSG_EXTENDED_LOGIN_REQUEST:
             break;
         case MSG_EXTENDED_LOGIN_RESPONSE:
+            result =
+                new ExtendedLoginResponse(op_val,
+                    get(SCREEN_NAME_NAME),
+                    get(PASSWORD_NAME),
+                    extsMap);
             break;
         case MSG_LOGIN_REQUEST:
             break;
         case MSG_LOGIN_RESPONSE:
+            result =
+                new LoginResponse(get(SCREEN_NAME_NAME),
+                    get(PASSWORD_NAME));
             break;
         case MSG_NEW_PIN_REQUEST:
             break;
diff --git a/base/server/cms/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java
index ffa8ea42fed2b3bb4c31cdcf72ac6488d106d545..85fe19635d48cdde6987247bab9fbc4935658c25 100644
--- a/base/server/cms/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java
+++ b/base/server/cms/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java
@@ -154,9 +154,11 @@ public class UidPwdDirAuthentication extends DirBasedAuthentication
 
             return userdn;
         } catch (ELdapException e) {
+            CMS.debug("Authenticating: User authentication failure: "+e);
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CANNOT_CONNECT_LDAP", e.toString()));
             throw e;
         } catch (LDAPException e) {
+            CMS.debug("Authenticating: User authentication failure: "+e);
             switch (e.getLDAPResultCode()) {
             case LDAPException.NO_SUCH_OBJECT:
             case LDAPException.LDAP_PARTIAL_RESULTS:
diff --git a/base/tps-tomcat/shared/conf/CS.cfg.in b/base/tps-tomcat/shared/conf/CS.cfg.in
index da41e950ab52b0f0f288d6044ea8dfd54aac1e6b..85c71c258e9f150022db6b16ccf54760b92da147 100644
--- a/base/tps-tomcat/shared/conf/CS.cfg.in
+++ b/base/tps-tomcat/shared/conf/CS.cfg.in
@@ -34,6 +34,17 @@ auths.impl.UidPwdPinDirAuth.class=com.netscape.cms.authentication.UidPwdPinDirAu
 auths.instance.AgentCertAuth.agentGroup=Certificate Manager Agents
 auths.instance.AgentCertAuth.pluginName=AgentCertAuth
 auths.instance.TokenAuth.pluginName=TokenAuth
+auths.instance.ldap1.ui.retries=3
+auths.instance.ldap1.ui.title.en=LDAP Authentication
+auths.instance.ldap1.ui.description.en=This authenticates user against the LDAP directory.
+auths.instance.ldap1.ui.id.UID.description.en=LDAP User ID
+auths.instance.ldap1.ui.id.UID.name.en=LDAP User ID
+auths.instance.ldap1.ui.id.UID.credMap.authCred=uid
+auths.instance.ldap1.ui.id.UID.credMap.msgCred=screen_name
+auths.instance.ldap1.ui.id.PASSWORD.description.en=LDAP Password
+auths.instance.ldap1.ui.id.PASSWORD.name.en=LDAP Password
+auths.instance.ldap1.ui.id.PASSWORD.credMap.authCred=pwd
+auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred=password
 auths.instance.ldap1.dnpattern=
 auths.instance.ldap1.ldapByteAttributes=
 auths.instance.ldap1.ldapStringAttributes=mail,cn,uid
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSSubsystem.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSSubsystem.java
index 10920ed9e77f264020811ecb326cd010f342038b..dbaee24da31b8f4e6c6c33a696f2e00ea9d099f3 100644
--- a/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSSubsystem.java
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSSubsystem.java
@@ -17,6 +17,7 @@
 // --- END COPYRIGHT BLOCK ---
 package org.dogtagpki.server.tps;
 
+import org.dogtagpki.server.tps.authentication.AuthenticationManager;
 import org.dogtagpki.server.tps.cms.ConnectionManager;
 import org.dogtagpki.server.tps.config.ConfigDatabase;
 import org.dogtagpki.server.tps.config.ConnectionDatabase;
@@ -66,6 +67,7 @@ public class TPSSubsystem implements IAuthority, ISubsystem {
     public ProfileMappingDatabase profileMappingDatabase;
     public TokenDatabase tokenDatabase;
     public ConnectionManager connManager;
+    public AuthenticationManager authManager;
     public TPSEngine engine;
 
     @Override
@@ -109,6 +111,8 @@ public class TPSSubsystem implements IAuthority, ISubsystem {
         CMS.debug("TPSSubsystem: startup() begins");
         connManager = new ConnectionManager();
         connManager.initConnectors();
+        authManager = new AuthenticationManager();
+        authManager.initAuthInstances();
         CMS.debug("TPSSubsystem: startup() ends.");
     }
 
@@ -189,6 +193,10 @@ public class TPSSubsystem implements IAuthority, ISubsystem {
         return connManager;
     }
 
+    public AuthenticationManager getAuthenticationManager() {
+        return authManager;
+    }
+
     public org.mozilla.jss.crypto.X509Certificate getSubsystemCert() throws EBaseException, NotInitializedException,
             ObjectNotFoundException, TokenException {
         IConfigStore cs = CMS.getConfigStore();
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/AuthUIParameter.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/AuthUIParameter.java
new file mode 100644
index 0000000000000000000000000000000000000000..07678b566723a83af2fbf705ad7f428e02104eed
--- /dev/null
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/AuthUIParameter.java
@@ -0,0 +1,86 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.authentication;
+
+import java.util.Hashtable;
+
+import com.netscape.certsrv.base.EBaseException;
+
+/*
+ * AuthUIParameters is a class for per locale parameter sets
+ *
+ * @author cfu
+ */
+public class AuthUIParameter {
+
+    private String paramId;
+    /*
+     *   auths.instance.<authInst>.ui.id.<param>.name.<locale>=<name>
+     *   auths.instance.<authInst>.ui.id.<param>.description.<locale>=<description>
+     *  e.g.
+     *   auths.instance.ldap1.ui.id.PASSWORD.description.en=LDAP Password
+     *   auths.instance.ldap1.ui.id.PASSWORD.name.en=LDAP Password
+     *   auths.instance.ldap1.ui.id.UID.description.en=LDAP User ID
+     *   auths.instance.ldap1.ui.id.UID.name.en=LDAP User ID
+     *
+     *  for each id param <locale, name>
+     */
+    private Hashtable<String, String> uiParamIdName;
+    private Hashtable<String, String> uiParamIdDescription;
+
+    public AuthUIParameter(String id)
+            throws EBaseException {
+        paramId = id;
+        uiParamIdName = new Hashtable<String, String>();
+        uiParamIdDescription = new Hashtable<String, String>();
+    }
+
+    public void setParamName(String locale, String name) {
+        uiParamIdName.put(locale, name);
+    }
+
+    public String getParamName(String locale) {
+        return uiParamIdName.get(locale);
+    }
+
+    public void setParamDescription(String locale, String desc) {
+        uiParamIdDescription.put(locale, desc);
+    }
+
+    public String getParamDescription(String locale) {
+        return uiParamIdDescription.get(locale);
+    }
+
+    public String toString(String locale) {
+        String name = getParamName(locale);
+        if (name == null)
+            name = getParamName("en");
+
+        String desc = getParamDescription(locale);
+        if (desc == null)
+            desc = getParamDescription("en");
+
+        String string =
+                "id=" + paramId +
+                        "&name=" + name +
+                        "&description=" + desc +
+                        "&type=string" +
+                        "&option=";
+        return string;
+    }
+}
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/AuthenticationManager.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/AuthenticationManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2dc771429d89fa1ef44c8816563c3577991f1cf
--- /dev/null
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/AuthenticationManager.java
@@ -0,0 +1,269 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.authentication;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+
+/**
+ * AuthenticationManager is a class for management of authentication
+ * instances
+ *
+ * @author cfu
+ */
+public class AuthenticationManager
+{
+    private Hashtable<String, TPSAuthenticator> authInstances;
+
+    public AuthenticationManager() {
+    }
+
+    /*
+     * initAuthInstances initializes authentication manager instances
+     *
+     * configuration e.g.
+     *
+     *   auths.instance.ldap1.ui.description.en=This authenticates user against the LDAP directory.
+     *   auths.instance.ldap1.ui.title.en=LDAP Authentication
+     *   auths.instance.ldap1.ui.id.PASSWORD.description.en=LDAP Password
+     *   auths.instance.ldap1.ui.id.PASSWORD.name.en=LDAP Password
+     *   auths.instance.ldap1.ui.id.PASSWORD.credMap.authCred=pwd
+     *   auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred=password
+     *   auths.instance.ldap1.ui.id.UID.description.en=LDAP User ID
+     *   auths.instance.ldap1.ui.id.UID.name.en=LDAP User ID
+     *   auths.instance.ldap1.ui.id.UID.credMap.authCred=uid
+     *   auths.instance.ldap1.ui.id.UID.credMap.msgCred=screen_name
+     *   auths.instance.ldap1.ui.retries=1
+     *
+     *   # the following are handled by the IAuthManager itself
+     *   auths.instance.ldap1.dnpattern=
+     *   auths.instance.ldap1.ldap.basedn=dc=idm,dc=lab,dc=bos,dc=redhat,dc=com
+     *   auths.instance.ldap1.ldap.ldapauth.authtype=BasicAuth
+     *   auths.instance.ldap1.ldap.ldapauth.bindDN=
+     *   auths.instance.ldap1.ldap.ldapauth.bindPWPrompt=ldap1
+     *   auths.instance.ldap1.ldap.ldapauth.clientCertNickname=
+     *   auths.instance.ldap1.ldap.ldapconn.host=vm-060.idm.lab.bos.redhat.com
+     *   auths.instance.ldap1.ldap.ldapconn.port=389
+     *   auths.instance.ldap1.ldap.ldapconn.secureConn=False
+     *   auths.instance.ldap1.ldap.ldapconn.version=3
+     *   auths.instance.ldap1.ldap.maxConns=15
+     *   auths.instance.ldap1.ldap.minConns=3
+     *   auths.instance.ldap1.ldapByteAttributes=
+     *   auths.instance.ldap1.ldapStringAttributes=mail,cn,uid
+     *   auths.instance.ldap1.pluginName=UidPwdDirAuth
+     */
+    public void initAuthInstances() throws EBaseException {
+        CMS.debug("AuthenticationManager: initAuthInstances(): begins.");
+        IConfigStore conf = CMS.getConfigStore();
+        IConfigStore authInstSubstore = conf.getSubStore("auths.instance");
+        Enumeration<String> auth_enu = authInstSubstore.getSubStoreNames();
+        authInstances = new Hashtable<String, TPSAuthenticator>();
+        while (auth_enu.hasMoreElements()) {
+            String authInstID = auth_enu.nextElement();
+            CMS.debug("AuthenticationManager: initAuthInstances(): initializing authentication instance " + authInstID);
+            IConfigStore authInstSub =
+                    authInstSubstore.getSubStore(authInstID);
+            try {
+                TPSAuthenticator authInst =
+                        createAuthentication(authInstSub, authInstID);
+                authInstances.put(authInstID, authInst);
+                CMS.debug("AuthenticationManager: initAuthInstances(): authentication instance "
+                        + authInstID +
+                        " initialized.");
+            } catch (EBaseException e) {
+                CMS.debug("AuthenticationManager: initAuthInstances(): createAuthentication failed on: " + authInstID);
+                continue;
+            }
+        }
+        CMS.debug("AuthenticationManager: initAuthInstances(): ends.");
+    }
+
+    /*
+     * createAuthentication creates and returns an Authenticaiton
+     *
+     * @param conf config store of the authentication instance
+     * @return Authentication the authentication instance
+     */
+    private TPSAuthenticator createAuthentication(IConfigStore conf, String authInstID)
+            throws EBaseException {
+
+        CMS.debug("AuthenticationManager: createAuthentication(): begins for " +
+                authInstID);
+
+        if (conf == null || conf.size() <= 0) {
+            CMS.debug("AuthenticationManager: createAuthentication(): conf null or empty.");
+            throw new EBaseException("called with null config store");
+        }
+
+        TPSAuthenticator auth = new TPSAuthenticator(authInstID);
+
+        IConfigStore uiSub = conf.getSubStore("ui");
+        if (uiSub == null) {
+            CMS.debug("AuthenticationManager: createAuthentication(): conf "
+                    + conf.getName() + ".ui" + " null or empty.");
+            throw new EBaseException("config " + conf.getName() + ".ui" + " not found");
+        }
+
+        // init ui title
+        IConfigStore uiTitleSub = uiSub.getSubStore("title");
+        if (uiTitleSub == null) {
+            CMS.debug("AuthenticationManager: createAuthentication(): conf "
+                    + uiSub.getName() + ".title" + " null or empty.");
+            throw new EBaseException("config " + uiSub.getName() + ".title" + " not found");
+        }
+
+        Enumeration<String> uiTitle_enu = uiTitleSub.getPropertyNames();
+
+        while (uiTitle_enu.hasMoreElements()) {
+            String locale = uiTitle_enu.nextElement();
+            String title = uiTitleSub.getString(locale);
+            if (title == null || title.equals("")) {
+                CMS.debug("AuthenticationManager: createAuthentication(): title for locale "
+                        + locale + " not found");
+                continue;
+            }
+            auth.setUiTitle(locale, title);
+            CMS.debug("AuthenticationManager: createAuthentication(): added title="
+                    + title + ", locale= " + locale);
+        }
+
+        // init ui description
+        IConfigStore uiDescSub = uiSub.getSubStore("description");
+        if (uiDescSub == null) {
+            CMS.debug("AuthenticationManager: createAuthentication(): conf "
+                    + uiSub.getName() + ".description" + " null or empty.");
+            throw new EBaseException("config " + uiSub.getName() + ".description" + " not found");
+        }
+        Enumeration<String> uiDesc_enu = uiDescSub.getPropertyNames();
+
+        while (uiDesc_enu.hasMoreElements()) {
+            String locale = uiDesc_enu.nextElement();
+            String description = uiDescSub.getString(locale);
+            if (description == null || description.equals("")) {
+                CMS.debug("AuthenticationManager: createAuthentication(): description for locale "
+                        + locale + " not found");
+                continue;
+            }
+            auth.setUiDescription(locale, description);
+            CMS.debug("AuthenticationManager: createAuthentication(): added description="
+                    + description + ", locale= " + locale);
+        }
+
+        // init ui parameters
+        IConfigStore uiParamSub = uiSub.getSubStore("id");
+        if (uiParamSub == null) {
+            CMS.debug("AuthenticationManager: createAuthentication(): conf "
+                    + uiSub.getName() + ".id" + " null or empty.");
+            throw new EBaseException("config " + uiSub.getName() + ".id" + " not found");
+        }
+        Enumeration<String> uiParam_enu = uiParamSub.getSubStoreNames();
+        while (uiParam_enu.hasMoreElements()) {
+            String id = uiParam_enu.nextElement();
+            CMS.debug("AuthenticationManager: createAuthentication(): id param=" +
+                    id);
+            IConfigStore idNameSub = uiParamSub.getSubStore(id + ".name");
+            if (idNameSub == null) {
+                CMS.debug("AuthenticationManager: createAuthentication(): conf "
+                        + uiParamSub.getName() + ".name" + " null or empty.");
+                continue;
+            }
+
+            AuthUIParameter up = new AuthUIParameter(id);
+            Enumeration<String> idName_enu = idNameSub.getPropertyNames();
+            while (idName_enu.hasMoreElements()) {
+                String locale = idName_enu.nextElement();
+                String name = idNameSub.getString(locale);
+                if (name == null || name.equals("")) {
+                    CMS.debug("AuthenticationManager: createAuthentication(): name for locale "
+                            + locale + " not found");
+                    continue;
+                }
+                CMS.debug("AuthenticationManager: createAuthentication(): name =" +
+                        name + " for locale " + locale);
+                up.setParamName(locale, name);
+            }
+
+            IConfigStore idDescSub = uiParamSub.getSubStore(id + ".description");
+            if (idDescSub == null) {
+                CMS.debug("AuthenticationManager: createAuthentication(): conf "
+                        + uiParamSub.getName() + ".description" + " null or empty.");
+                continue;
+            }
+            Enumeration<String> idDesc_enu = idDescSub.getPropertyNames();
+            while (idDesc_enu.hasMoreElements()) {
+                String locale = idDesc_enu.nextElement();
+                String desc = idDescSub.getString(locale);
+                if (desc == null || desc.equals("")) {
+                    CMS.debug("AuthenticationManager: createAuthentication(): description for locale "
+                            + locale + " not found");
+                    continue;
+                }
+                CMS.debug("AuthenticationManager: createAuthentication(): desc =" +
+                        desc);
+                up.setParamDescription(locale, desc);
+            }
+
+            auth.setUiParam(id, up);
+            CMS.debug("AuthenticationManager: createAuthentication(): added param="
+                    + id);
+
+            IConfigStore credMapSub = uiParamSub.getSubStore(id + ".credMap");
+            if (credMapSub == null) {
+                CMS.debug("AuthenticationManager: createAuthentication(): conf "
+                        + uiParamSub.getName() + ".credMapsub" + " null or empty.");
+                continue;
+            }
+            String authCred = credMapSub.getString("authCred");
+            if (authCred == null || authCred.equals("")) {
+                CMS.debug("AuthenticationManager: createAuthentication(): conf "
+                        + credMapSub.getName() + ".authCred" + " null or empty.");
+                continue;
+            }
+            String msgCred = credMapSub.getString("msgCred");
+            if (msgCred == null || msgCred.equals("")) {
+                CMS.debug("AuthenticationManager: createAuthentication(): conf "
+                        + credMapSub.getName() + ".msgCred" + " null or empty.");
+                continue;
+            }
+            // map the auth mgr required cred to cred name in request message
+            auth.setCredMap(authCred, msgCred);
+
+            CMS.debug("AuthenticationManager: createAuthentication(): added cred map="
+                    + authCred + ":" + msgCred);
+        }
+
+        Integer retries = uiSub.getInteger("retries", 1);
+        auth.setNumOfRetries(retries.intValue());
+
+        CMS.debug("AuthenticationManager: createAuthentication(): completed for " +
+                authInstID);
+        return auth;
+    }
+
+    /*
+     * gets an established Authentication instance
+     */
+    public TPSAuthenticator getAuthInstance(String id) {
+        return authInstances.get(id);
+    }
+}
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/TPSAuthenticator.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/TPSAuthenticator.java
new file mode 100644
index 0000000000000000000000000000000000000000..d677ed96b91316bfa14e7fd4a3ecf6b68dfe7bf3
--- /dev/null
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/authentication/TPSAuthenticator.java
@@ -0,0 +1,130 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.authentication;
+
+import java.util.Hashtable;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthManager;
+import com.netscape.certsrv.authentication.IAuthSubsystem;
+import com.netscape.certsrv.base.EBaseException;
+
+/**
+ * Authentication is a class for an authentication instance
+ *
+ * @author cfu
+ */
+public class TPSAuthenticator {
+    private String id;
+    private IAuthManager authManager;
+
+    /*
+     *  for auths instance ui <locale, value>
+     *  e.g.
+     *   auths.instance.ldap1.ui.description.en=
+     *       This authenticates user against the LDAP directory.
+     *   auths.instance.ldap1.ui.title.en=LDAP Authentication
+     */
+    private Hashtable<String, String> uiTitle;
+    private Hashtable<String, String> uiDescription;
+
+    private Hashtable<String, AuthUIParameter> uiParameters;
+    /*
+     * credMap is for authentication manager required
+     * credential names (authCred) mapping to the
+     * client message credentail names (msgCred)
+     * e.g.
+     *   auths.instance.ldap1.ui.id.UID.credMap.authCred=uid
+     *   auths.instance.ldap1.ui.id.UID.credMap.msgCred=screen_name
+     *   auths.instance.ldap1.ui.id.PASSWORD.credMap.authCred=pwd
+     *   auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred=password
+     */
+    private Hashtable<String, String> credMap;
+
+    // retries if the user entered the wrong password/securid
+    private int maxLoginRetries = 1;
+
+    /*
+     * Authentication constructor
+     * @param authId authentication instance id
+     */
+    public TPSAuthenticator(String authId)
+            throws EBaseException {
+        id = authId;
+        // retrieves and set authentication manager
+        IAuthSubsystem authSub =
+                (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH);
+        authManager = authSub.getAuthManager(authId);
+        uiTitle = new Hashtable<String, String>();
+        uiDescription = new Hashtable<String, String>();
+        uiParameters = new Hashtable<String, AuthUIParameter>();
+        credMap = new Hashtable<String, String>();
+    }
+
+    public String getID() {
+        return id;
+    }
+
+    public IAuthManager getAuthManager() {
+        return authManager;
+    }
+
+    public void setUiTitle(String locale, String title) {
+        uiTitle.put(locale, title);
+    }
+
+    public String getUiTitle(String locale) {
+        return uiTitle.get(locale);
+    }
+
+    public void setUiDescription(String locale, String desc) {
+        uiDescription.put(locale, desc);
+    }
+
+    public String getUiDescription(String locale) {
+        return uiDescription.get(locale);
+    }
+
+    public void setUiParam(String id, AuthUIParameter up) {
+        uiParameters.put(id, up);
+    }
+
+    public AuthUIParameter getUiParam(String id) {
+        return uiParameters.get(id);
+    }
+
+    public Hashtable<String, AuthUIParameter> getUiParamSet() {
+        return uiParameters;
+    }
+
+    public void setCredMap(String authCred, String msgCred) {
+        credMap.put(authCred, msgCred);
+    }
+
+    public String getCredMap(String authCred) {
+        return credMap.get(authCred);
+    }
+
+    public int getNumOfRetries() {
+        return maxLoginRetries;
+    }
+
+    public void setNumOfRetries(int num) {
+        maxLoginRetries = num;
+    }
+}
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/processor/TPSProcessor.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
index f054b7e6486da649ad3edbe88b6c2d2b69510b42..a7a11cd63a3f0693a4ddb1b866eafbb05b823814 100644
--- a/base/tps-tomcat/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
@@ -21,10 +21,14 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.HashSet;
+import java.util.Hashtable;
 import java.util.Map;
+import java.util.Set;
 
 import org.dogtagpki.server.tps.TPSSession;
 import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.authentication.TPSAuthenticator;
 import org.dogtagpki.server.tps.channel.SecureChannel;
 import org.dogtagpki.server.tps.cms.TKSComputeRandomDataResponse;
 import org.dogtagpki.server.tps.cms.TKSComputeSessionKeyResponse;
@@ -42,13 +46,21 @@ import org.dogtagpki.tps.main.TPSBuffer;
 import org.dogtagpki.tps.main.TPSException;
 import org.dogtagpki.tps.msg.BeginOp;
 import org.dogtagpki.tps.msg.EndOp.TPSStatus;
+import org.dogtagpki.tps.msg.ExtendedLoginRequest;
+import org.dogtagpki.tps.msg.ExtendedLoginResponse;
+import org.dogtagpki.tps.msg.LoginRequest;
+import org.dogtagpki.tps.msg.LoginResponse;
 import org.dogtagpki.tps.msg.StatusUpdateRequest;
+import org.dogtagpki.tps.msg.TPSMessage;
 import org.dogtagpki.tps.msg.TokenPDURequest;
 import org.dogtagpki.tps.msg.TokenPDUResponse;
 import org.mozilla.jss.CryptoManager.NotInitializedException;
 import org.mozilla.jss.pkcs11.PK11SymKey;
 
 import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthCredentials;
+import com.netscape.certsrv.authentication.IAuthManager;
+import com.netscape.certsrv.authentication.IAuthToken;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.EPropertyNotFound;
 import com.netscape.certsrv.base.IConfigStore;
@@ -561,6 +573,238 @@ public class TPSProcessor {
         return contents;
     }
 
+    /**
+     * getAuthentication gets Authentication per configuration
+     *
+     * @param prefix config prefix for tokenType
+     * @param tokenType the tokenType(profile)
+     * @return Authentication
+     */
+    public TPSAuthenticator getAuthentication(String prefix, String tokenType)
+            throws EBaseException {
+        CMS.debug("TPSProcessor.getAuthentication");
+        if (prefix == null || prefix.equals("") || tokenType == null || tokenType.equals("")) {
+            CMS.debug("TPSProcessor.getAuthentication: missing parameters: prefix or tokenType");
+            throw new EBaseException("TPSProcessor.getAuthentication: missing parameters: prefix or tokenType");
+        }
+        IConfigStore configStore = CMS.getConfigStore();
+        String configName = prefix + "." + tokenType + ".auth.id";
+        String authId;
+
+        CMS.debug("TPSProcessor.getAuthentication: getting config: " +
+                configName);
+        authId = configStore.getString(configName);
+
+        TPSSubsystem subsystem =
+                (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+        TPSAuthenticator authInst =
+                subsystem.getAuthenticationManager().getAuthInstance(authId);
+        return authInst;
+    }
+
+    /**
+     * authenticateUser authenticates a user using specified authentication
+     *
+     * @param op "enrollment", "format", or "pinReset" //TODO: for tokendb activity log
+     * @param prefix "op.enroll", "op.format", or "op.pinReset"
+     * @param tokenType the profile name
+     * @param userCred IAuthCredentials obtained from a successful requestUserId call
+     */
+    public void authenticateUser(
+            String op,
+            TPSAuthenticator userAuth,
+            IAuthCredentials userCred)
+            throws EBaseException, TPSException {
+        /**
+         * TODO: isExternalReg is not handled until decision made
+         */
+        CMS.debug("TPSProcessor.authenticateUser");
+        if (op == null || op.equals("") || userAuth == null || userCred == null) {
+            CMS.debug("TPSProcessor.authenticateUser: missing parameter(s): op, userAuth, or userCred");
+            throw new EBaseException("TPSProcessor.getAuthentication: missing parameter(s): op, userAuth, or userCred");
+        }
+        IAuthManager auth = userAuth.getAuthManager();
+
+        try {
+            // Authenticate user
+            IAuthToken aToken = auth.authenticate(userCred);
+            if (aToken != null)
+                CMS.debug("TPSProcessor.authenticateUser: authentication success");
+            else {
+                CMS.debug("TPSProcessor.authenticateUser: authentication failure with aToken null");
+                throw new TPSException("TPS error user authentication failed.",
+                        TPSStatus.STATUS_ERROR_LOGIN);
+            }
+        } catch (Exception e) {
+            CMS.debug("TPSProcessor.authenticateUser: authentication failure:" + e);
+            throw new TPSException("TPS error user authentication failed.",
+                    TPSStatus.STATUS_ERROR_LOGIN);
+        }
+    }
+
+    /**
+     * requestUserId sends message to client to request for user credential
+     * per authentication plugin
+     *
+     * @param op "enrollment", "format", or "pinReset" //TODO: for tokendb activity log
+     * @param cuid token CUID //TODO: for tokendb activity log
+     * @param extensions message extensions
+     * @return IAuthCredentials containing user credential needed for authentication
+     */
+    IAuthCredentials requestUserId(String op, String cuid, TPSAuthenticator auth, Map<String, String> extensions)
+            throws IOException, TPSException, EBaseException {
+        CMS.debug("TPSProcessor.requestUserId");
+        if (op == null || op.equals("") ||
+                cuid == null || cuid.equals("") || auth == null || extensions == null) {
+            CMS.debug("TPSProcessor.requestUserId: missing parameter(s): op, cuid, auth, or extensions");
+            throw new EBaseException("TPSProcessor.requestUserId: missing parameter(s): op, cuid, auth, or extensions");
+        }
+
+        IAuthCredentials login;
+        if (extensions != null &&
+                extensions.get("extendedLoginRequest") != null) {
+            // default locale will be "en"
+            String locale = extensions.get("locale");
+            if (extensions.get("locale") == null) {
+                locale = "en";
+            }
+            // title
+            String title = auth.getUiTitle(locale);
+            if (title==null || title.equals(""))
+                title = auth.getUiTitle("en");
+	    // description
+            String description = auth.getUiDescription(locale);
+            if (description==null || description.equals(""))
+                description = auth.getUiTitle("en");
+            // parameters
+            Hashtable authParamSet = auth.getUiParamSet();
+            Set<String> keys = authParamSet.keySet();
+            Set<String> params = new HashSet<String>();
+            for (String key : keys) {
+                params.add(auth.getUiParam(key).toString(locale));
+                CMS.debug("TPSProcessor.requestUserId: for extendedLoginRequest, added param: " +
+                        auth.getUiParam(key).toString(locale));
+            }
+
+            login = requestExtendedLogin(0 /* invalid_pw */, 0 /* blocked */,
+                    params, title, description, auth);
+        } else {
+            login = requestLogin(0 /* invalid_pw */, 0 /* blocked */, auth);
+        }
+
+        return login;
+    }
+
+    /**
+     * mapCredFromMsgResponse fills up authManager required auth credentials
+     * with mapped values from client
+     * configuration example:
+     *
+     * auths.instance.ldap1.ui.id.UID.credMap.msgCred=screen_name
+     * auths.instance.ldap1.ui.id.UID.credMap.authCred=uid
+     *
+     * auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred=password
+     * auths.instance.ldap1.ui.id.PASSWORD.credMap.authCred=pwd
+     *
+     * @param response the message response to be mapped
+     * @param auth the authentication for mapping consultation
+     * @return IAuthCredentials auth credential for auth manager
+     */
+    public IAuthCredentials mapCredFromMsgResponse(TPSMessage response, TPSAuthenticator auth)
+            throws EBaseException {
+        CMS.debug("TPSProcessor.mapCredFromMsgResponse");
+        if (response == null || auth == null) {
+            CMS.debug("TPSProcessor.mapCredFromMsgResponse: missing parameter(s): response or auth");
+            throw new EBaseException("TPSProcessor.mapCredFromMsgResponse: missing parameter(s): response or auth");
+        }
+        IAuthCredentials login =
+                new com.netscape.certsrv.authentication.AuthCredentials();
+
+        String[] requiredCreds = auth.getAuthManager().getRequiredCreds();
+        for (String cred : requiredCreds) {
+            String name = auth.getCredMap(cred);
+            login.set(cred, response.get(name));
+        }
+
+        return login;
+    }
+
+    /**
+     * Requests login ID and password from user.
+     */
+    public IAuthCredentials requestExtendedLogin(int invalidPW, int blocked,
+            Set<String> parameters,
+            String title,
+            String description,
+            TPSAuthenticator auth)
+            throws IOException, TPSException, EBaseException {
+
+        CMS.debug("TPSProcessor.requestExtendedLogin");
+        if (parameters == null || title == null || title.equals("") ||
+                description == null || description.equals("") || auth == null) {
+            CMS.debug("TPSProcessor.requestExtendedLogin: missing parameter(s): parameters, title, description, or auth");
+            throw new EBaseException(
+                    "TPSProcessor.requestExtendedLogin: missing parameter(s): parameters, title, description, or auth");
+        }
+        ExtendedLoginRequest loginReq =
+                new ExtendedLoginRequest(invalidPW, blocked, parameters, title, description);
+
+        try {
+            session.write(loginReq);
+        } catch (IOException e) {
+            CMS.debug("TPSProcessor.requestExtendedLogin failed WriteMsg: " + e.toString());
+            throw e;
+        }
+        CMS.debug("TPSProcessor.requestExtendedLogin: extendedLoginRequest sent");
+
+        ExtendedLoginResponse loginResp = null;
+        try {
+            loginResp = (ExtendedLoginResponse) session.read();
+        } catch (IOException e) {
+            CMS.debug("TPSProcessor.requestExtendedLogin failed ReadMsg: " + e.toString());
+            throw e;
+        }
+
+        IAuthCredentials login = mapCredFromMsgResponse(loginResp, auth);
+
+        return login;
+    }
+
+    /**
+     * Requests login ID and password from user.
+     */
+    public IAuthCredentials requestLogin(int invalidPW, int blocked,
+            TPSAuthenticator auth)
+            throws IOException, TPSException, EBaseException {
+
+        CMS.debug("TPSProcessor.requestLogin");
+        if (auth == null) {
+            CMS.debug("TPSProcessor.requestLogin: missing parameter(s): parameters, title, description, or auth");
+            throw new EBaseException(
+                    "TPSProcessor.requestLogin: missing parameter(s): parameters, title, description, or auth");
+        }
+        LoginRequest loginReq = new LoginRequest(invalidPW, blocked);
+
+        try {
+            session.write(loginReq);
+        } catch (IOException e) {
+            CMS.debug("TPSProcessor.requestLogin failed WriteMsg: " + e.toString());
+            throw e;
+        }
+        CMS.debug("TPSProcessor.requestLogin: loginRequest sent");
+
+        LoginResponse loginResp = null;
+        try {
+            loginResp = (LoginResponse) session.read();
+        } catch (IOException e) {
+            CMS.debug("TPSProcessor.requestLogin failed ReadMsg: " + e.toString());
+            throw e;
+        }
+
+        IAuthCredentials login = mapCredFromMsgResponse(loginResp, auth);
+        return login;
+    }
+
     protected void format() throws TPSException, IOException {
 
         IConfigStore configStore = CMS.getConfigStore();
@@ -585,7 +829,7 @@ public class TPSProcessor {
                     TPSEngine.CFG_DEF_NETKEY_INSTANCE_AID);
             CMS.debug("In TPS_Processor.Format. CardManagerAID: " + CardManagerAID + " NetKeyAID: " + NetKeyAID);
             this.isExternalReg = configStore.getBoolean(External_Reg_Cfg, false);
-            CMS.debug("In TPS_Processor.Format isExternalReg: " + isExternalReg);
+            CMS.debug("In TPSProcessor.format isExternalReg: " + isExternalReg);
         } catch (EBaseException e1) {
             CMS.debug("TPS_Processor.Format: Internal Error obtaining mandatory config values. Error: " + e1);
             throw new TPSException("TPS error getting config values from config store.",
@@ -638,16 +882,52 @@ public class TPSProcessor {
         CMS.debug("TPSProcessor.format: major_version " + major_version + " minor_version: " + minor_version
                 + " app_major_version: " + app_major_version + " app_minor_version: " + app_minor_version);
 
+        String tokenType;
+        IAuthCredentials userCred;
         if (isExternalReg) {
             //ToDo, do some external Reg stuff along with authentication
+            tokenType = "externalRegAddToToken";
         } else {
-            //ToDo, Do some authentication
+            CMS.debug("In TPSProcessor.format isExternalReg: OFF");
+            tokenType = getTokenType(TPSEngine.OP_FORMAT_PREFIX, major_version, minor_version, cuid, msn,
+                    beginMsg.getExtensions());
+
+            CMS.debug("TPSProcessor.format: calculated tokenType: " + tokenType);
+
         }
 
-        String tokenType = getTokenType(TPSEngine.OP_FORMAT_PREFIX, major_version, minor_version, cuid, msn,
-                beginMsg.getExtensions());
+        // isExternalReg : user already authenticated earlier
+        if (!isExternalReg) {
+            // authenticate per profile/tokenType configuration
+            String configName = TPSEngine.OP_FORMAT_PREFIX + "." + tokenType + ".auth.enable";
+            boolean isAuthRequired;
+            try {
+                CMS.debug("TPSProcessor.format: getting config: " + configName);
+                isAuthRequired = configStore.getBoolean(configName, true);
+            } catch (EBaseException e) {
+                CMS.debug("TPSProcessor.format: Internal Error obtaining mandatory config values. Error: " + e);
+                throw new TPSException("TPS error getting config values from config store.",
+                        TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+            }
+            if (isAuthRequired) {
+                try {
+                    TPSAuthenticator userAuth =
+                            getAuthentication(TPSEngine.OP_FORMAT_PREFIX, tokenType);
+                    userCred = requestUserId("format", cuid, userAuth, beginMsg.getExtensions());
+                    authenticateUser("format", userAuth, userCred);
+                } catch (Exception e) {
+                    // all exceptions are considered login failure
+                    CMS.debug("TPSProcessor.format:: authentication exception thrown: " + e);
+                    throw new TPSException("TPS error user authentication failed.",
+                            TPSStatus.STATUS_ERROR_LOGIN);
+                }
+            }
+        }
 
-        CMS.debug("TPS_Processor.format: calculated tokenType: " + tokenType);
+        /**
+         * TODO:
+         * isExternalReg is not handled beyond this point until decided
+         */
 
         //Now check provided profile
 
-- 
1.8.4.2

