[AAF-21] Initial code import

Change-Id: I63d7d499bbd46f500b5f5a4db966166f613f327a
Signed-off-by: sg481n <sg481n@att.com>
diff --git a/authz-certman/src/main/config/certman.props b/authz-certman/src/main/config/certman.props
new file mode 100644
index 0000000..496d8c3
--- /dev/null
+++ b/authz-certman/src/main/config/certman.props
@@ -0,0 +1,25 @@
+##
+## AUTHZ Certman (authz-certman) Properties
+##
+
+hostname=_HOSTNAME_
+
+## DISCOVERY (DME2) Parameters on the Command Line
+AFT_LATITUDE=_AFT_LATITUDE_
+AFT_LONGITUDE=_AFT_LONGITUDE_
+AFT_ENVIRONMENT=_AFT_ENVIRONMENT_
+DEPLOYED_VERSION=_ARTIFACT_VERSION_
+
+## Pull in common/security properties
+
+cadi_prop_files=_COMMON_DIR_/com.att.aaf.common.props;_COMMON_DIR_/com.att.aaf.props
+
+##DME2 related parameters
+DMEServiceName=service=com.att.authz.certman/version=_MAJOR_VER_._MINOR_VER_._PATCH_VER_/envContext=_ENV_CONTEXT_/routeOffer=_ROUTE_OFFER_
+AFT_DME2_PORT_RANGE=_AUTHZ_CERTMAN_PORT_RANGE_
+
+# Turn on both AAF TAF & LUR 2.0                                                
+aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=_MAJOR_VER_._MINOR_VER_/envContext=_ENV_CONTEXT_/routeOffer=_ROUTE_OFFER_
+
+
+
diff --git a/authz-certman/src/main/config/log4j.properties b/authz-certman/src/main/config/log4j.properties
new file mode 100644
index 0000000..ad853f5
--- /dev/null
+++ b/authz-certman/src/main/config/log4j.properties
@@ -0,0 +1,79 @@
+#-------------------------------------------------------------------------------

+# ============LICENSE_START====================================================

+# * org.onap.aai

+# * ===========================================================================

+# * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+# * Copyright © 2017 Amdocs

+# * ===========================================================================

+# * Licensed under the Apache License, Version 2.0 (the "License");

+# * you may not use this file except in compliance with the License.

+# * You may obtain a copy of the License at

+# * 

+#  *      http://www.apache.org/licenses/LICENSE-2.0

+# * 

+#  * Unless required by applicable law or agreed to in writing, software

+# * distributed under the License is distributed on an "AS IS" BASIS,

+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+# * See the License for the specific language governing permissions and

+# * limitations under the License.

+# * ============LICENSE_END====================================================

+# *

+# * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+# *

+#-------------------------------------------------------------------------------

+###############################################################################

+# Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.

+###############################################################################

+#

+# Licensed to the Apache Software Foundation (ASF) under one

+# or more contributor license agreements.  See the NOTICE file

+# distributed with this work for additional information

+# regarding copyright ownership.  The ASF licenses this file

+# to you under the Apache License, Version 2.0 (the

+# "License"); you may not use this file except in compliance

+# with the License.  You may obtain a copy of the License at

+#

+#     http://www.apache.org/licenses/LICENSE-2.0

+#

+# Unless required by applicable law or agreed to in writing,

+# software distributed under the License is distributed on an

+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+# KIND, either express or implied.  See the License for the

+# specific language governing permissions and limitations

+# under the License.

+#

+log4j.appender.INIT=org.apache.log4j.DailyRollingFileAppender 

+log4j.appender.INIT.File=_LOG_DIR_/${LOG4J_FILENAME_init}

+log4j.appender.INIT.DatePattern='.'yyyy-MM-dd

+#log4j.appender.INIT.MaxFileSize=_MAX_LOG_FILE_SIZE_

+#log4j.appender.INIT.MaxBackupIndex=_MAX_LOG_FILE_BACKUP_COUNT_

+log4j.appender.INIT.layout=org.apache.log4j.PatternLayout 

+log4j.appender.INIT.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSSZ} %m %n

+

+

+log4j.appender.CM=org.apache.log4j.DailyRollingFileAppender 

+log4j.appender.CM.File=_LOG_DIR_/${LOG4J_FILENAME_cm}

+log4j.appender.CM.DatePattern='.'yyyy-MM-dd

+#log4j.appender.CM.MaxFileSize=_MAX_LOG_FILE_SIZE_

+#log4j.appender.CM.MaxBackupIndex=_MAX_LOG_FILE_BACKUP_COUNT_

+log4j.appender.CM.layout=org.apache.log4j.PatternLayout 

+log4j.appender.CM.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSSZ} %p [%c] %m %n

+

+log4j.appender.AUDIT=org.apache.log4j.DailyRollingFileAppender

+log4j.appender.AUDIT.File=_LOG_DIR_/${LOG4J_FILENAME_audit}

+log4j.appender.AUDIT.DatePattern='.'yyyy-MM-dd

+#log4j.appender.AUDIT.MaxFileSize=_MAX_LOG_FILE_SIZE_

+#log4j.appender.AUDIT.MaxBackupIndex=_MAX_LOG_FILE_BACKUP_COUNT_

+log4j.appender.AUDIT.layout=org.apache.log4j.PatternLayout 

+log4j.appender.AUDIT.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSSZ} %m %n

+

+

+# General Apache libraries

+log4j.rootLogger=INFO,CM

+log4j.logger.org.apache=WARN,INIT

+log4j.logger.dme2=WARN,INIT

+log4j.logger.init=INFO,INIT

+log4j.logger.authz=_LOG4J_LEVEL_,CM

+log4j.logger.audit=INFO,AUDIT

+log4j.category.org.jscep=INFO

+

diff --git a/authz-certman/src/main/config/lrm-authz-certman.xml b/authz-certman/src/main/config/lrm-authz-certman.xml
new file mode 100644
index 0000000..689c2db
--- /dev/null
+++ b/authz-certman/src/main/config/lrm-authz-certman.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

+<!--

+  ============LICENSE_START====================================================

+  * org.onap.aai

+  * ===========================================================================

+  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+  * Copyright © 2017 Amdocs

+  * ===========================================================================

+  * Licensed under the Apache License, Version 2.0 (the "License");

+  * you may not use this file except in compliance with the License.

+  * You may obtain a copy of the License at

+  * 

+   *      http://www.apache.org/licenses/LICENSE-2.0

+  * 

+   * Unless required by applicable law or agreed to in writing, software

+  * distributed under the License is distributed on an "AS IS" BASIS,

+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+  * See the License for the specific language governing permissions and

+  * limitations under the License.

+  * ============LICENSE_END====================================================

+  *

+  * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+  *

+-->

+<ns2:ManagedResourceList xmlns:ns2="http://scld.att.com/lrm/util" xmlns="http://scld.att.com/lrm/commontypes" xmlns:ns3="http://scld.att.com/lrm/types">

+    <ns2:ManagedResource>

+        <ResourceDescriptor>

+            <ResourceName>com.att.authz._ARTIFACT_ID_</ResourceName>

+            <ResourceVersion>

+                <Major>_MAJOR_VER_</Major>

+                <Minor>_MINOR_VER_</Minor>

+                <Patch>_PATCH_VER_</Patch>                

+            </ResourceVersion>

+            <RouteOffer>_ROUTE_OFFER_</RouteOffer>

+        </ResourceDescriptor>

+        <ResourceType>Java</ResourceType>

+        <ResourcePath>com.att.authz.cm.service.CertManAPI</ResourcePath>

+        <ResourceProps>

+            <Tag>process.workdir</Tag>

+            <Value>_ROOT_DIR_</Value>

+        </ResourceProps>    	       

+        <ResourceProps>

+            <Tag>jvm.version</Tag>

+            <Value>1.8</Value>

+        </ResourceProps>

+        <ResourceProps>

+            <Tag>jvm.args</Tag>

+            <Value>-DAFT_LATITUDE=_AFT_LATITUDE_ -DAFT_LONGITUDE=_AFT_LONGITUDE_ -DAFT_ENVIRONMENT=_AFT_ENVIRONMENT_ -Dplatform=_SCLD_PLATFORM_ -Dcom.sun.jndi.ldap.connect.pool.maxsize=20  -Dcom.sun.jndi.ldap.connect.pool.prefsize=10 -Dcom.sun.jndi.ldap.connect.pool.timeout=3000 </Value>

+        </ResourceProps>

+        <ResourceProps>

+            <Tag>jvm.classpath</Tag>

+            <Value>_ROOT_DIR_/etc:_ROOT_DIR_/lib/*:</Value>

+        </ResourceProps>

+        <ResourceProps>

+            <Tag>jvm.heap.min</Tag>

+            <Value>1024m</Value>

+        </ResourceProps>

+        <ResourceProps>

+            <Tag>jvm.heap.max</Tag>

+            <Value>2048m</Value>

+        </ResourceProps>

+        <ResourceProps>

+            <Tag>start.class</Tag>

+            <Value>com.att.authz.cm.service.CertManAPI</Value>

+        </ResourceProps>

+        <ResourceProps>

+            <Tag>stdout.redirect</Tag>

+            <Value>_ROOT_DIR_/logs/SystemOut.log</Value>

+        </ResourceProps>

+        <ResourceProps>

+            <Tag>stderr.redirect</Tag>

+            <Value>_ROOT_DIR_/logs/SystemErr.log</Value>

+        </ResourceProps>

+        <ResourceOSID>aft</ResourceOSID>

+        <ResourceStartType>AUTO</ResourceStartType>

+        <ResourceStartPriority>2</ResourceStartPriority>

+		<ResourceMinCount>_RESOURCE_MIN_COUNT_</ResourceMinCount>

+		<ResourceMaxCount>_RESOURCE_MAX_COUNT_</ResourceMaxCount>        

+		<ResourceRegistration>_RESOURCE_REGISTRATION_</ResourceRegistration>

+        <ResourceSWMComponent>com.att.authz:_ARTIFACT_ID_</ResourceSWMComponent>

+        <ResourceSWMComponentVersion>_ARTIFACT_VERSION_</ResourceSWMComponentVersion>

+    </ns2:ManagedResource>

+</ns2:ManagedResourceList>

diff --git a/authz-certman/src/main/java/com/att/authz/cm/api/API_Artifact.java b/authz-certman/src/main/java/com/att/authz/cm/api/API_Artifact.java
new file mode 100644
index 0000000..be41751
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/api/API_Artifact.java
@@ -0,0 +1,130 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.api;

+

+import javax.servlet.http.HttpServletRequest;

+import javax.servlet.http.HttpServletResponse;

+

+import com.att.aft.dme2.internal.jetty.http.HttpStatus;

+import com.att.authz.cm.mapper.Mapper.API;

+import com.att.authz.cm.service.CertManAPI;

+import com.att.authz.cm.service.Code;

+import com.att.authz.env.AuthzTrans;

+import com.att.authz.layer.Result;

+import com.att.cssa.rserv.HttpMethods;

+

+/**

+ * API Deployment Artifact Apis.. using Redirect for mechanism

+ * 

+ *

+ */

+public class API_Artifact {

+	private static final String GET_ARTIFACTS = "Get Artifacts";

+

+	/**

+	 * Normal Init level APIs

+	 * 

+	 * @param cmAPI

+	 * @param facade

+	 * @throws Exception

+	 */

+	public static void init(final CertManAPI cmAPI) throws Exception {

+		cmAPI.route(HttpMethods.POST, "/cert/artifacts", API.ARTIFACTS, new Code(cmAPI,"Create Artifacts") {

+			@Override

+			public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {

+				Result<Void> r = context.createArtifacts(trans, req, resp);

+				if(r.isOK()) {

+					resp.setStatus(HttpStatus.CREATED_201);

+				} else {

+					context.error(trans,resp,r);

+				}

+			}

+		});

+		

+		cmAPI.route(HttpMethods.GET, "/cert/artifacts/:mechid/:machine", API.ARTIFACTS, new Code(cmAPI,GET_ARTIFACTS) {

+			@Override

+			public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {

+				

+				Result<Void> r = context.readArtifacts(trans, resp, pathParam(req,":mechid"), pathParam(req,":machine"));

+				if(r.isOK()) {

+					resp.setStatus(HttpStatus.CREATED_201);

+				} else {

+					context.error(trans,resp,r);

+				}

+			}

+		});

+

+		cmAPI.route(HttpMethods.GET, "/cert/artifacts", API.ARTIFACTS, new Code(cmAPI,GET_ARTIFACTS) {

+			@Override

+			public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {

+				Result<Void> r = context.readArtifacts(trans, req, resp);

+				if(r.isOK()) {

+					resp.setStatus(HttpStatus.CREATED_201);

+				} else {

+					context.error(trans,resp,r);

+				}

+			}

+		});

+

+		cmAPI.route(HttpMethods.PUT, "/cert/artifacts", API.ARTIFACTS, new Code(cmAPI,"Update Artifacts") {

+			@Override

+			public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {

+				Result<Void> r = context.updateArtifacts(trans, req, resp);

+				if(r.isOK()) {

+					resp.setStatus(HttpStatus.OK_200);

+				} else {

+					context.error(trans,resp,r);

+				}

+			}

+		});

+

+		cmAPI.route(HttpMethods.DELETE, "/cert/artifacts/:mechid/:machine", API.VOID, new Code(cmAPI,"Delete Artifacts") {

+			@Override

+			public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {

+				Result<Void> r = context.deleteArtifacts(trans, resp, 

+						pathParam(req, ":mechid"), pathParam(req,":machine"));

+				if(r.isOK()) {

+					resp.setStatus(HttpStatus.OK_200);

+				} else {

+					context.error(trans,resp,r);

+				}

+			}

+		});

+		

+

+		cmAPI.route(HttpMethods.DELETE, "/cert/artifacts", API.VOID, new Code(cmAPI,"Delete Artifacts") {

+			@Override

+			public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {

+				Result<Void> r = context.deleteArtifacts(trans, req, resp);

+				if(r.isOK()) {

+					resp.setStatus(HttpStatus.OK_200);

+				} else {

+					context.error(trans,resp,r);

+				}

+			}

+		});

+		

+

+	}

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/api/API_Cert.java b/authz-certman/src/main/java/com/att/authz/cm/api/API_Cert.java
new file mode 100644
index 0000000..3a7bbe1
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/api/API_Cert.java
@@ -0,0 +1,100 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.api;

+

+import javax.servlet.http.HttpServletRequest;

+import javax.servlet.http.HttpServletResponse;

+

+import com.att.aft.dme2.internal.jetty.http.HttpStatus;

+import com.att.authz.cm.ca.CA;

+import com.att.authz.cm.mapper.Mapper.API;

+import com.att.authz.cm.service.CertManAPI;

+import com.att.authz.cm.service.Code;

+import com.att.authz.env.AuthzTrans;

+import com.att.authz.layer.Result;

+import com.att.cssa.rserv.HttpMethods;

+import com.att.inno.env.Slot;

+import com.att.inno.env.TransStore;

+

+/**

+ * API Apis.. using Redirect for mechanism

+ * 

+ *

+ */

+public class API_Cert {

+	public static final String CERT_AUTH = "CertAuthority";

+	private static Slot sCertAuth;

+

+	/**

+	 * Normal Init level APIs

+	 * 

+	 * @param cmAPI

+	 * @param facade

+	 * @throws Exception

+	 */

+	public static void init(final CertManAPI cmAPI) throws Exception {

+		// Check for Created Certificate Authorities in TRANS

+		sCertAuth = ((TransStore) cmAPI.env).slot(CERT_AUTH);

+		

+		////////

+		// Overall APIs

+		///////

+		cmAPI.route(HttpMethods.PUT,"/cert/:ca",API.CERT_REQ,new Code(cmAPI,"Request Certificate") {

+			@Override

+			public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {

+				String key = pathParam(req, ":ca");

+				CA ca;

+				if((ca = cmAPI.getCA(key))==null) {

+					context.error(trans,resp,Result.ERR_BadData,"CA %s is not supported",key);

+				} else {

+					trans.put(sCertAuth, ca);

+					

+					Result<Void> r = context.requestCert(trans, req, resp, req.getParameter("withTrust")!=null);

+					if(r.isOK()) {

+						resp.setStatus(HttpStatus.OK_200);

+					} else {

+						context.error(trans,resp,r);

+					}

+				}

+			}

+		});

+		

+		/**

+		 * 

+		 */

+		cmAPI.route(HttpMethods.GET, "/cert/may/:perm", API.VOID, new Code(cmAPI,"Check Permission") {

+			@Override

+			public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {

+				Result<Void> r = context.check(trans, resp, pathParam(req,"perm"));

+				if(r.isOK()) {

+					resp.setStatus(HttpStatus.OK_200);

+				} else {

+					trans.checkpoint(r.errorString());

+					context.error(trans,resp,Result.err(Result.ERR_Denied,"%s does not have Permission.",trans.user()));

+				}

+			}

+		});

+

+	}

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/ca/AppCA.java b/authz-certman/src/main/java/com/att/authz/cm/ca/AppCA.java
new file mode 100644
index 0000000..761867d
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/ca/AppCA.java
@@ -0,0 +1,357 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.ca;

+

+import java.io.File;

+import java.io.IOException;

+import java.net.Authenticator;

+import java.net.MalformedURLException;

+import java.net.PasswordAuthentication;

+import java.net.URL;

+import java.security.cert.CertStore;

+import java.security.cert.CertStoreException;

+import java.security.cert.Certificate;

+import java.security.cert.CertificateException;

+import java.security.cert.X509Certificate;

+import java.util.ArrayList;

+import java.util.Collection;

+import java.util.Date;

+import java.util.Iterator;

+import java.util.List;

+

+import org.bouncycastle.operator.OperatorCreationException;

+import org.bouncycastle.pkcs.PKCS10CertificationRequest;

+import org.jscep.client.Client;

+import org.jscep.client.ClientException;

+import org.jscep.client.EnrollmentResponse;

+import org.jscep.client.verification.CertificateVerifier;

+import org.jscep.transaction.TransactionException;

+

+import com.att.authz.cm.cert.BCFactory;

+import com.att.authz.cm.cert.CSRMeta;

+import com.att.authz.cm.cert.StandardFields;

+import com.att.authz.common.Define;

+import com.att.cadi.cm.CertException;

+import com.att.cadi.cm.Factory;

+import com.att.cadi.config.Config;

+import com.att.cadi.routing.GreatCircle;

+import com.att.inno.env.Env;

+import com.att.inno.env.TimeTaken;

+import com.att.inno.env.Trans;

+import com.att.inno.env.util.Split;

+

+public class AppCA extends CA {

+	public static final String CA_PERM_TYPE = Define.ROOT_NS+".ca"; // Permission Type for validation

+	private static final String AAF_DATA_DIR = "aaf_data_dir";

+	private static final String CA_PREFIX = "http://";

+	private static final String CA_POSTFIX="/certsrv/mscep_admin/mscep.dll";

+

+	private final static String MS_PROFILE="1";

+	private static final String CM_TRUST_CAS = "cm_trust_cas";

+	private Clients clients;

+

+	private static class AAFStdFields implements StandardFields {

+		private final String env;

+		public AAFStdFields(Trans trans) throws CertException {

+	 		env = trans.getProperty(Config.AAF_ENV);

+			if(env==null) {

+				throw new CertException(Config.AAF_ENV + " must be set to create Certificates");

+			}

+		}

+		@Override

+		public void set(CSRMeta csr) {

+			// Environment

+			csr.environment(env);

+			// Standard Fields

+			csr.o("ATT Services,Inc.");

+			csr.l("St Louis");

+			csr.st("Missouri");

+			csr.c("US");

+		}

+	}

+

+	public AppCA(final Trans trans, final String name, final String urlstr, final String id, final String pw) throws IOException, CertificateException, CertException {

+ 		super(name,new AAFStdFields(trans), CA_PERM_TYPE);

+		

+		clients = new Clients(trans,urlstr);

+		

+ 		

+		// Set this for NTLM password Microsoft

+		Authenticator.setDefault(new Authenticator() {

+			  public PasswordAuthentication getPasswordAuthentication () {

+		            return new PasswordAuthentication (

+		            		id,

+		             		trans.decryptor().decrypt(pw).toCharArray());

+		        }

+		});

+

+

+

+		try {

+			StringBuilder sb = new StringBuilder("CA Reported Trusted Certificates");

+			List<X509Certificate> trustCerts = new ArrayList<X509Certificate>();

+			for(Client client : clients) {

+				CertStore cs = client.getCaCertificate(MS_PROFILE);

+				

+				Collection<? extends Certificate> cc = cs.getCertificates(null);

+				for(Certificate c : cc) {

+					X509Certificate xc = (X509Certificate)c;

+					// Avoid duplicate Certificates from multiple servers

+					X509Certificate match = null;

+					for(X509Certificate t : trustCerts) {

+						if(t.getSerialNumber().equals(xc.getSerialNumber())) {

+							match = xc;

+							break;

+						}

+					}

+					if(match==null && xc.getSubjectDN().getName().startsWith("CN=ATT ")) {

+						sb.append("\n\t");

+						sb.append(xc.getSubjectDN());

+						sb.append("\n\t\tSerial Number: ");

+						String bi = xc.getSerialNumber().toString(16);

+						for(int i=0;i<bi.length();++i) {

+							if(i>1 && i%2==0) {

+								sb.append(':');

+							}

+							sb.append(bi.charAt(i));

+						}

+						sb.append("\n\t\tIssuer:        ");

+						sb.append(xc.getIssuerDN());

+						sb.append("\n\t\tNot Before:    ");

+						sb.append(xc.getNotBefore());

+						sb.append("\n\t\tNot After:     ");

+						sb.append(xc.getNotAfter());

+						sb.append("\n\t\tSigAlgorithm:  ");

+						sb.append(xc.getSigAlgName());

+						sb.append("\n\t\tType:          ");

+						sb.append(xc.getType());

+						sb.append("\n\t\tVersion:       ");

+						sb.append(xc.getVersion());

+

+						trustCerts.add(xc);

+					}

+				}

+			}

+			trans.init().log(sb);

+			// Add Additional ones from Property

+			String data_dir = trans.getProperty(AAF_DATA_DIR);

+			if(data_dir!=null) {

+				File data = new File(data_dir);

+				if(data.exists()) {

+					String trust_cas = trans.getProperty(CM_TRUST_CAS);

+					byte[] bytes;

+					if(trust_cas!=null) {

+						for(String fname : Split.split(';', trust_cas)) {

+							File crt = new File(data,fname);

+							if(crt.exists()) {

+								bytes = Factory.decode(crt);

+								try {

+									Collection<? extends Certificate> cc = Factory.toX509Certificate(bytes);

+									for(Certificate c : cc) {

+										trustCerts.add((X509Certificate)c);

+									}

+								} catch (CertificateException e) {

+									throw new CertException(e);

+								}

+							}

+						}

+					}

+				}

+			}

+			

+			String[] trustChain = new String[trustCerts.size()];

+			int i=-1;

+			for( Certificate cert : trustCerts) {

+				trustChain[++i]=BCFactory.toString(trans,cert);

+			}

+			

+			setTrustChain(trustChain);

+		} catch (ClientException | CertStoreException e) {

+			// Note:  Cannot validly start without all Clients, because we need to read all Issuing Certificates

+			// This is acceptable risk for most things, as we're not real time in general

+			throw new CertException(e);

+		}

+	}

+

+

+	@Override

+	public X509Certificate sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException {

+		TimeTaken tt = trans.start("Generating CSR and Keys for New Certificate", Env.SUB);

+		PKCS10CertificationRequest csr;

+		try {

+			csr = csrmeta.generateCSR(trans);

+			if(trans.info().isLoggable()) {

+				trans.info().log(BCFactory.toString(trans, csr));

+			} 

+			if(trans.info().isLoggable()) {

+				trans.info().log(csr);

+			}

+		} finally {

+			tt.done();

+		}

+		

+		tt = trans.start("Enroll CSR", Env.SUB);

+		Client client = null;

+		try {

+			client = clients.best();

+			EnrollmentResponse er = client.enrol(

+					csrmeta.initialConversationCert(trans),

+					csrmeta.keypair(trans).getPrivate(),

+					csr,

+					MS_PROFILE /* profile... MS can't deal with blanks*/);

+			while(true) {

+				if(er.isSuccess()) {

+					for( Certificate cert : er.getCertStore().getCertificates(null)) {

+						return (X509Certificate)cert;

+					}

+					break;

+				} else if (er.isPending()) {

+					trans.checkpoint("Polling, waiting on CA to complete");

+					Thread.sleep(3000);

+				} else if (er.isFailure()) {

+					throw new CertException(er.getFailInfo().toString());

+				}

+			}

+		} catch (ClientException e) {

+			trans.error().log(e,"SCEP Client Error, Temporarily Invalidating Client");

+			if(client!=null) {

+				clients.invalidate(client);

+			}

+		} catch (InterruptedException|TransactionException|CertificateException|OperatorCreationException | CertStoreException e) {

+			trans.error().log(e);

+		} finally {

+			tt.done();

+		}

+		

+		return null;

+	}

+

+

+	private class Clients implements Iterable<Client>{

+		/**

+		 * CSO Servers are in Dallas and St Louis

+		 * GEO_LOCATION   LATITUDE    LONGITUDE    ZIPCODE   TIMEZONE

+		 * ------------   --------    ---------    -------   --------

+		 * DLLSTXCF       32.779295   -96.800014   75202     America/Chicago

+		 * STLSMORC       38.627345   -90.193774   63101     America/Chicago

+		 * 

+		 * The online production issuing CA servers are:

+		 * 	AAF - CADI Issuing CA 01	135.41.45.152	MOSTLS1AAFXXA02

+		 * 	AAF - CADI Issuing CA 02	135.31.72.154	TXDLLS2AAFXXA02

+		 */

+		

+		private final Client[] client;

+		private final Date[] failure;

+		private int preferred;

+

+		public Clients(Trans trans, String urlstr) throws MalformedURLException { 

+	 		String[] urlstrs = Split.split(',', urlstr);

+	 		client = new Client[urlstrs.length];

+	 		failure = new Date[urlstrs.length];

+	 		double distance = Double.MAX_VALUE;

+	 		String localLat = trans.getProperty("AFT_LATITUDE","39.833333"); //Note: Defaulting to GEO center of US

+	 		String localLong = trans.getProperty("AFT_LONGITUDE","-98.583333");

+	 		for(int i=0;i<urlstrs.length;++i) {

+	 			String[] info = Split.split('/', urlstrs[i]);

+	 			if(info.length<3) {

+	 				throw new MalformedURLException("Configuration needs LAT and LONG, i.e. ip:port/lat/long");

+	 			}

+	 			client[i] = new Client(new URL(CA_PREFIX + info[0] + CA_POSTFIX), 

+		 			new CertificateVerifier() {

+		 				@Override

+		 				public boolean verify(X509Certificate cert) {

+		 					return true;

+		 				}

+		 			}

+	 			);

+	 			double d = GreatCircle.calc(info[1],info[2],localLat,localLong);

+	 			if(d<distance) {

+	 				preferred = i;

+	 				distance=d;

+	 			}

+	 		}

+	 		trans.init().printf("Preferred Certificate Authority is %s",urlstrs[preferred]);

+	 		for(int i=0;i<urlstrs.length;++i) {

+	 			if(i!=preferred) {

+	 				trans.init().printf("Alternate Certificate Authority is %s",urlstrs[i]);

+	 			}

+	 		}

+		}

+		private Client best() throws ClientException {

+			if(failure[preferred]==null) {

+				return client[preferred];

+			} else {

+				Client c=null;

+				// See if Alternate available

+				for(int i=0;i<failure.length;++i) {

+					if(failure[i]==null) {

+						c=client[i];

+					}

+				}

+				

+				// If not, see if any expirations can be cleared

+				Date now = new Date();

+				for(int i=0;i<failure.length;++i) {

+					if(now.after(failure[i])) {

+						failure[i]=null;

+						if(c==null) {

+							c=client[i];

+						}

+					}

+				}

+				

+				// if still nothing found, then throw.

+				if(c==null) {

+					throw new ClientException("No available machines to call");

+				} 

+				return c;

+			}

+		}

+		

+		public void invalidate(Client clt) {

+		   for(int i=0;i<client.length;++i) {

+			   if(client[i].equals(clt)) {

+				   failure[i]=new Date(System.currentTimeMillis()+180000 /* 3 mins */);

+			   }

+		   }

+		}

+		

+		@Override

+		public Iterator<Client> iterator() {

+			return new Iterator<Client>() {

+				private int iter = 0;

+				@Override

+				public boolean hasNext() {

+					return iter < Clients.this.client.length;

+				}

+

+				@Override

+				public Client next() {

+					return Clients.this.client[iter++];

+				}

+				

+			};

+		}

+	}

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/ca/CA.java b/authz-certman/src/main/java/com/att/authz/cm/ca/CA.java
new file mode 100644
index 0000000..fab8994
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/ca/CA.java
@@ -0,0 +1,84 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.ca;

+

+import java.io.IOException;

+import java.security.MessageDigest;

+import java.security.cert.X509Certificate;

+

+import com.att.authz.cm.cert.CSRMeta;

+import com.att.authz.cm.cert.StandardFields;

+import com.att.cadi.cm.CertException;

+import com.att.inno.env.Trans;

+

+public abstract class CA {

+	private final String name;

+	private String[] trustChain;

+	private final StandardFields stdFields;

+	private MessageDigest messageDigest;

+	private final String permType;

+	

+	protected CA(String name, StandardFields sf, String permType) {

+		this.name = name;

+		stdFields = sf;

+		this.permType = permType;

+	}

+

+	/* 

+	 * NOTE: These two functions must be called in Protected Constructors during their Construction.

+	 */

+	protected void setTrustChain(String[] trustChain) {

+		this.trustChain = trustChain;

+	}

+

+	protected void setMessageDigest(MessageDigest md) {

+		messageDigest = md;

+	}

+

+	/*

+	 * End Required Constructor calls

+	 */

+

+	public String getName() {

+		return name;

+	}

+

+	public String[] getTrustChain() {

+		return trustChain;

+	}

+	

+	public String getPermType() {

+		return permType;

+	}

+	

+	public StandardFields stdFields() {

+		return stdFields;

+	}

+	

+	public abstract X509Certificate sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException;

+

+	public MessageDigest messageDigest() {

+		return messageDigest;

+	}

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/ca/DevlCA.java b/authz-certman/src/main/java/com/att/authz/cm/ca/DevlCA.java
new file mode 100644
index 0000000..bc999f2
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/ca/DevlCA.java
@@ -0,0 +1,227 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.ca;

+

+import java.io.File;

+import java.io.IOException;

+import java.math.BigInteger;

+import java.security.GeneralSecurityException;

+import java.security.KeyFactory;

+import java.security.cert.Certificate;

+import java.security.cert.CertificateException;

+import java.security.cert.X509Certificate;

+import java.security.interfaces.RSAPrivateKey;

+import java.security.spec.PKCS8EncodedKeySpec;

+import java.util.ArrayList;

+import java.util.Collection;

+import java.util.Date;

+import java.util.GregorianCalendar;

+import java.util.List;

+import java.security.SecureRandom;

+

+import org.bouncycastle.asn1.ASN1Sequence;

+import org.bouncycastle.asn1.x500.X500Name;

+import org.bouncycastle.asn1.x500.X500NameBuilder;

+import org.bouncycastle.asn1.x500.style.BCStyle;

+import org.bouncycastle.asn1.x509.BasicConstraints;

+import org.bouncycastle.asn1.x509.ExtendedKeyUsage;

+import org.bouncycastle.asn1.x509.Extension;

+import org.bouncycastle.asn1.x509.GeneralName;

+import org.bouncycastle.asn1.x509.GeneralNames;

+import org.bouncycastle.asn1.x509.KeyPurposeId;

+import org.bouncycastle.asn1.x509.KeyUsage;

+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;

+import org.bouncycastle.cert.X509v3CertificateBuilder;

+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;

+import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;

+import org.bouncycastle.operator.OperatorCreationException;

+

+import com.att.authz.cm.cert.BCFactory;

+import com.att.authz.cm.cert.CSRMeta;

+import com.att.authz.cm.cert.StandardFields;

+import com.att.authz.common.Define;

+import com.att.cadi.cm.CertException;

+import com.att.cadi.cm.Factory;

+import com.att.inno.env.Env;

+import com.att.inno.env.TimeTaken;

+import com.att.inno.env.Trans;

+

+public class DevlCA extends CA {

+	

+	// Extensions

+	private static final KeyPurposeId[] ASN_WebUsage = new KeyPurposeId[] {

+				KeyPurposeId.id_kp_serverAuth, // WebServer

+				KeyPurposeId.id_kp_clientAuth};// WebClient

+				

+	private X509Certificate caCert;

+	private final RSAPrivateKey caKey;

+	private final X500Name issuer;

+	private final SecureRandom random = new SecureRandom();

+	private byte[] serialish = new byte[24];

+

+	public DevlCA(Trans trans, String name, String dirString) throws IOException, CertException {

+		super(name, new StandardFields() {

+			@Override

+			public void set(CSRMeta csr) {

+				// Standard Fields

+				csr.o("ATT Services, Inc.");

+				csr.l("St Louis");

+				csr.st("Missouri");

+				csr.c("US");

+			}

+		}, Define.ROOT_NS+".ca" // Permission Type for validation

+		);

+		File dir = new File(dirString);

+		if(!dir.exists()) {

+			throw new CertException(dirString + " does not exist");

+		}

+		

+		File ca = new File(dir,"ca.crt");

+		if(ca.exists()) {

+			byte[] bytes = Factory.decode(ca);

+			Collection<? extends Certificate> certs;

+			try {

+				certs = Factory.toX509Certificate(bytes);

+			} catch (CertificateException e) {

+				throw new CertException(e);

+			}

+			List<String> lTrust = new ArrayList<String>();

+			caCert=null;

+			for(Certificate c : certs) {

+				if(caCert==null) {

+					caCert = (X509Certificate)c;

+				} else {

+					lTrust.add(Factory.toString(trans,c));

+				}

+				break;

+			}

+		}

+		

+		this.setTrustChain(new String[]{Factory.toString(trans,caCert)});

+				

+			/*

+			 * Private key needs to be converted to "DER" format, with no password.  

+			 * 	Use chmod 400 on key

+			 * 

+			 *  openssl pkcs8 -topk8 -outform DER -nocrypt -in ca.key -out ca.der

+			 *

+			 */

+			ca = new File(dir,"ca.der");

+			if(ca.exists()) {

+				byte[] bytes = Factory.binary(ca);

+				

+//					EncryptedPrivateKeyInfo ekey=new EncryptedPrivateKeyInfo(bytes);

+//				    Cipher cip=Cipher.getInstance(ekey.getAlgName());

+//				    PBEKeySpec pspec=new PBEKeySpec("password".toCharArray());

+//				    SecretKeyFactory skfac=SecretKeyFactory.getInstance(ekey.getAlgName());

+//				    Key pbeKey=skfac.generateSecret(pspec);

+//				    AlgorithmParameters algParams=ekey.getAlgParameters();

+//				    cip.init(Cipher.DECRYPT_MODE,pbeKey,algParams);

+					

+				KeyFactory keyFactory;

+				try {

+					keyFactory = KeyFactory.getInstance("RSA");

+					PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(bytes);

+						

+		            caKey = (RSAPrivateKey) keyFactory.generatePrivate(privSpec);

+				} catch (GeneralSecurityException e) {

+					throw new CertException(e);

+				}

+				

+				X500NameBuilder xnb = new X500NameBuilder();

+				xnb.addRDN(BCStyle.C,"US");

+				xnb.addRDN(BCStyle.ST,"Missouri");

+				xnb.addRDN(BCStyle.L,"Arnold");

+				xnb.addRDN(BCStyle.O,"ATT Services, Inc.");

+				xnb.addRDN(BCStyle.OU,"AAF");

+				xnb.addRDN(BCStyle.CN,"aaf.att.com");

+				xnb.addRDN(BCStyle.EmailAddress,"DL-aaf-support@att.com");

+				issuer = xnb.build();

+		} else {

+			throw new CertException(ca.getPath() + " does not exist");

+		}

+	}

+

+	/* (non-Javadoc)

+	 * @see com.att.authz.cm.service.CA#sign(org.bouncycastle.pkcs.PKCS10CertificationRequest)

+	 */

+	@Override

+	public X509Certificate sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException {

+		GregorianCalendar gc = new GregorianCalendar();

+		Date start = gc.getTime();

+		gc.add(GregorianCalendar.DAY_OF_MONTH, 1);

+		Date end = gc.getTime();

+		X509Certificate x509;

+		TimeTaken tt = trans.start("Create/Sign Cert",Env.SUB);

+		try {

+			BigInteger bi;

+			synchronized(serialish) {

+				random.nextBytes(serialish);

+				bi = new BigInteger(serialish);

+			}

+				

+			X509v3CertificateBuilder xcb = new X509v3CertificateBuilder(

+					issuer,

+					bi, // replace with Serialnumber scheme

+					start,

+					end,

+					csrmeta.x500Name(),

+//					SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(caCert.getPublicKey().getEn)

+					new SubjectPublicKeyInfo(ASN1Sequence.getInstance(caCert.getPublicKey().getEncoded()))

+					);

+			List<GeneralName> lsan = new ArrayList<GeneralName>();

+			for(String s : csrmeta.sans()) {

+				lsan.add(new GeneralName(GeneralName.dNSName,s));

+			}

+			GeneralName[] sans = new GeneralName[lsan.size()];

+			lsan.toArray(sans);

+

+		    JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

+		    xcb		.addExtension(Extension.basicConstraints,

+                    	false, new BasicConstraints(false))

+		            .addExtension(Extension.keyUsage,

+		                true, new KeyUsage(KeyUsage.digitalSignature

+		                                 | KeyUsage.keyEncipherment))

+		            .addExtension(Extension.extendedKeyUsage,

+		                          true, new ExtendedKeyUsage(ASN_WebUsage))

+

+                    .addExtension(Extension.authorityKeyIdentifier,

+		                          false, extUtils.createAuthorityKeyIdentifier(caCert))

+		            .addExtension(Extension.subjectKeyIdentifier,

+		                          false, extUtils.createSubjectKeyIdentifier(caCert.getPublicKey()))

+		            .addExtension(Extension.subjectAlternativeName,

+		            		false, new GeneralNames(sans))

+		                                           ;

+	

+			x509 = new JcaX509CertificateConverter().getCertificate(

+					xcb.build(BCFactory.contentSigner(caKey)));

+		} catch (GeneralSecurityException|OperatorCreationException e) {

+			throw new CertException(e);

+		} finally {

+			tt.done();

+		}

+		return x509;

+	}

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/cert/BCFactory.java b/authz-certman/src/main/java/com/att/authz/cm/cert/BCFactory.java
new file mode 100644
index 0000000..52621e5
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/cert/BCFactory.java
@@ -0,0 +1,169 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.cert;

+

+import java.io.File;

+import java.io.FileReader;

+import java.io.IOException;

+import java.lang.reflect.Field;

+import java.security.InvalidKeyException;

+import java.security.NoSuchAlgorithmException;

+import java.security.PrivateKey;

+import java.security.SignatureException;

+import java.util.List;

+

+import org.bouncycastle.asn1.ASN1Object;

+import org.bouncycastle.operator.ContentSigner;

+import org.bouncycastle.operator.OperatorCreationException;

+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

+import org.bouncycastle.pkcs.PKCS10CertificationRequest;

+

+import com.att.authz.cm.ca.CA;

+import com.att.authz.cm.validation.Validator;

+import com.att.cadi.Symm;

+import com.att.cadi.cm.CertException;

+import com.att.cadi.cm.Factory;

+import com.att.inno.env.Env;

+import com.att.inno.env.TimeTaken;

+import com.att.inno.env.Trans;

+

+

+/**

+ * Additional Factory mechanisms for CSRs, and BouncyCastle.  The main Factory

+ * utilizes only Java abstractions, and is useful in Client code.

+ * 

+

+ *

+ */

+public class BCFactory extends Factory {

+	private static final JcaContentSignerBuilder jcsb;

+

+

+	static {

+		// Bouncy

+		jcsb = new JcaContentSignerBuilder(Factory.SIG_ALGO);

+	}

+	

+	public static ContentSigner contentSigner(PrivateKey pk) throws OperatorCreationException {

+		return jcsb.build(pk);

+	}

+	

+	public static String toString(Trans trans, PKCS10CertificationRequest csr) throws IOException, CertException {

+		TimeTaken tt = trans.start("CSR to String", Env.SUB);

+		try {

+			if(csr==null) {

+				throw new CertException("x509 Certificate Request not built");

+			}

+			return textBuilder("CERTIFICATE REQUEST",csr.getEncoded());

+		}finally {

+			tt.done();

+		}

+	}

+

+	public static PKCS10CertificationRequest toCSR(Trans trans, File file) throws IOException {

+		TimeTaken tt = trans.start("Reconstitute CSR", Env.SUB);

+		try {

+			FileReader fr = new FileReader(file);

+			return new PKCS10CertificationRequest(decode(strip(fr)));

+		} finally {

+			tt.done();

+		}

+	}

+

+	public static byte[] sign(Trans trans, ASN1Object toSign, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {

+		TimeTaken tt = trans.start("Encode Security Object", Env.SUB);

+		try {

+			return sign(trans,toSign.getEncoded(),pk);

+		} finally {

+			tt.done();

+		}

+	}

+

+	public static CSRMeta createCSRMeta(CA ca,final String args[]) throws IllegalArgumentException, IllegalAccessException, CertException {

+		CSRMeta csr = new CSRMeta();

+		ca.stdFields().set(csr);

+		//TODO should we checkDigest?

+//		digest = ca.messageDigest();

+

+		Field[] fld = CSRMeta.class.getDeclaredFields();

+		for(int i=0;i+1<args.length;++i) {

+			if(args[i].charAt(0)=='-') {

+				for(int j=0;j<fld.length;++j) {

+					if(fld[j].getType().equals(String.class) && args[i].substring(1).equals(fld[j].getName())) {

+						fld[j].set(csr,args[++i]);

+						break;

+					}

+				}

+			}

+		}

+		String errs = validate(csr);

+		if(errs!=null) {

+			throw new CertException(errs);

+		}

+		return csr;

+	}

+	

+	

+	public static CSRMeta createCSRMeta(CA ca, String mechid, String sponsorEmail, List<String> fqdns) throws CertException {

+		CSRMeta csr = new CSRMeta();

+		boolean first = true;

+		// Set CN (and SAN)

+		for(String fqdn : fqdns) {

+			if(first) {

+				first = false;

+				csr.cn(fqdn);

+			} else {

+				csr.san(fqdn);

+			}

+		}

+		

+		csr.challenge(new String(Symm.randomGen(24)));

+		ca.stdFields().set(csr);

+		csr.mechID(mechid);

+		csr.email(sponsorEmail);

+		String errs = validate(csr);

+		if(errs!=null) {

+			throw new CertException(errs);

+		}

+		return csr;

+	}

+

+	private static String validate(CSRMeta csr) {

+		Validator v = new Validator();

+		if(v.nullOrBlank("cn", csr.cn())

+			.nullOrBlank("mechID", csr.mechID())

+			.nullOrBlank("email", csr.email())

+			.nullOrBlank("o",csr.o())

+			.nullOrBlank("l",csr.l())

+			.nullOrBlank("st",csr.st())

+			.nullOrBlank("c",csr.c())

+			.err()) {

+			return v.errs();

+		} else {

+			return null;

+		}

+	}

+	

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/cert/CSRMeta.java b/authz-certman/src/main/java/com/att/authz/cm/cert/CSRMeta.java
new file mode 100644
index 0000000..91168dc
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/cert/CSRMeta.java
@@ -0,0 +1,330 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.cert;

+

+import java.io.IOException;

+import java.math.BigInteger;

+import java.security.KeyPair;

+import java.security.SecureRandom;

+import java.security.cert.CertificateException;

+import java.security.cert.X509Certificate;

+import java.util.ArrayList;

+import java.util.Date;

+import java.util.GregorianCalendar;

+import java.util.List;

+

+import org.bouncycastle.asn1.ASN1Sequence;

+import org.bouncycastle.asn1.DERPrintableString;

+import org.bouncycastle.asn1.pkcs.Attribute;

+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;

+import org.bouncycastle.asn1.x500.X500Name;

+import org.bouncycastle.asn1.x500.X500NameBuilder;

+import org.bouncycastle.asn1.x500.style.BCStyle;

+import org.bouncycastle.asn1.x509.Extension;

+import org.bouncycastle.asn1.x509.Extensions;

+import org.bouncycastle.asn1.x509.GeneralName;

+import org.bouncycastle.asn1.x509.GeneralNames;

+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;

+import org.bouncycastle.cert.X509v3CertificateBuilder;

+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;

+import org.bouncycastle.operator.OperatorCreationException;

+import org.bouncycastle.pkcs.PKCS10CertificationRequest;

+import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;

+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;

+

+import com.att.cadi.cm.CertException;

+import com.att.cadi.cm.Factory;

+import com.att.inno.env.Trans;

+

+public class CSRMeta {

+	private String environment;

+	private String cn;

+	private String mechID;

+	private String email;

+	private String o;

+	private String l;

+	private String st;

+	private String c;

+	private String challenge;

+	

+	private ArrayList<String> sanList = new ArrayList<String>();

+

+	private KeyPair keyPair;

+	private X500Name name = null;

+	private SecureRandom random = new SecureRandom();

+

+	public X500Name x500Name() throws IOException {

+		if(name==null) {

+			X500NameBuilder xnb = new X500NameBuilder();

+			xnb.addRDN(BCStyle.CN,cn);

+			xnb.addRDN(BCStyle.E,email);

+			if(environment==null) {

+				xnb.addRDN(BCStyle.OU,mechID);

+			} else {

+				xnb.addRDN(BCStyle.OU,mechID+':'+environment);

+			}

+			xnb.addRDN(BCStyle.O,o);

+			xnb.addRDN(BCStyle.L,l);

+			xnb.addRDN(BCStyle.ST,st);

+			xnb.addRDN(BCStyle.C,c);

+			name = xnb.build();

+		}

+		return name;

+	}

+	

+	

+	public PKCS10CertificationRequest  generateCSR(Trans trans) throws IOException, CertException {

+		PKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(x500Name(),keypair(trans).getPublic());

+		if(challenge!=null) {

+			DERPrintableString password = new DERPrintableString(challenge);

+			builder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_challengePassword, password);

+		}

+		

+		if(sanList.size()>0) {

+			GeneralName[] gna = new GeneralName[sanList.size()];

+			int i=-1;

+			for(String s : sanList) {

+				gna[++i]=new GeneralName(GeneralName.dNSName,s);

+			}

+			

+			builder.addAttribute(

+					PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,

+					new Extensions(new Extension[] {

+							new Extension(Extension.subjectAlternativeName,false,new GeneralNames(gna).getEncoded())

+					})

+			);

+		}

+//		builder.addAttribute(Extension.basicConstraints,new BasicConstraints(false))

+//      .addAttribute(Extension.keyUsage, new KeyUsage(KeyUsage.digitalSignature

+//                           | KeyUsage.keyEncipherment));

+		try {

+			return builder.build(BCFactory.contentSigner(keypair(trans).getPrivate()));

+		} catch (OperatorCreationException e) {

+			throw new CertException(e);

+		}

+	}

+	

+	@SuppressWarnings("deprecation")

+	public static void dump(PKCS10CertificationRequest csr) {

+		 Attribute[] certAttributes = csr.getAttributes();

+		 for (Attribute attribute : certAttributes) {

+		     if (attribute.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest)) {

+		         Extensions extensions = Extensions.getInstance(attribute.getAttrValues().getObjectAt(0));

+//		         Extension ext = extensions.getExtension(Extension.subjectAlternativeName);

+		         GeneralNames gns = GeneralNames.fromExtensions(extensions,Extension.subjectAlternativeName);

+		         GeneralName[] names = gns.getNames();

+		         for(int k=0; k < names.length; k++) {

+		             String title = "";

+		             if(names[k].getTagNo() == GeneralName.dNSName) {

+		                 title = "dNSName";

+		             }

+		             else if(names[k].getTagNo() == GeneralName.iPAddress) {

+		                 title = "iPAddress";

+		                 // Deprecated, but I don't see anything better to use.

+		                 names[k].toASN1Object();

+		             }

+		             else if(names[k].getTagNo() == GeneralName.otherName) {

+		                 title = "otherName";

+		             }

+		             System.out.println(title + ": "+ names[k].getName());

+		         } 

+		     }

+		 }

+	}

+	

+	public X509Certificate initialConversationCert(Trans trans) throws IOException, CertificateException, OperatorCreationException {

+		GregorianCalendar gc = new GregorianCalendar();

+		Date start = gc.getTime();

+		gc.add(GregorianCalendar.DAY_OF_MONTH,2);

+		Date end = gc.getTime();

+		X509v3CertificateBuilder xcb = new X509v3CertificateBuilder(

+				x500Name(),

+				new BigInteger(12,random), // replace with Serialnumber scheme

+				start,

+				end,

+				x500Name(),

+//				SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(caCert.getPublicKey().getEn)

+				new SubjectPublicKeyInfo(ASN1Sequence.getInstance(keypair(trans).getPublic().getEncoded()))

+				);

+		return new JcaX509CertificateConverter().getCertificate(

+				xcb.build(BCFactory.contentSigner(keypair(trans).getPrivate())));

+	}

+

+	public CSRMeta san(String v) {

+		sanList.add(v);

+		return this;

+	}

+

+	public List<String> sans() {

+		return sanList;

+	}

+

+

+	public KeyPair keypair(Trans trans) {

+		if(keyPair == null) {

+			keyPair = Factory.generateKeyPair(trans);

+		}

+		return keyPair;

+	}

+

+	/**

+	 * @return the cn

+	 */

+	public String cn() {

+		return cn;

+	}

+

+

+	/**

+	 * @param cn the cn to set

+	 */

+	public void cn(String cn) {

+		this.cn = cn;

+	}

+

+	/**

+	 * Environment of Service MechID is good for

+	 */

+	public void environment(String env) {

+		environment = env;

+	}

+	

+	/**

+	 * 

+	 * @return

+	 */

+	public String environment() {

+		return environment;

+	}

+	

+	/**

+	 * @return the mechID

+	 */

+	public String mechID() {

+		return mechID;

+	}

+

+

+	/**

+	 * @param mechID the mechID to set

+	 */

+	public void mechID(String mechID) {

+		this.mechID = mechID;

+	}

+

+

+	/**

+	 * @return the email

+	 */

+	public String email() {

+		return email;

+	}

+

+

+	/**

+	 * @param email the email to set

+	 */

+	public void email(String email) {

+		this.email = email;

+	}

+

+

+	/**

+	 * @return the o

+	 */

+	public String o() {

+		return o;

+	}

+

+

+	/**

+	 * @param o the o to set

+	 */

+	public void o(String o) {

+		this.o = o;

+	}

+

+	/**

+	 * 

+	 * @return the l

+	 */

+	public String l() {

+		return l;

+	}

+	

+	/**

+	 * @param l the l to set

+	 */

+	public void l(String l) {

+		this.l=l;

+	}

+

+	/**

+	 * @return the st

+	 */

+	public String st() {

+		return st;

+	}

+

+

+	/**

+	 * @param st the st to set

+	 */

+	public void st(String st) {

+		this.st = st;

+	}

+

+

+	/**

+	 * @return the c

+	 */

+	public String c() {

+		return c;

+	}

+

+

+	/**

+	 * @param c the c to set

+	 */

+	public void c(String c) {

+		this.c = c;

+	}

+

+

+	/**

+	 * @return the challenge

+	 */

+	public String challenge() {

+		return challenge;

+	}

+

+

+	/**

+	 * @param challenge the challenge to set

+	 */

+	public void challenge(String challenge) {

+		this.challenge = challenge;

+	}

+	

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/cert/StandardFields.java b/authz-certman/src/main/java/com/att/authz/cm/cert/StandardFields.java
new file mode 100644
index 0000000..e9c2457
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/cert/StandardFields.java
@@ -0,0 +1,30 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.cert;

+

+import com.att.cadi.cm.CertException;

+

+public interface StandardFields {

+	public void set(CSRMeta csr) throws CertException;

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/data/CertDrop.java b/authz-certman/src/main/java/com/att/authz/cm/data/CertDrop.java
new file mode 100644
index 0000000..c0a219d
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/data/CertDrop.java
@@ -0,0 +1,28 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.data;

+

+public class CertDrop {

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/data/CertRenew.java b/authz-certman/src/main/java/com/att/authz/cm/data/CertRenew.java
new file mode 100644
index 0000000..4c13ab4
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/data/CertRenew.java
@@ -0,0 +1,28 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.data;

+

+public class CertRenew {

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/data/CertReq.java b/authz-certman/src/main/java/com/att/authz/cm/data/CertReq.java
new file mode 100644
index 0000000..6806a58
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/data/CertReq.java
@@ -0,0 +1,51 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.data;

+

+import java.util.List;

+

+import javax.xml.datatype.XMLGregorianCalendar;

+

+import com.att.authz.cm.ca.CA;

+import com.att.authz.cm.cert.BCFactory;

+import com.att.authz.cm.cert.CSRMeta;

+import com.att.cadi.cm.CertException;

+

+public class CertReq {

+	// These cannot be null

+	public CA certAuthority;

+	public String mechid;

+	public List<String> fqdns;

+	// Notify

+	public List<String> emails;

+	

+	

+	// These may be null

+	public String sponsor;

+	public XMLGregorianCalendar start, end;

+	

+	public CSRMeta getCSRMeta() throws CertException {

+		return BCFactory.createCSRMeta(certAuthority, mechid, sponsor,fqdns);

+	}

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/data/CertResp.java b/authz-certman/src/main/java/com/att/authz/cm/data/CertResp.java
new file mode 100644
index 0000000..8257e5c
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/data/CertResp.java
@@ -0,0 +1,66 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.data;

+

+import java.io.IOException;

+import java.security.GeneralSecurityException;

+import java.security.KeyPair;

+import java.security.cert.X509Certificate;

+

+import com.att.authz.cm.cert.CSRMeta;

+import com.att.cadi.cm.CertException;

+import com.att.cadi.cm.Factory;

+import com.att.inno.env.Trans;

+

+public class CertResp {

+	public CertResp(Trans trans, X509Certificate x509, CSRMeta csrMeta, String[] notes) throws IOException, GeneralSecurityException, CertException {

+		keyPair = csrMeta.keypair(trans);

+		privateKey = Factory.toString(trans, keyPair.getPrivate());

+		certString = Factory.toString(trans,x509);

+		challenge=csrMeta.challenge();

+		this.notes = notes;

+	}

+	private KeyPair keyPair;

+	private String challenge;

+	

+	private String privateKey, certString;

+	private String[] notes;

+	

+	

+	public String asCertString() {

+		return certString;

+	}

+	

+	public String privateString() throws IOException {

+		return privateKey;

+	}

+	

+	public String challenge() {

+		return challenge==null?"":challenge;

+	}

+	

+	public String[] notes() {

+		return notes;

+	}

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/facade/Facade.java b/authz-certman/src/main/java/com/att/authz/cm/facade/Facade.java
new file mode 100644
index 0000000..249f218
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/facade/Facade.java
@@ -0,0 +1,162 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.facade;

+

+import java.io.IOException;

+

+import javax.servlet.http.HttpServletRequest;

+import javax.servlet.http.HttpServletResponse;

+

+import com.att.authz.cm.mapper.Mapper;

+import com.att.authz.env.AuthzTrans;

+import com.att.authz.layer.Result;

+

+

+/**

+ *   

+ *

+ */

+public interface Facade<REQ,CERT,ARTIFACTS,ERROR> {

+

+/////////////////////  STANDARD ELEMENTS //////////////////

+	/** 

+	 * @param trans

+	 * @param response

+	 * @param result

+	 */

+	void error(AuthzTrans trans, HttpServletResponse response, Result<?> result);

+

+	/**

+	 * 

+	 * @param trans

+	 * @param response

+	 * @param status

+	 */

+	void error(AuthzTrans trans, HttpServletResponse response, int status,	String msg, String ... detail);

+

+	/**

+	 * Permission checker

+	 *

+	 * @param trans

+	 * @param resp

+	 * @param perm

+	 * @return

+	 * @throws IOException 

+	 */

+	Result<Void> check(AuthzTrans trans, HttpServletResponse resp, String perm) throws IOException;

+

+	/**

+	 * 

+	 * @return

+	 */

+	public Mapper<REQ,CERT,ARTIFACTS,ERROR> mapper();

+

+/////////////////////  STANDARD ELEMENTS //////////////////

+	

+	/**

+	 * 

+	 * @param trans

+	 * @param resp

+	 * @param rservlet

+	 * @return

+	 */

+	public abstract Result<Void> requestCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, boolean withTrust);

+

+	/**

+	 * 

+	 * @param trans

+	 * @param req

+	 * @param resp

+	 * @return

+	 */

+	public abstract Result<Void> renewCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, boolean withTrust);

+

+	/**

+	 * 

+	 * @param trans

+	 * @param req

+	 * @param resp

+	 * @return

+	 */

+	public abstract Result<Void> dropCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp);

+

+	/**

+	 * 

+	 * @param trans

+	 * @param req

+	 * @param resp

+	 * @return

+	 */

+	Result<Void> createArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp);

+	

+	/**

+	 * 

+	 * @param trans

+	 * @param req

+	 * @param resp

+	 * @return

+	 */

+	Result<Void> readArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp);

+

+	/**

+	 * 

+	 * @param trans

+	 * @param resp

+	 * @param mechid

+	 * @param machine

+	 * @return

+	 */

+	Result<Void> readArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine);

+

+	/**

+	 * 

+	 * @param trans

+	 * @param req

+	 * @param resp

+	 * @return

+	 */

+	Result<Void> updateArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp);

+	

+	/**

+	 * 

+	 * @param trans

+	 * @param req

+	 * @param resp

+	 * @return

+	 */

+	Result<Void> deleteArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp);

+

+	/**

+	 * 

+	 * @param trans

+	 * @param resp

+	 * @param mechid

+	 * @param machine

+	 * @return

+	 */

+	Result<Void> deleteArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine);

+

+

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/facade/Facade1_0.java b/authz-certman/src/main/java/com/att/authz/cm/facade/Facade1_0.java
new file mode 100644
index 0000000..6dd012d
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/facade/Facade1_0.java
@@ -0,0 +1,47 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.facade;

+

+import com.att.authz.cm.mapper.Mapper;

+import com.att.authz.cm.service.CMService;

+import com.att.authz.cm.service.CertManAPI;

+import com.att.inno.env.APIException;

+import com.att.inno.env.Data;

+

+import aaf.v2_0.Error;

+import certman.v1_0.Artifacts;

+import certman.v1_0.BaseRequest;

+import certman.v1_0.CertInfo;

+

+/**

+ *

+ */

+public class Facade1_0 extends FacadeImpl<BaseRequest,CertInfo, Artifacts, Error> {

+	public Facade1_0(CertManAPI certman, 

+					 CMService service, 

+					 Mapper<BaseRequest,CertInfo,Artifacts,Error> mapper, 

+					 Data.TYPE type) throws APIException {

+		super(certman, service, mapper, type);

+	}

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/facade/FacadeFactory.java b/authz-certman/src/main/java/com/att/authz/cm/facade/FacadeFactory.java
new file mode 100644
index 0000000..e9e5d54
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/facade/FacadeFactory.java
@@ -0,0 +1,43 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.facade;

+

+import com.att.authz.cm.mapper.Mapper1_0;

+import com.att.authz.cm.service.CertManAPI;

+import com.att.authz.cm.service.CMService;

+import com.att.authz.env.AuthzTrans;

+import com.att.inno.env.APIException;

+import com.att.inno.env.Data;

+

+

+public class FacadeFactory {

+	public static Facade1_0 v1_0(CertManAPI certman, AuthzTrans trans, CMService service, Data.TYPE type) throws APIException {

+		return new Facade1_0(

+				certman,

+				service,

+				new Mapper1_0(),

+				type);  

+	}

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/facade/FacadeImpl.java b/authz-certman/src/main/java/com/att/authz/cm/facade/FacadeImpl.java
new file mode 100644
index 0000000..2242144
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/facade/FacadeImpl.java
@@ -0,0 +1,493 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.facade;

+

+import static com.att.authz.layer.Result.ERR_ActionNotCompleted;

+import static com.att.authz.layer.Result.ERR_BadData;

+import static com.att.authz.layer.Result.ERR_ConflictAlreadyExists;

+import static com.att.authz.layer.Result.ERR_Denied;

+import static com.att.authz.layer.Result.ERR_NotFound;

+import static com.att.authz.layer.Result.ERR_NotImplemented;

+import static com.att.authz.layer.Result.ERR_Policy;

+import static com.att.authz.layer.Result.ERR_Security;

+import static com.att.authz.layer.Result.OK;

+

+import java.io.IOException;

+

+import javax.servlet.http.HttpServletRequest;

+import javax.servlet.http.HttpServletResponse;

+

+import com.att.authz.cm.api.API_Cert;

+import com.att.authz.cm.ca.CA;

+import com.att.authz.cm.data.CertResp;

+import com.att.authz.cm.mapper.Mapper;

+import com.att.authz.cm.mapper.Mapper.API;

+import com.att.authz.cm.service.CMService;

+import com.att.authz.cm.service.CertManAPI;

+import com.att.authz.env.AuthzEnv;

+import com.att.authz.env.AuthzTrans;

+import com.att.authz.layer.Result;

+import com.att.cadi.aaf.AAFPermission;

+import com.att.dao.aaf.cass.ArtiDAO;

+import com.att.dao.aaf.cass.Status;

+import com.att.inno.env.APIException;

+import com.att.inno.env.Data;

+import com.att.inno.env.Env;

+import com.att.inno.env.Slot;

+import com.att.inno.env.TimeTaken;

+import com.att.inno.env.util.Split;

+import com.att.rosetta.env.RosettaDF;

+import com.att.rosetta.env.RosettaData;

+

+/**

+ * AuthzFacade

+ * 

+ * This Service Facade encapsulates the essence of the API Service can do, and provides

+ * a single created object for elements such as RosettaDF.

+ *

+ * The Responsibilities of this class are to:

+ * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage)

+ * 2) Validate incoming data (if applicable)

+ * 3) Convert the Service response into the right Format, and mark the Content Type

+ * 		a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request.

+ * 4) Log Service info, warnings and exceptions as necessary

+ * 5) When asked by the API layer, this will create and write Error content to the OutputStream

+ * 

+ * Note: This Class does NOT set the HTTP Status Code.  That is up to the API layer, so that it can be 

+ * clearly coordinated with the API Documentation

+ * 

+ *

+ */

+public abstract class FacadeImpl<REQ,CERT,ARTIFACTS,ERROR> extends com.att.authz.layer.FacadeImpl implements Facade<REQ,CERT,ARTIFACTS,ERROR> 

+	{

+	private static final String REQUEST_CERT = "Request New Certificate";

+	private static final String RENEW_CERT = "Renew Certificate";

+	private static final String DROP_CERT = "Drop Certificate";

+	private static final String CREATE_ARTIFACTS = "Create Deployment Artifact";

+	private static final String READ_ARTIFACTS = "Read Deployment Artifact";

+	private static final String UPDATE_ARTIFACTS = "Update Deployment Artifact";

+	private static final String DELETE_ARTIFACTS = "Delete Deployment Artifact";

+

+	private CMService service;

+

+	private final RosettaDF<ERROR>	 	errDF;

+	private final RosettaDF<REQ> 		certRequestDF, certRenewDF, certDropDF;

+	private final RosettaDF<CERT>		certDF;

+	private final RosettaDF<ARTIFACTS>	artiDF;

+	private Mapper<REQ, CERT, ARTIFACTS, ERROR> 	mapper;

+	private Slot sCertAuth;

+	private CertManAPI certman;

+	private final String voidResp;

+

+	public FacadeImpl(CertManAPI certman,

+					  CMService service, 

+					  Mapper<REQ,CERT,ARTIFACTS,ERROR> mapper, 

+					  Data.TYPE dataType) throws APIException {

+		this.service = service;

+		this.mapper = mapper;

+		this.certman = certman;

+		AuthzEnv env = certman.env;

+		(errDF 				= env.newDataFactory(mapper.getClass(API.ERROR))).in(dataType).out(dataType);

+		(certRequestDF 		= env.newDataFactory(mapper.getClass(API.CERT_REQ))).in(dataType).out(dataType);

+		(certRenewDF 		= env.newDataFactory(mapper.getClass(API.CERT_RENEW))).in(dataType).out(dataType);

+		(certDropDF 		= env.newDataFactory(mapper.getClass(API.CERT_DROP))).in(dataType).out(dataType);

+		(certDF 			= env.newDataFactory(mapper.getClass(API.CERT))).in(dataType).out(dataType);

+		(artiDF 			= env.newDataFactory(mapper.getClass(API.ARTIFACTS))).in(dataType).out(dataType);

+		sCertAuth = env.slot(API_Cert.CERT_AUTH);

+		if(artiDF.getOutType().name().contains("xml")) {

+			voidResp = "application/Void+xml;charset=utf-8;version=1.0,application/xml;version=1.0,*/*";

+		} else {

+			voidResp = "application/Void+json;charset=utf-8;version=1.0,application/json;version=1.0,*/*";

+		}

+	}

+	

+	public Mapper<REQ,CERT,ARTIFACTS,ERROR> mapper() {

+		return mapper;

+	}

+	

+	/* (non-Javadoc)

+	 * @see com.att.authz.facade.AuthzFacade#error(com.att.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse, int)

+	 * 

+	 * Note: Conforms to AT&T TSS RESTful Error Structure

+	 */

+	@Override

+	public void error(AuthzTrans trans, HttpServletResponse response, Result<?> result) {

+		error(trans, response, result.status,

+				result.details==null?"":result.details.trim(),

+				result.variables==null?new String[0]:result.variables);

+	}

+		

+	@Override

+	public void error(AuthzTrans trans, HttpServletResponse response, int status, final String _msg, final String ... _detail) {

+		String msgId;

+		String prefix;

+		switch(status) {

+			case 202:

+			case ERR_ActionNotCompleted:

+				msgId = "SVC1202";

+				prefix = "Accepted, Action not complete";

+				response.setStatus(/*httpstatus=*/202);

+				break;

+

+			case 403:

+			case ERR_Policy:

+			case ERR_Security:

+			case ERR_Denied:

+				msgId = "SVC1403";

+				prefix = "Forbidden";

+				response.setStatus(/*httpstatus=*/403);

+				break;

+				

+			case 404:

+			case ERR_NotFound:

+				msgId = "SVC1404";

+				prefix = "Not Found";

+				response.setStatus(/*httpstatus=*/404);

+				break;

+

+			case 406:

+			case ERR_BadData:

+				msgId="SVC1406";

+				prefix = "Not Acceptable";

+				response.setStatus(/*httpstatus=*/406);

+				break;

+				

+			case 409:

+			case ERR_ConflictAlreadyExists:

+				msgId = "SVC1409";

+				prefix = "Conflict Already Exists";

+				response.setStatus(/*httpstatus=*/409);

+				break;

+			

+			case 501:

+			case ERR_NotImplemented:

+				msgId = "SVC1501";

+				prefix = "Not Implemented"; 

+				response.setStatus(/*httpstatus=*/501);

+				break;

+				

+

+			default:

+				msgId = "SVC1500";

+				prefix = "General Service Error";

+				response.setStatus(/*httpstatus=*/500);

+				break;

+		}

+

+		try {

+			StringBuilder holder = new StringBuilder();

+			errDF.newData(trans).load(

+				mapper().errorFromMessage(holder, msgId,prefix + ": " + _msg,_detail)).to(response.getOutputStream());

+			

+			holder.append(']');

+			trans.checkpoint(

+					"ErrResp [" + 

+					holder,

+					Env.ALWAYS);

+		} catch (Exception e) {

+			trans.error().log(e,"unable to send response for",_msg);

+		}

+	}

+

+	@Override

+	public Result<Void> check(AuthzTrans trans, HttpServletResponse resp, String perm) throws IOException {

+		String[] p = Split.split('|',perm);

+		if(p.length!=3) {

+			return Result.err(Result.ERR_BadData,"Invalid Perm String");

+		}

+		AAFPermission ap = new AAFPermission(p[0],p[1],p[2]);

+		if(certman.aafLurPerm.fish(trans.getUserPrincipal(), ap)) {

+			resp.setContentType(voidResp);

+			resp.getOutputStream().write(0);

+			return Result.ok();

+		} else {

+			return Result.err(Result.ERR_Denied,"%s does not have %s",trans.user(),ap.getKey());

+		}

+	}

+

+	/* (non-Javadoc)

+	 * @see com.att.auth.certman.facade.Facade#requestCert(com.att.authz.env.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)

+	 */

+	@Override

+	public Result<Void> requestCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, boolean withTrust) {

+		TimeTaken tt = trans.start(REQUEST_CERT, Env.SUB|Env.ALWAYS);

+		try {

+			REQ request;

+			try {

+				Data<REQ> rd = certRequestDF.newData().load(req.getInputStream());

+				request = rd.asObject();

+			} catch(APIException e) {

+				trans.error().log("Invalid Input",IN,REQUEST_CERT);

+				return Result.err(Result.ERR_BadData,"Invalid Input");

+			}

+			

+			Result<CertResp> rcr = service.requestCert(trans,mapper.toReq(trans,request));

+			if(rcr.notOK()) {

+				return Result.err(rcr);

+			}

+			

+			CA certAuth = trans.get(sCertAuth,null);

+			Result<CERT> rc = mapper.toCert(trans, rcr, withTrust?certAuth.getTrustChain():null);

+			switch(rc.status) {

+			case OK: 

+				RosettaData<CERT> data = certDF.newData(trans).load(rc.value);

+				data.to(resp.getOutputStream());

+

+				setContentType(resp,certDF.getOutType());

+				return Result.ok();

+			default:

+				return Result.err(rc);

+		}

+

+		} catch (Exception e) {

+			trans.error().log(e,IN,REQUEST_CERT);

+			return Result.err(e);

+		} finally {

+			tt.done();

+		}

+	}

+	

+	@Override

+	public Result<Void> renewCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, boolean withTrust) {

+		TimeTaken tt = trans.start(RENEW_CERT, Env.SUB|Env.ALWAYS);

+		try {

+			REQ request;

+			try {

+				Data<REQ> rd = certRenewDF.newData().load(req.getInputStream());

+				request = rd.asObject();

+			} catch(APIException e) {

+				trans.error().log("Invalid Input",IN,RENEW_CERT);

+				return Result.err(Result.ERR_BadData,"Invalid Input");

+			}

+			

+			String certAuth = trans.get(sCertAuth,null);

+			Result<CertResp> rcr = service.renewCert(trans,mapper.toRenew(trans,request));

+			Result<CERT> rc = mapper.toCert(trans, rcr, certman.getTrustChain(certAuth));

+

+			switch(rc.status) {

+				case OK: 

+					RosettaData<CERT> data = certDF.newData(trans).load(rc.value);

+					data.to(resp.getOutputStream());

+

+					setContentType(resp,certDF.getOutType());

+					return Result.ok();

+				default:

+					return Result.err(rc);

+			}

+		} catch (Exception e) {

+			trans.error().log(e,IN,RENEW_CERT);

+			return Result.err(e);

+		} finally {

+			tt.done();

+		}

+

+	}

+

+	@Override

+	public Result<Void> dropCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {

+		TimeTaken tt = trans.start(DROP_CERT, Env.SUB|Env.ALWAYS);

+		try {

+			REQ request;

+			try {

+				Data<REQ> rd = certDropDF.newData().load(req.getInputStream());

+				request = rd.asObject();

+			} catch(APIException e) {

+				trans.error().log("Invalid Input",IN,DROP_CERT);

+				return Result.err(Result.ERR_BadData,"Invalid Input");

+			}

+			

+			Result<Void> rv = service.dropCert(trans,mapper.toDrop(trans, request));

+			switch(rv.status) {

+				case OK: 

+					setContentType(resp,certRequestDF.getOutType());

+					return Result.ok();

+				default:

+					return Result.err(rv);

+			}

+		} catch (Exception e) {

+			trans.error().log(e,IN,DROP_CERT);

+			return Result.err(e);

+		} finally {

+			tt.done();

+		}

+	}

+

+	////////////////////////////

+	// Artifacts

+	////////////////////////////

+	@Override

+	public Result<Void> createArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {

+		TimeTaken tt = trans.start(CREATE_ARTIFACTS, Env.SUB);

+		try {

+			ARTIFACTS arti;

+			try {

+				Data<ARTIFACTS> rd = artiDF.newData().load(req.getInputStream());

+				arti = rd.asObject();

+			} catch(APIException e) {

+				trans.error().log("Invalid Input",IN,CREATE_ARTIFACTS);

+				return Result.err(Result.ERR_BadData,"Invalid Input");

+			}

+			

+			return service.createArtifact(trans,mapper.toArtifact(trans,arti));

+		} catch (Exception e) {

+

+			trans.error().log(e,IN,CREATE_ARTIFACTS);

+			return Result.err(e);

+		} finally {

+			tt.done();

+		}

+	}

+

+	@Override

+	public Result<Void> readArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {

+		TimeTaken tt = trans.start(READ_ARTIFACTS, Env.SUB);

+		try {

+			String mechid = req.getParameter("mechid");

+			String machine = req.getParameter("machine");

+			

+			Result<ARTIFACTS> ra;

+			if( machine !=null && mechid == null) {

+				ra = mapper.fromArtifacts(service.readArtifactsByMachine(trans, machine));

+			} else if(mechid!=null && machine==null) {

+				ra = mapper.fromArtifacts(service.readArtifactsByMechID(trans, mechid));

+			} else if(mechid!=null && machine!=null) {

+				ArtiDAO.Data add = new ArtiDAO.Data();

+				add.mechid = mechid;

+				add.machine = machine;

+				ra = mapper.fromArtifacts(service.readArtifacts(trans,add));

+			} else {

+				ra = Result.err(Status.ERR_BadData,"Invalid request inputs");

+			}

+			

+			if(ra.isOK()) {

+				RosettaData<ARTIFACTS> data = artiDF.newData(trans).load(ra.value);

+				data.to(resp.getOutputStream());

+				setContentType(resp,artiDF.getOutType());

+				return Result.ok();

+			} else {

+				return Result.err(ra);

+			}

+

+		} catch (Exception e) {

+			trans.error().log(e,IN,READ_ARTIFACTS);

+			return Result.err(e);

+		} finally {

+			tt.done();

+		}

+	}

+

+	@Override

+	public Result<Void> readArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine) {

+		TimeTaken tt = trans.start(READ_ARTIFACTS, Env.SUB);

+		try {

+			ArtiDAO.Data add = new ArtiDAO.Data();

+			add.mechid = mechid;

+			add.machine = machine;

+			Result<ARTIFACTS> ra = mapper.fromArtifacts(service.readArtifacts(trans,add));

+			if(ra.isOK()) {

+				RosettaData<ARTIFACTS> data = artiDF.newData(trans).load(ra.value);

+				data.to(resp.getOutputStream());

+				setContentType(resp,artiDF.getOutType());

+				return Result.ok();

+			} else {

+				return Result.err(ra);

+			}

+		} catch (Exception e) {

+			trans.error().log(e,IN,READ_ARTIFACTS);

+			return Result.err(e);

+		} finally {

+			tt.done();

+		}

+	}

+

+

+	@Override

+	public Result<Void> updateArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {

+		TimeTaken tt = trans.start(UPDATE_ARTIFACTS, Env.SUB);

+		try {

+			ARTIFACTS arti;

+			try {

+				Data<ARTIFACTS> rd = artiDF.newData().load(req.getInputStream());

+				arti = rd.asObject();

+			} catch(APIException e) {

+				trans.error().log("Invalid Input",IN,UPDATE_ARTIFACTS);

+				return Result.err(Result.ERR_BadData,"Invalid Input");

+			}

+			

+			return service.updateArtifact(trans,mapper.toArtifact(trans,arti));

+		} catch (Exception e) {

+			trans.error().log(e,IN,UPDATE_ARTIFACTS);

+			return Result.err(e);

+		} finally {

+			tt.done();

+		}

+	}

+

+	@Override

+	public Result<Void> deleteArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {

+		TimeTaken tt = trans.start(DELETE_ARTIFACTS, Env.SUB);

+		try {

+			ARTIFACTS arti;

+			try {

+				Data<ARTIFACTS> rd = artiDF.newData().load(req.getInputStream());

+				arti = rd.asObject();

+			} catch(APIException e) {

+				trans.error().log("Invalid Input",IN,DELETE_ARTIFACTS);

+				return Result.err(Result.ERR_BadData,"Invalid Input");

+			}

+			

+			Result<Void> rv = service.deleteArtifact(trans,mapper.toArtifact(trans,arti));

+			switch(rv.status) {

+				case OK: 

+					setContentType(resp,artiDF.getOutType());

+			} 

+			return rv;

+		} catch (Exception e) {

+			trans.error().log(e,IN,DELETE_ARTIFACTS);

+			return Result.err(e);

+		} finally {

+			tt.done();

+		}

+	}

+

+	@Override

+	public Result<Void> deleteArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine) {

+		TimeTaken tt = trans.start(DELETE_ARTIFACTS, Env.SUB);

+		try {

+			Result<Void> rv = service.deleteArtifact(trans, mechid, machine);

+			switch(rv.status) {

+				case OK: 

+					setContentType(resp,artiDF.getOutType());

+			} 

+			return rv;

+		} catch (Exception e) {

+			trans.error().log(e,IN,DELETE_ARTIFACTS);

+			return Result.err(e);

+		} finally {

+			tt.done();

+		}

+	}

+

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/mapper/Mapper.java b/authz-certman/src/main/java/com/att/authz/cm/mapper/Mapper.java
new file mode 100644
index 0000000..7218b15
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/mapper/Mapper.java
@@ -0,0 +1,53 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.mapper;

+

+import java.io.IOException;

+import java.util.List;

+

+import com.att.authz.cm.data.CertDrop;

+import com.att.authz.cm.data.CertRenew;

+import com.att.authz.cm.data.CertReq;

+import com.att.authz.cm.data.CertResp;

+import com.att.authz.env.AuthzTrans;

+import com.att.authz.layer.Result;

+import com.att.dao.aaf.cass.ArtiDAO;

+

+public interface Mapper<REQ,CERT,ARTIFACTS,ERROR>

+{

+	public enum API{ERROR,VOID,CERT,CERT_REQ,CERT_RENEW,CERT_DROP,ARTIFACTS};

+	

+	public Class<?> getClass(API api);

+	public<A> A newInstance(API api);

+

+	public ERROR errorFromMessage(StringBuilder holder, String msgID, String text, String... detail);

+	

+	public Result<CERT> toCert(AuthzTrans trans, Result<CertResp> in, String[] trustChain) throws IOException;

+	public Result<CertReq> toReq(AuthzTrans trans, REQ req);

+	public Result<CertRenew> toRenew(AuthzTrans trans, REQ req);

+	public Result<CertDrop>  toDrop(AuthzTrans trans, REQ req);

+	

+	public List<ArtiDAO.Data> toArtifact(AuthzTrans trans, ARTIFACTS arti);

+	public Result<ARTIFACTS> fromArtifacts(Result<List<ArtiDAO.Data>> readArtifactsByMachine);

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/mapper/Mapper1_0.java b/authz-certman/src/main/java/com/att/authz/cm/mapper/Mapper1_0.java
new file mode 100644
index 0000000..63c4f6a
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/mapper/Mapper1_0.java
@@ -0,0 +1,246 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.mapper;

+

+import java.io.IOException;

+import java.util.ArrayList;

+import java.util.List;

+

+import aaf.v2_0.Error;

+import certman.v1_0.Artifacts;

+import certman.v1_0.Artifacts.Artifact;

+import certman.v1_0.BaseRequest;

+import certman.v1_0.CertInfo;

+import certman.v1_0.CertificateDrop;

+import certman.v1_0.CertificateRenew;

+import certman.v1_0.CertificateRequest;

+

+import com.att.authz.cm.data.CertDrop;

+import com.att.authz.cm.data.CertRenew;

+import com.att.authz.cm.data.CertReq;

+import com.att.authz.cm.data.CertResp;

+import com.att.authz.cm.validation.Validator;

+import com.att.authz.env.AuthzTrans;

+import com.att.authz.layer.Result;

+import com.att.cadi.aaf.v2_0.AAFCon;

+import com.att.cadi.util.Vars;

+import com.att.dao.aaf.cass.ArtiDAO;

+import com.att.dao.aaf.cass.ArtiDAO.Data;

+

+

+public class Mapper1_0 implements Mapper<BaseRequest,CertInfo,Artifacts,Error> {

+	

+	@Override

+	public Class<?> getClass(API api) {

+		switch(api) {

+			case CERT_REQ: return CertificateRequest.class;

+			case CERT_RENEW: return CertificateRenew.class;

+			case CERT_DROP: return CertificateDrop.class;

+			case CERT: return CertInfo.class;

+			case ARTIFACTS: return Artifacts.class;

+			case ERROR: return Error.class;

+			case VOID: return Void.class;

+		}

+		return null;

+	}

+

+	@SuppressWarnings("unchecked")

+	@Override

+	public <A> A newInstance(API api) {

+		switch(api) {

+			case CERT_REQ: return (A) new CertificateRequest();

+			case CERT_RENEW: return (A) new CertificateRenew();

+			case CERT_DROP: return (A) new CertificateDrop();

+			case CERT: return (A) new CertInfo();

+			case ARTIFACTS: return (A) new Artifacts();

+			case ERROR: return (A)new Error();

+			case VOID: return null;

+		}

+		return null;

+	}

+

+	//////////////  Mapping Functions /////////////

+	@Override

+	public Error errorFromMessage(StringBuilder holder, String msgID, String text, String... var) {

+		Error err = new Error();

+		err.setMessageId(msgID);

+		// AT&T Restful Error Format requires numbers "%" placements

+		err.setText(Vars.convert(holder, text, var));

+		for(String s : var) {

+			err.getVariables().add(s);

+		}

+		return err;

+	}

+

+	/* (non-Javadoc)

+	 * @see com.att.authz.certman.mapper.Mapper#toCert(com.att.authz.env.AuthzTrans, com.att.authz.layer.Result)

+	 */

+	@Override

+	public Result<CertInfo> toCert(AuthzTrans trans, Result<CertResp> in, String[] trustChain) throws IOException {

+		if(in.isOK()) {

+			CertResp cin = in.value;

+			CertInfo cout = newInstance(API.CERT);

+			cout.setPrivatekey(cin.privateString());

+			String value;

+			if((value=cin.challenge())!=null) {

+				cout.setChallenge(value);

+			}

+			cout.getCerts().add(cin.asCertString());

+			if(trustChain!=null) {

+				for(String c : trustChain) {

+					cout.getCerts().add(c);

+				}

+			}

+			if(cin.notes()!=null) {

+				boolean first = true;

+				StringBuilder sb = new StringBuilder();

+				for(String n : cin.notes()) {

+					if(first) {

+						first = false;

+					} else {

+						sb.append('\n');

+					}

+					sb.append(n);

+				}

+				cout.setNotes(sb.toString());

+			}

+			return Result.ok(cout);

+		} else {

+			return Result.err(in);

+		}

+	}

+

+	/* (non-Javadoc)

+	 * @see com.att.authz.certman.mapper.Mapper#toReq(com.att.authz.env.AuthzTrans, java.lang.Object)

+	 */

+	@Override

+	public Result<CertReq> toReq(AuthzTrans trans, BaseRequest req) {

+		CertificateRequest in;

+		try {

+			in = (CertificateRequest)req;

+		} catch(ClassCastException e) {

+			return Result.err(Result.ERR_BadData,"Request is not a CertificateRequest");

+		}

+

+		CertReq out = new CertReq();

+		Validator v = new Validator();

+		if(v.isNull("CertRequest", req)

+			.nullOrBlank("MechID", out.mechid=in.getMechid())

+			.nullBlankMin("FQDNs", out.fqdns=in.getFqdns(),1)

+			.err()) {

+			return Result.err(Result.ERR_BadData, v.errs());

+		}

+		out.emails = in.getEmail();

+		out.sponsor=in.getSponsor();

+		out.start = in.getStart();

+		out.end = in.getEnd();

+		return Result.ok(out);

+	}

+

+	/* (non-Javadoc)

+	 * @see com.att.authz.certman.mapper.Mapper#toRenew(com.att.authz.env.AuthzTrans, java.lang.Object)

+	 */

+	@Override

+	public Result<CertRenew> toRenew(AuthzTrans trans, BaseRequest req) {

+		return Result.err(Result.ERR_NotImplemented,"Not Implemented... yet");

+	}

+

+	/* (non-Javadoc)

+	 * @see com.att.authz.certman.mapper.Mapper#toDrop(com.att.authz.env.AuthzTrans, java.lang.Object)

+	 */

+	@Override

+	public Result<CertDrop> toDrop(AuthzTrans trans, BaseRequest req) {

+		return Result.err(Result.ERR_NotImplemented,"Not Implemented... yet");

+	}

+

+	/* (non-Javadoc)

+	 * @see com.att.authz.cm.mapper.Mapper#toArtifact(com.att.authz.env.AuthzTrans, java.lang.Object)

+	 */

+	@Override

+	public List<ArtiDAO.Data> toArtifact(AuthzTrans trans, Artifacts artifacts) {

+		List<ArtiDAO.Data> ladd = new ArrayList<ArtiDAO.Data>();

+		for(Artifact arti : artifacts.getArtifact()) {

+			ArtiDAO.Data data = new ArtiDAO.Data();

+			data.mechid = arti.getMechid();

+			data.machine = arti.getMachine();

+			data.type(true).addAll(arti.getType());

+			data.ca = arti.getCa();

+			data.dir = arti.getDir();

+			data.os_user = arti.getOsUser();

+			// Optional (on way in)

+			data.appName = arti.getAppName();

+			data.renewDays = arti.getRenewDays();

+			data.notify = arti.getNotification();

+			

+			// Ignored on way in for create/update

+			data.sponsor = arti.getSponsor();

+			data.expires = null;

+			

+			// Derive Optional Data from Machine (Domain) if exists

+			if(data.machine!=null) {

+				if(data.ca==null) {

+					if(data.machine.endsWith(".att.com")) {

+						data.ca = "aaf"; // default

+					}

+				}

+				if(data.appName==null ) {

+					data.appName=AAFCon.reverseDomain(data.machine);

+				}

+			}

+

+			ladd.add(data);

+		}

+		return ladd;

+	}

+

+	/* (non-Javadoc)

+	 * @see com.att.authz.cm.mapper.Mapper#fromArtifacts(com.att.authz.layer.Result)

+	 */

+	@Override

+	public Result<Artifacts> fromArtifacts(Result<List<Data>> lArtiDAO) {

+		if(lArtiDAO.isOK()) {

+			Artifacts artis = new Artifacts();

+			for(ArtiDAO.Data arti : lArtiDAO.value) {

+				Artifact a = new Artifact();

+				a.setMechid(arti.mechid);

+				a.setMachine(arti.machine);

+				a.setSponsor(arti.sponsor);

+				a.setAppName(arti.appName);

+				a.setCa(arti.ca);

+				a.setDir(arti.dir);

+				a.getType().addAll(arti.type(false));

+				a.setOsUser(arti.os_user);

+				a.setRenewDays(arti.renewDays);

+				a.setNotification(arti.notify);

+				artis.getArtifact().add(a);

+			}

+			return Result.ok(artis);

+		} else {

+			return Result.err(lArtiDAO);

+		}

+	}

+	

+	

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/service/CMService.java b/authz-certman/src/main/java/com/att/authz/cm/service/CMService.java
new file mode 100644
index 0000000..9e6d5fa
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/service/CMService.java
@@ -0,0 +1,515 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.service;

+

+import java.io.IOException;

+import java.net.InetAddress;

+import java.net.UnknownHostException;

+import java.nio.ByteBuffer;

+import java.security.NoSuchAlgorithmException;

+import java.security.cert.X509Certificate;

+import java.util.ArrayList;

+import java.util.Date;

+import java.util.List;

+

+import com.att.authz.cm.api.API_Cert;

+import com.att.authz.cm.ca.CA;

+import com.att.authz.cm.cert.BCFactory;

+import com.att.authz.cm.cert.CSRMeta;

+import com.att.authz.cm.data.CertDrop;

+import com.att.authz.cm.data.CertRenew;

+import com.att.authz.cm.data.CertReq;

+import com.att.authz.cm.data.CertResp;

+import com.att.authz.cm.validation.Validator;

+import com.att.authz.env.AuthzTrans;

+import com.att.authz.layer.Result;

+import com.att.authz.org.Organization;

+import com.att.authz.org.Organization.Identity;

+import com.att.authz.org.OrganizationException;

+import com.att.cadi.Hash;

+import com.att.cadi.aaf.AAFPermission;

+import com.att.cadi.aaf.v2_0.AAFCon;

+import com.att.cadi.cm.Factory;

+import com.att.dao.CassAccess;

+import com.att.dao.DAO;

+import com.att.dao.aaf.cass.ArtiDAO;

+import com.att.dao.aaf.cass.CacheInfoDAO;

+import com.att.dao.aaf.cass.CertDAO;

+import com.att.dao.aaf.cass.CredDAO;

+import com.att.dao.aaf.cass.HistoryDAO;

+import com.att.dao.aaf.cass.Status;

+import com.att.dao.aaf.hl.Question;

+import com.att.inno.env.APIException;

+import com.att.inno.env.Slot;

+import com.att.inno.env.util.Chrono;

+import com.datastax.driver.core.Cluster;

+

+

+public class CMService {

+	// If we add more CAs, may want to parameterize

+	private static final int STD_RENEWAL = 30;

+	private static final int MAX_RENEWAL = 60;

+	private static final int MIN_RENEWAL = 10;

+	

+	public static final String REQUEST = "request";

+	public static final String RENEW = "renew";

+	public static final String DROP = "drop";

+	public static final String SANS = "san";

+	

+	private static final String[] NO_NOTES = new String[0];

+	private Slot sCertAuth;

+	private final CertDAO certDAO;

+	private final CredDAO credDAO;

+	private final ArtiDAO artiDAO;

+	private DAO<AuthzTrans, ?>[] daos;

+

+	@SuppressWarnings("unchecked")

+	public CMService(AuthzTrans trans, CertManAPI certman) throws APIException, IOException {

+

+		sCertAuth = certman.env.slot(API_Cert.CERT_AUTH);

+		Cluster cluster;

+		try {

+			cluster = com.att.dao.CassAccess.cluster(certman.env,null);

+		} catch (IOException e) {

+			throw new APIException(e);

+		}

+

+		// jg 4/2015 SessionFilter unneeded... DataStax already deals with Multithreading well

+		

+		HistoryDAO hd = new HistoryDAO(trans,  cluster, CassAccess.KEYSPACE);

+		CacheInfoDAO cid = new CacheInfoDAO(trans, hd);

+		certDAO = new CertDAO(trans, hd, cid);

+		credDAO = new CredDAO(trans, hd, cid);

+		artiDAO = new ArtiDAO(trans, hd, cid);

+		

+		daos =(DAO<AuthzTrans, ?>[]) new DAO<?,?>[] {

+				hd,cid,certDAO,credDAO,artiDAO

+		};

+

+		// Setup Shutdown Hooks for Cluster and Pooled Sessions

+		Runtime.getRuntime().addShutdownHook(new Thread() {

+			@Override

+			public void run() {

+				for(DAO<AuthzTrans,?> dao : daos) {

+					dao.close(trans);

+				}

+

+//				sessionFilter.destroy();

+				cluster.close();

+			}

+		}); 

+	}

+	

+	public Result<CertResp> requestCert(AuthzTrans trans,Result<CertReq> req) {

+		if(req.isOK()) {

+			CA ca = trans.get(sCertAuth, null);

+			if(ca==null) {

+				return Result.err(Result.err(Result.ERR_BadData, "Invalid Cert Authority requested"));

+			}

+

+			// Allow only AAF CA without special permission

+			if(!ca.getName().equals("aaf") && !trans.fish( new AAFPermission(ca.getPermType(), ca.getName(), REQUEST))) {

+				return Result.err(Status.ERR_Denied, "'%s' does not have permission to request Certificates from Certificate Authority '%s'", 

+						trans.user(),ca.getName());

+			}

+

+			List<String> notes = null;

+			List<String> fqdns;

+			String email = null;

+

+			try {

+				Organization org = trans.org();

+				

+				// Policy 1: Requests are only by Pre-Authorized Configurations

+				ArtiDAO.Data add = null;

+				try {

+					for(InetAddress ia : InetAddress.getAllByName(trans.ip())) {

+						Result<List<ArtiDAO.Data>> ra = artiDAO.read(trans, req.value.mechid,ia.getHostName());

+						if(ra.isOKhasData()) {

+							add = ra.value.get(0);

+							break;

+						}

+					}

+				} catch (UnknownHostException e1) {

+					return Result.err(Result.ERR_BadData,"There is no host for %s",trans.ip());

+				}

+				

+				if(add==null) {

+					return Result.err(Result.ERR_BadData,"There is no configuration for %s",req.value.mechid);

+				}

+				

+				// Policy 2: If Config marked as Expired, do not create or renew

+				Date now = new Date();

+				if(add.expires!=null && now.after(add.expires)) {

+					return Result.err(Result.ERR_Policy,"Configuration for %s %s is expired %s",add.mechid,add.machine,Chrono.dateFmt.format(add.expires));

+				}

+				

+				// Policy 3: MechID must be current

+				Identity muser = org.getIdentity(trans, add.mechid);

+				if(muser == null) {

+					return Result.err(Result.ERR_Policy,"MechID must exist in %s",org.getName());

+				}

+				

+				// Policy 4: Sponsor must be current

+				Identity ouser = muser.owner();

+				if(ouser==null) {

+					return Result.err(Result.ERR_Policy,"%s does not have a current sponsor at %s",add.mechid,org.getName());

+				} else if(!ouser.isFound() || !ouser.isResponsible()) {

+					return Result.err(Result.ERR_Policy,"%s reports that %s cannot be responsible for %s",org.getName(),trans.user());

+				}

+				

+					// Set Email from most current Sponsor

+				email = ouser.email();

+				

+				// Policy 5: keep Artifact data current

+				if(!ouser.fullID().equals(add.sponsor)) {

+					add.sponsor = ouser.fullID();

+					artiDAO.update(trans, add);

+				}

+		

+				// Policy 6: Requester must be granted Change permission in Namespace requested

+				String mechNS = AAFCon.reverseDomain(req.value.mechid);

+				if(mechNS==null) {

+					return Result.err(Status.ERR_Denied, "%s does not reflect a valid AAF Namespace",req.value.mechid);

+				}

+				

+				// Policy 7: Caller must be the MechID or have specifically delegated permissions

+				if(!trans.user().equals(req.value.mechid) && !trans.fish(new AAFPermission(mechNS + ".certman", ca.getName() , "request"))) {

+					return Result.err(Status.ERR_Denied, "%s must have access to modify x509 certs in NS %s",trans.user(),mechNS);

+				}

+				

+	

+				// Policy 8: SANs only allowed by Exception... need permission

+				fqdns = new ArrayList<String>();

+				fqdns.add(add.machine);  // machine is first

+				if(req.value.fqdns.size()>1 && !trans.fish(new AAFPermission(ca.getPermType(), ca.getName(), SANS))) {

+					if(notes==null) {notes = new ArrayList<String>();}

+					notes.add("Warning: Subject Alternative Names only allowed by Permission: Get CSO Exception.  This Certificate will be created, but without SANs");

+				} else {

+					for(String m : req.value.fqdns) {

+						if(!add.machine.equals(m)) {

+							fqdns.add(m);

+						}

+					}

+				}

+				

+			} catch (Exception e) {

+				trans.error().log(e);

+				return Result.err(Status.ERR_Denied,"MechID Sponsorship cannot be determined at this time.  Try later");

+			}

+			

+			CSRMeta csrMeta;

+			try {

+				csrMeta = BCFactory.createCSRMeta(

+						ca, 

+						req.value.mechid, 

+						email, 

+						fqdns);

+				X509Certificate x509 = ca.sign(trans, csrMeta);

+				if(x509==null) {

+					return Result.err(Result.ERR_ActionNotCompleted,"x509 Certificate not signed by CA");

+				}

+				CertDAO.Data cdd = new CertDAO.Data();

+				cdd.ca=ca.getName();

+				cdd.serial=x509.getSerialNumber();

+				cdd.id=req.value.mechid;

+				cdd.x500=x509.getSubjectDN().getName();

+				cdd.x509=Factory.toString(trans, x509);

+				certDAO.create(trans, cdd);

+				

+				CredDAO.Data crdd = new CredDAO.Data();

+				crdd.other = Question.random.nextInt();

+				crdd.cred=getChallenge256SaltedHash(csrMeta.challenge(),crdd.other);

+				crdd.expires = x509.getNotAfter();

+				crdd.id = req.value.mechid;

+				crdd.ns = Question.domain2ns(crdd.id);

+				crdd.type = CredDAO.CERT_SHA256_RSA;

+				credDAO.create(trans, crdd);

+				

+				CertResp cr = new CertResp(trans,x509,csrMeta, compileNotes(notes));

+				return Result.ok(cr);

+			} catch (Exception e) {

+				trans.error().log(e);

+				return Result.err(Result.ERR_ActionNotCompleted,e.getMessage());

+			}

+		} else {

+			return Result.err(req);

+		}

+	}

+

+    public Result<CertResp> renewCert(AuthzTrans trans, Result<CertRenew> renew) {

+		if(renew.isOK()) {

+			return Result.err(Result.ERR_NotImplemented,"Not implemented yet");

+		} else {

+			return Result.err(renew);

+		}	

+	}

+

+	public Result<Void> dropCert(AuthzTrans trans, Result<CertDrop> drop) {

+		if(drop.isOK()) {

+			return Result.err(Result.ERR_NotImplemented,"Not implemented yet");

+		} else {

+			return Result.err(drop);

+		}	

+	}

+

+	///////////////

+	// Artifact

+	//////////////

+	public Result<Void> createArtifact(AuthzTrans trans, List<ArtiDAO.Data> list) {

+		Validator v = new Validator().artisRequired(list, 1);

+		if(v.err()) {

+			return Result.err(Result.ERR_BadData,v.errs());

+		}

+		for(ArtiDAO.Data add : list) {

+			try {

+				// Policy 1: MechID must exist in Org

+				Identity muser = trans.org().getIdentity(trans, add.mechid);

+				if(muser == null) {

+					return Result.err(Result.ERR_Denied,"%s is not valid for %s", add.mechid,trans.org().getName());

+				}

+				

+				// Policy 2: MechID must have valid Organization Owner

+				Identity ouser = muser.owner();

+				if(ouser == null) {

+					return Result.err(Result.ERR_Denied,"%s is not a valid Sponsor for %s at %s",

+							trans.user(),add.mechid,trans.org().getName());

+				}

+				

+				// Policy 3: Calling ID must be MechID Owner

+				if(!trans.user().equals(ouser.fullID())) {

+					return Result.err(Result.ERR_Denied,"%s is not the Sponsor for %s at %s",

+							trans.user(),add.mechid,trans.org().getName());

+				}

+

+				// Policy 4: Renewal Days are between 10 and 60 (constants, may be parameterized)

+				if(add.renewDays<MIN_RENEWAL) {

+					add.renewDays = STD_RENEWAL;

+				} else if(add.renewDays>MAX_RENEWAL) {

+					add.renewDays = MAX_RENEWAL;

+				}

+				

+				// Policy 5: If Notify is blank, set to Owner's Email

+				if(add.notify==null || add.notify.length()==0) {

+					add.notify = "mailto:"+ouser.email();

+				}

+

+				// Set Sponsor from Golden Source

+				add.sponsor = ouser.fullID();

+				

+				

+			} catch (OrganizationException e) {

+				return Result.err(e);

+			}

+			// Add to DB

+			Result<ArtiDAO.Data> rv = artiDAO.create(trans, add);

+			// TODO come up with Partial Reporting Scheme, or allow only one at a time.

+			if(rv.notOK()) {

+				return Result.err(rv);

+			}

+		}

+		return Result.ok();

+	}

+

+	public Result<List<ArtiDAO.Data>> readArtifacts(AuthzTrans trans, ArtiDAO.Data add) throws OrganizationException {

+		Validator v = new Validator().keys(add);

+		if(v.err()) {

+			return Result.err(Result.ERR_BadData,v.errs());

+		}

+		String ns = AAFCon.reverseDomain(add.mechid);

+		

+		if( trans.user().equals(add.mechid)

+			|| trans.fish(new AAFPermission(ns + ".access", "*", "read"))

+			|| (trans.org().validate(trans,Organization.Policy.OWNS_MECHID,null,add.mechid))==null) {

+				return artiDAO.read(trans, add);

+		} else {

+			return Result.err(Result.ERR_Denied,"%s is not %s, is not the sponsor, and doesn't have delegated permission.",trans.user(),add.mechid); // note: reason is set by 2nd case, if 1st case misses

+		}

+

+	}

+

+	public Result<List<ArtiDAO.Data>> readArtifactsByMechID(AuthzTrans trans, String mechid) throws OrganizationException {

+		Validator v = new Validator().nullOrBlank("mechid", mechid);

+		if(v.err()) {

+			return Result.err(Result.ERR_BadData,v.errs());

+		}

+		String ns = AAFCon.reverseDomain(mechid);

+		

+		String reason;

+		if(trans.fish(new AAFPermission(ns + ".access", "*", "read"))

+			|| (reason=trans.org().validate(trans,Organization.Policy.OWNS_MECHID,null,mechid))==null) {

+			return artiDAO.readByMechID(trans, mechid);

+		} else {

+			return Result.err(Result.ERR_Denied,reason); // note: reason is set by 2nd case, if 1st case misses

+		}

+

+	}

+

+	public Result<List<ArtiDAO.Data>> readArtifactsByMachine(AuthzTrans trans, String machine) {

+		Validator v = new Validator().nullOrBlank("machine", machine);

+		if(v.err()) {

+			return Result.err(Result.ERR_BadData,v.errs());

+		}

+		

+		// TODO do some checks?

+

+		Result<List<ArtiDAO.Data>> rv = artiDAO.readByMachine(trans, machine);

+		return rv;

+	}

+

+	public Result<Void> updateArtifact(AuthzTrans trans, List<ArtiDAO.Data> list) throws OrganizationException {

+		Validator v = new Validator().artisRequired(list, 1);

+		if(v.err()) {

+			return Result.err(Result.ERR_BadData,v.errs());

+		}

+		

+		// Check if requesting User is Sponsor

+		//TODO - Shall we do one, or multiples?

+		for(ArtiDAO.Data add : list) {

+			// Policy 1: MechID must exist in Org

+			Identity muser = trans.org().getIdentity(trans, add.mechid);

+			if(muser == null) {

+				return Result.err(Result.ERR_Denied,"%s is not valid for %s", add.mechid,trans.org().getName());

+			}

+			

+			// Policy 2: MechID must have valid Organization Owner

+			Identity ouser = muser.owner();

+			if(ouser == null) {

+				return Result.err(Result.ERR_Denied,"%s is not a valid Sponsor for %s at %s",

+						trans.user(),add.mechid,trans.org().getName());

+			}

+

+			// Policy 3: Renewal Days are between 10 and 60 (constants, may be parameterized)

+			if(add.renewDays<MIN_RENEWAL) {

+				add.renewDays = STD_RENEWAL;

+			} else if(add.renewDays>MAX_RENEWAL) {

+				add.renewDays = MAX_RENEWAL;

+			}

+

+			// Policy 4: Data is always updated with the latest Sponsor

+			// Add to Sponsor, to make sure we are always up to date.

+			add.sponsor = ouser.fullID();

+

+			// Policy 5: If Notify is blank, set to Owner's Email

+			if(add.notify==null || add.notify.length()==0) {

+				add.notify = "mailto:"+ouser.email();

+			}

+

+			// Policy 4: only Owner may update info

+			if(trans.user().equals(add.sponsor)) {

+				return artiDAO.update(trans, add);

+			} else {

+				return Result.err(Result.ERR_Denied,"%s may not update info for %s",trans.user(),muser.fullID());

+			}

+			

+		}

+		return Result.err(Result.ERR_BadData,"No Artifacts to update");

+	}

+	

+	public Result<Void> deleteArtifact(AuthzTrans trans, String mechid, String machine) throws OrganizationException {

+		Validator v = new Validator()

+				.nullOrBlank("mechid", mechid)

+				.nullOrBlank("machine", machine);

+		if(v.err()) {

+			return Result.err(Result.ERR_BadData,v.errs());

+		}

+

+		Result<List<ArtiDAO.Data>> rlad = artiDAO.read(trans, mechid, machine);

+		if(rlad.notOKorIsEmpty()) {

+			return Result.err(Result.ERR_NotFound,"Artifact for %s %s does not exist.",mechid,machine);

+		}

+		

+		return deleteArtifact(trans,rlad.value.get(0));

+	}

+		

+	private Result<Void> deleteArtifact(AuthzTrans trans, ArtiDAO.Data add) throws OrganizationException {

+		// Policy 1: Record should be delete able only by Existing Sponsor.  

+		String sponsor=null;

+		Identity muser = trans.org().getIdentity(trans, add.mechid);

+		if(muser != null) {

+			Identity ouser = muser.owner();

+			if(ouser!=null) {

+				sponsor = ouser.fullID();

+			}

+		}

+		// Policy 1.a: If Sponsorship is deleted in system of Record, then 

+		// accept deletion by sponsor in Artifact Table

+		if(sponsor==null) {

+			sponsor = add.sponsor;

+		}

+		

+		String ns = AAFCon.reverseDomain(add.mechid);

+

+		if(trans.fish(new AAFPermission(ns + ".access", "*", "write"))

+				|| trans.user().equals(sponsor)) {

+			return artiDAO.delete(trans, add, false);

+		}

+		return null;

+	}

+

+	public Result<Void> deleteArtifact(AuthzTrans trans, List<ArtiDAO.Data> list) {

+		Validator v = new Validator().artisRequired(list, 1);

+		if(v.err()) {

+			return Result.err(Result.ERR_BadData,v.errs());

+		}

+

+		try {

+			boolean partial = false;

+			Result<Void> result=null;

+			for(ArtiDAO.Data add : list) {

+				result = deleteArtifact(trans, add);

+				if(result.notOK()) {

+					partial = true;

+				}

+			}

+			if(result == null) {

+				result = Result.err(Result.ERR_BadData,"No Artifacts to delete"); 

+			} else if(partial) {

+				result.partialContent(true);

+			}

+			return result;

+		} catch(Exception e) {

+			return Result.err(e);

+		}

+	}

+

+	private String[] compileNotes(List<String> notes) {

+		String[] rv;

+		if(notes==null) {

+			rv = NO_NOTES;

+		} else {

+			rv = new String[notes.size()];

+			notes.toArray(rv);

+		}

+		return rv;

+	}

+

+	private ByteBuffer getChallenge256SaltedHash(String challenge, int salt) throws NoSuchAlgorithmException {

+		ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE + challenge.length());

+		bb.putInt(salt);

+		bb.put(challenge.getBytes());

+		byte[] hash = Hash.hashSHA256(bb.array());

+		return ByteBuffer.wrap(hash);

+	}

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/service/CertManAPI.java b/authz-certman/src/main/java/com/att/authz/cm/service/CertManAPI.java
new file mode 100644
index 0000000..fa8ac6f
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/service/CertManAPI.java
@@ -0,0 +1,286 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.service;

+

+import java.lang.reflect.Constructor;

+import java.util.ArrayList;

+import java.util.EnumSet;

+import java.util.List;

+import java.util.Map;

+import java.util.Properties;

+import java.util.TreeMap;

+

+import com.att.aft.dme2.api.DME2Exception;

+//import com.att.aft.dme2.api.DME2FilterHolder;

+//import com.att.aft.dme2.api.DME2FilterHolder.RequestDispatcherType;

+import com.att.aft.dme2.api.DME2Manager;

+import com.att.aft.dme2.api.DME2Server;

+import com.att.aft.dme2.api.DME2ServerProperties;

+import com.att.aft.dme2.api.DME2ServiceHolder;

+import com.att.aft.dme2.api.util.DME2FilterHolder;

+import com.att.aft.dme2.api.util.DME2FilterHolder.RequestDispatcherType;

+import com.att.aft.dme2.api.util.DME2ServletHolder;

+//import com.att.aft.dme2.api.DME2ServletHolder;

+import com.att.authz.cm.api.API_Artifact;

+import com.att.authz.cm.api.API_Cert;

+import com.att.authz.cm.ca.CA;

+import com.att.authz.cm.facade.Facade1_0;

+import com.att.authz.cm.facade.FacadeFactory;

+import com.att.authz.cm.mapper.Mapper.API;

+import com.att.authz.env.AuthzEnv;

+import com.att.authz.env.AuthzTrans;

+import com.att.authz.env.AuthzTransFilter;

+import com.att.authz.server.AbsServer;

+import com.att.cache.Cache;

+import com.att.cache.Cache.Dated;

+import com.att.cadi.Access;

+import com.att.cadi.Access.Level;

+import com.att.cadi.CadiException;

+import com.att.cadi.TrustChecker;

+import com.att.cadi.aaf.v2_0.AAFAuthn;

+import com.att.cadi.aaf.v2_0.AAFCon;

+import com.att.cadi.aaf.v2_0.AAFConHttp;

+import com.att.cadi.aaf.v2_0.AAFLurPerm;

+import com.att.cadi.aaf.v2_0.AAFTrustChecker;

+import com.att.cadi.config.Config;

+import com.att.cssa.rserv.HttpMethods;

+import com.att.inno.env.APIException;

+import com.att.inno.env.Data;

+import com.att.inno.env.Env;

+import com.att.inno.env.Trans;

+import com.att.inno.env.util.Split;

+

+public class CertManAPI extends AbsServer {

+

+	private static final String USER_PERMS = "userPerms";

+	private static final Map<String,CA> certAuths = new TreeMap<String,CA>();

+	private static final String AAF_CERTMAN_CA_PREFIX = null;

+	public Facade1_0 facade1_0; // this is the default Facade

+	public Facade1_0 facade1_0_XML; // this is the XML Facade

+	public Map<String, Dated> cacheUser;

+	public AAFAuthn<?> aafAuthn;

+	public AAFLurPerm aafLurPerm;

+

+	private String[] EMPTY;

+	private AAFCon<?> aafcon;

+	

+	/**

+	 * Construct AuthzAPI with all the Context Supporting Routes that Authz needs

+	 * 

+	 * @param env

+	 * @param si 

+	 * @param dm 

+	 * @param decryptor 

+	 * @throws APIException 

+	 */

+	public CertManAPI(AuthzEnv env) throws Exception {

+		super(env,"CertMan");

+		env.setLog4JNames("log4j.properties","authz","cm","audit","init","trace");

+		

+		//aafcon = new AAFConHttp(env);

+		

+		aafLurPerm = aafcon.newLur();

+		// Note: If you need both Authn and Authz construct the following:

+		aafAuthn = aafcon.newAuthn(aafLurPerm);

+

+		String aaf_env = env.getProperty(Config.AAF_ENV);

+		if(aaf_env==null) {

+			throw new APIException("aaf_env needs to be set");

+		}

+		

+		// Initialize Facade for all uses

+		AuthzTrans trans = env.newTrans();

+		

+		// Load Supported Certificate Authorities by property 

+		for(String key : env.existingStaticSlotNames()) {

+			if(key.startsWith(AAF_CERTMAN_CA_PREFIX)) {

+				int idx = key.indexOf('.');

+				String[] params = Split.split(';', env.getProperty(key));

+				if(params.length>1) {

+					@SuppressWarnings("unchecked")

+					Class<CA> cac = (Class<CA>)Class.forName((String)params[0]);

+					Class<?> ptype[] = new Class<?>[params.length+1];

+					ptype[0]=Trans.class;

+					ptype[1]=String.class;

+					Object pinst[] = new Object[params.length+1];

+					pinst[0]=trans;

+					pinst[1]= key.substring(idx+1);

+					for(int i=1;i<params.length;++i) {

+						idx = i+1;

+						ptype[idx]=String.class;

+						pinst[idx]=params[i];

+					}

+					Constructor<CA> cons = cac.getConstructor(ptype);

+					CA ca = cons.newInstance(pinst);

+					certAuths.put(ca.getName(),ca);

+				}

+			}

+		}

+		if(certAuths.size()==0) {

+			throw new APIException("No Certificate Authorities have been configured in CertMan");

+		}

+		

+		CMService service = new CMService(trans, this);

+		// note: Service knows how to shutdown Cluster on Shutdown, etc.  See Constructor

+		facade1_0 = FacadeFactory.v1_0(this,trans, service,Data.TYPE.JSON);   // Default Facade

+		facade1_0_XML = FacadeFactory.v1_0(this,trans,service,Data.TYPE.XML); 

+		

+

+		synchronized(env) {

+			if(cacheUser == null) {

+				cacheUser = Cache.obtain(USER_PERMS);

+				Cache.startCleansing(env, USER_PERMS);

+				Cache.addShutdownHook(); // Setup Shutdown Hook to close cache

+			}

+		}

+		

+		////////////////////////////////////////////////////////////////////////////

+		// APIs

+		////////////////////////////////////////////////////////////////////////

+		API_Cert.init(this);

+		API_Artifact.init(this);

+		

+		StringBuilder sb = new StringBuilder();

+		trans.auditTrail(2, sb);

+		trans.init().log(sb);

+	}

+	

+	public CA getCA(String key) {

+		return certAuths.get(key);

+	}

+

+	public String[] getTrustChain(String key) {

+		CA ca = certAuths.get(key);

+		if(ca==null) {

+			return EMPTY;

+		} else {

+			return ca.getTrustChain();

+		}

+	}

+

+	/**

+	 * Setup XML and JSON implementations for each supported Version type

+	 * 

+	 * We do this by taking the Code passed in and creating clones of these with the appropriate Facades and properties

+	 * to do Versions and Content switches

+	 * 

+	 */

+	public void route(HttpMethods meth, String path, API api, Code code) throws Exception {

+		String version = "1.0";

+		// Get Correct API Class from Mapper

+		Class<?> respCls = facade1_0.mapper().getClass(api); 

+		if(respCls==null) throw new Exception("Unknown class associated with " + api.getClass().getName() + ' ' + api.name());

+		// setup Application API HTML ContentTypes for JSON and Route

+		String application = applicationJSON(respCls, version);

+		route(env,meth,path,code,application,"application/json;version="+version,"*/*");

+

+		// setup Application API HTML ContentTypes for XML and Route

+		application = applicationXML(respCls, version);

+		route(env,meth,path,code.clone(facade1_0_XML),application,"application/xml;version="+version);

+		

+		// Add other Supported APIs here as created

+	}

+	

+	public void routeAll(HttpMethods meth, String path, API api, Code code) throws Exception {

+		route(env,meth,path,code,""); // this will always match

+	}

+

+

+	/**

+	 * Start up AuthzAPI as DME2 Service

+	 * @param env

+	 * @param props

+	 * @throws DME2Exception

+	 * @throws CadiException 

+	 */

+	public void startDME2(Properties props) throws DME2Exception, CadiException {

+        DME2Manager dme2 = new DME2Manager("AAF Certman DME2Manager", props);

+

+

+        DME2ServiceHolder svcHolder;

+        List<DME2ServletHolder> slist = new ArrayList<DME2ServletHolder>();

+        svcHolder = new DME2ServiceHolder();

+        String serviceName = env.getProperty("DMEServiceName",null);

+    	if(serviceName!=null) {

+	    	svcHolder.setServiceURI(serviceName);

+	        svcHolder.setManager(dme2);

+	        svcHolder.setContext("/");

+	        

+	        

+	        

+	        DME2ServletHolder srvHolder = new DME2ServletHolder(this, new String[]{"/cert"});

+	        srvHolder.setContextPath("/*");

+	        slist.add(srvHolder);

+	        

+	        EnumSet<RequestDispatcherType> edlist = EnumSet.of(

+	        		RequestDispatcherType.REQUEST,

+	        		RequestDispatcherType.FORWARD,

+	        		RequestDispatcherType.ASYNC

+	        		);

+

+	        ///////////////////////

+	        // Apply Filters

+	        ///////////////////////

+	        List<DME2FilterHolder> flist = new ArrayList<DME2FilterHolder>();

+	        

+	        // Secure all GUI interactions with AuthzTransFilter

+	        flist.add(new DME2FilterHolder(

+	        		new AuthzTransFilter(env,aafcon,TrustChecker.NOTRUST),

+	        		"/*", edlist));

+	        

+

+	        svcHolder.setFilters(flist);

+	        svcHolder.setServletHolders(slist);

+	        

+	        DME2Server dme2svr = dme2.getServer();

+	        DME2ServerProperties dsprops = dme2svr.getServerProperties();

+	        dsprops.setGracefulShutdownTimeMs(1000);

+	

+	        env.init().log("Starting AAF Certman Jetty/DME2 server...");

+	        dme2svr.start();

+	        try {

+//	        	if(env.getProperty("NO_REGISTER",null)!=null)

+	        	dme2.bindService(svcHolder);

+	        	env.init().log("DME2 is available as HTTP"+(dsprops.isSslEnable()?"/S":""),"on port:",dsprops.getPort());

+	            while(true) { // Per DME2 Examples...

+	            	Thread.sleep(5000);

+	            }

+	        } catch(InterruptedException e) {

+	            env.init().log("AAF Jetty Server interrupted!");

+	        } catch(Exception e) { // Error binding service doesn't seem to stop DME2 or Process

+	            env.init().log(e,"DME2 Initialization Error");

+	        	dme2svr.stop();

+	        	System.exit(1);

+	        }

+    	} else {

+    		env.init().log("Properties must contain DMEServiceName");

+    	}

+	}

+

+	public static void main(String[] args) {

+		setup(CertManAPI.class, "certman.props");

+

+	}

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/service/Code.java b/authz-certman/src/main/java/com/att/authz/cm/service/Code.java
new file mode 100644
index 0000000..c29404e
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/service/Code.java
@@ -0,0 +1,46 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.service;

+

+import com.att.authz.cm.facade.Facade1_0;

+import com.att.authz.env.AuthzTrans;

+import com.att.cssa.rserv.HttpCode;

+

+public abstract class Code extends HttpCode<AuthzTrans,Facade1_0> implements Cloneable {

+

+	public Code(CertManAPI cma, String description, String ... roles) {

+		super(cma.facade1_0, description, roles);

+		// Note, the first "Code" will be created with default Facade, "JSON".

+		// use clone for another Code with XML

+	}

+	

+

+	public <D extends Code> D clone(Facade1_0 facade) throws Exception {

+		@SuppressWarnings("unchecked")

+		D d = (D)clone();

+		d.context = facade;

+		return d;

+	}

+

+}

diff --git a/authz-certman/src/main/java/com/att/authz/cm/validation/Validator.java b/authz-certman/src/main/java/com/att/authz/cm/validation/Validator.java
new file mode 100644
index 0000000..85163f0
--- /dev/null
+++ b/authz-certman/src/main/java/com/att/authz/cm/validation/Validator.java
@@ -0,0 +1,166 @@
+/*******************************************************************************

+ * ============LICENSE_START====================================================

+ * * org.onap.aai

+ * * ===========================================================================

+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.

+ * * Copyright © 2017 Amdocs

+ * * ===========================================================================

+ * * Licensed under the Apache License, Version 2.0 (the "License");

+ * * you may not use this file except in compliance with the License.

+ * * You may obtain a copy of the License at

+ * * 

+ *  *      http://www.apache.org/licenses/LICENSE-2.0

+ * * 

+ *  * Unless required by applicable law or agreed to in writing, software

+ * * distributed under the License is distributed on an "AS IS" BASIS,

+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * * See the License for the specific language governing permissions and

+ * * limitations under the License.

+ * * ============LICENSE_END====================================================

+ * *

+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.

+ * *

+ ******************************************************************************/

+package com.att.authz.cm.validation;

+

+import java.util.List;

+

+import com.att.authz.layer.Result;

+import com.att.dao.aaf.cass.ArtiDAO;

+import com.att.dao.aaf.cass.ArtiDAO.Data;

+

+/**

+ * Validator

+ * Consistently apply content rules for content (incoming)

+ * 

+ * Note: We restrict content for usability in URLs (because RESTful service), and avoid 

+ * issues with Regular Expressions, and other enabling technologies. 

+ *

+ */

+public class Validator {

+	// Repeated Msg fragments

+	private static final String MECHID = "mechid";

+	private static final String MACHINE = "machine";

+	private static final String ARTIFACT_LIST_IS_NULL = "Artifact List is null.";

+	private static final String Y = "y.";

+	private static final String IES = "ies.";

+	private static final String ENTR = " entr";

+	private static final String MUST_HAVE_AT_LEAST = " must have at least ";

+	private static final String IS_NULL = " is null.";

+	private static final String ARTIFACTS_MUST_HAVE_AT_LEAST = "Artifacts must have at least ";

+	private StringBuilder msgs;

+

+	public Validator nullOrBlank(String name, String str) {

+		if(str==null) {

+			msg(name + IS_NULL);

+		} else if(str.length()==0) {

+			msg(name + " is blank.");

+		}

+		return this;

+	}

+	

+	private void msg(String ... strs) {

+		if(msgs==null) {

+			msgs=new StringBuilder();

+		}

+		for(String str : strs) {

+			msgs.append(str);

+		}

+		msgs.append('\n');

+	}

+	

+	public boolean err() {

+		return msgs!=null;

+	}

+	

+	public String errs() {

+		return msgs.toString();

+	}

+

+	public Validator notOK(Result<?> res) {

+		if(res==null) {

+			msgs.append("Result object is blank");

+		} else if(res.notOK()) {

+			msgs.append(res.getClass().getSimpleName() + " is not OK");

+		}

+		return this;

+	}

+

+	public Validator isNull(String name, Object obj) {

+		if(obj==null) {

+			msg(name + IS_NULL);

+		} 

+		return this;

+	}

+

+	public Validator nullBlankMin(String name, List<String> list, int min) {

+		if(list==null) {

+			msg(name + IS_NULL);

+		} else {

+			if(list.size()<min) {

+				msg(name + MUST_HAVE_AT_LEAST + min + ENTR + (min==1?Y:IES));

+			} else {

+				for(String s : list) {

+					nullOrBlank("List Item",s);

+				}

+			}

+		}

+		return this;

+	}

+

+	public Validator artisRequired(List<ArtiDAO.Data> list, int min) {

+		if(list==null) {

+			msg(ARTIFACT_LIST_IS_NULL);

+		} else {

+			if(list.size()<min) {

+				msg(ARTIFACTS_MUST_HAVE_AT_LEAST + min + ENTR + (min==1?Y:IES));

+			} else {

+				for(ArtiDAO.Data a : list) {

+					allRequired(a);

+				}

+			}

+		}

+		return this;

+	}

+

+	public Validator artisKeys(List<ArtiDAO.Data> list, int min) {

+		if(list==null) {

+			msg(ARTIFACT_LIST_IS_NULL);

+		} else {

+			if(list.size()<min) {

+				msg(ARTIFACTS_MUST_HAVE_AT_LEAST + min + ENTR + (min==1?Y:IES));

+			} else {

+				for(ArtiDAO.Data a : list) {

+					keys(a);

+				}

+			}

+		}

+		return this;

+	}

+

+

+	public Validator keys(ArtiDAO.Data add) {

+		if(add==null) {

+			msg("Artifact is null.");

+		} else {

+			nullOrBlank(MECHID, add.mechid);

+			nullOrBlank(MACHINE, add.machine);

+		}

+		return this;

+	}

+	

+	private Validator allRequired(Data a) {

+		if(a==null) {

+			msg("Artifact is null.");

+		} else {

+			nullOrBlank(MECHID, a.mechid);

+			nullOrBlank(MACHINE, a.machine);

+			nullOrBlank("ca",a.ca);

+			nullOrBlank("dir",a.dir);

+			nullOrBlank("os_user",a.os_user);

+			// Note: AppName, Notify & Sponsor are currently not required

+		}

+		return this;

+	}

+

+}