summaryrefslogtreecommitdiffstats
path: root/aaf/src/main/java/com/att/cadi
diff options
context:
space:
mode:
Diffstat (limited to 'aaf/src/main/java/com/att/cadi')
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/AAFPermission.java106
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/AAFTransmutate.java88
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/ConnectivityTest.java459
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/PermEval.java150
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/cert/AAFListedCertIdentity.java179
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/client/ErrMessage.java98
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/client/Examples.java445
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java67
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java46
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java207
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java396
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java224
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java187
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java221
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java168
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java116
-rw-r--r--aaf/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java269
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/ArtifactDir.java288
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/CertException.java47
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/CmAgent.java711
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/Factory.java449
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifact.java34
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java54
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java130
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java53
-rw-r--r--aaf/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java139
-rw-r--r--aaf/src/main/java/com/att/cadi/sso/AAFSSO.java286
27 files changed, 5617 insertions, 0 deletions
diff --git a/aaf/src/main/java/com/att/cadi/aaf/AAFPermission.java b/aaf/src/main/java/com/att/cadi/aaf/AAFPermission.java
new file mode 100644
index 0000000..e604053
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/AAFPermission.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * ============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.cadi.aaf;
+
+import com.att.cadi.Permission;
+
+/**
+ * A Class that understands the AAF format of Permission (name/type/action)
+ * or String "name|type|action"
+ *
+ *
+ */
+public class AAFPermission implements Permission {
+ protected String type,instance,action,key;
+
+ protected AAFPermission() {}
+
+ public AAFPermission(String type, String instance, String action) {
+ this.type = type;
+ this.instance = instance;
+ this.action = action;
+ key = type + '|' + instance + '|' + action;
+ }
+
+ /**
+ * Match a Permission
+ * if Permission is Fielded type "Permission", we use the fields
+ * otherwise, we split the Permission with '|'
+ *
+ * when the type or action starts with REGEX indicator character ( ! ),
+ * then it is evaluated as a regular expression.
+ *
+ * If you want a simple field comparison, it is faster without REGEX
+ */
+ public boolean match(Permission p) {
+ if(p instanceof AAFPermission) {
+ AAFPermission ap = (AAFPermission)p;
+ // Note: In AAF > 1.0, Accepting "*" from name would violate multi-tenancy
+ // Current solution is only allow direct match on Type.
+ // 8/28/2014 - added REGEX ability
+ if(type.equals(ap.getName()))
+ if(PermEval.evalInstance(instance,ap.getInstance()))
+ if(PermEval.evalAction(action,ap.getAction()))
+ return true;
+ } else {
+ // Permission is concatenated together: separated by |
+ String[] aaf = p.getKey().split("[\\s]*\\|[\\s]*",3);
+ if(aaf.length>0 && type.equals(aaf[0]))
+ if(PermEval.evalInstance(instance,aaf.length>1?aaf[1]:"*"))
+ if(PermEval.evalAction(action,aaf.length>2?aaf[2]:"*"))
+ return true;
+ }
+ return false;
+ }
+
+ public String getName() {
+ return type;
+ }
+
+ public String getInstance() {
+ return instance;
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Permission#permType()
+ */
+ public String permType() {
+ return "AAF";
+ }
+
+ public String toString() {
+ return "AAFPermission:\n\tType: " + type +
+ "\n\tInstance: " + instance +
+ "\n\tAction: " + action +
+ "\n\tKey: " + key;
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/AAFTransmutate.java b/aaf/src/main/java/com/att/cadi/aaf/AAFTransmutate.java
new file mode 100644
index 0000000..a6a9bb7
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/AAFTransmutate.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * ============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.cadi.aaf;
+
+import java.security.Principal;
+import java.util.regex.Pattern;
+
+import com.att.cadi.Transmutate;
+import com.att.cadi.lur.ConfigPrincipal;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.principal.CSPPrincipal_T;
+
+/**
+ * AAFTransmutate
+ *
+ * Each System determines the mechanisms for which one Principal is transmutated to another, such as whether it is created
+ * independently, etc.
+ *
+ * For AAF, the only important thing is that these are valid ATTUID/mechIDs, to avoid unnecessary user hits
+ *
+ * attUIDs look like ab1234 or AB1234 or AZ123a
+ * mechids look like m12345
+ *
+ *
+ */
+public final class AAFTransmutate implements Transmutate<Principal> {
+ private Pattern pattern = Pattern.compile("[a-zA-Z]\\w\\d\\d\\d\\w");
+
+ public Principal mutate(Principal p) {
+ // Accept these three internal kinds of Principals
+ if(p instanceof CSPPrincipal_T
+ || p instanceof BasicPrincipal
+ || p instanceof ConfigPrincipal) {
+ return p;
+ } else {
+
+ final String name = p.getName();
+ final int idx = name.indexOf('@');
+ String shortName;
+ if(idx>0) { // strip off any domain
+ shortName = name.substring(0,idx);
+ } else {
+ shortName = name;
+ }
+
+ // Check for ATTUID specs before creating CSP_T
+ return pattern.matcher(shortName).matches()?
+ new CSP_T(name): // Note: use REAL name, short name for CSP_T
+ null;
+ }
+ }
+
+ /**
+ * Essential Principal reflecting CSP Principal
+ *
+ *
+ */
+ private final class CSP_T implements CSPPrincipal_T {
+ private String name;
+ public CSP_T(String name) {
+ this.name = name;
+ }
+ public String getName() {
+ return name;
+ }
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/ConnectivityTest.java b/aaf/src/main/java/com/att/cadi/aaf/ConnectivityTest.java
new file mode 100644
index 0000000..070d48d
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/ConnectivityTest.java
@@ -0,0 +1,459 @@
+/*******************************************************************************
+ * ============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.cadi.aaf;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.util.Date;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.LocatorException;
+import com.att.cadi.Lur;
+import com.att.cadi.PropAccess;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.TrustChecker;
+import com.att.cadi.aaf.v2_0.AAFCon;
+import com.att.cadi.aaf.v2_0.AAFConDME2;
+import com.att.cadi.client.Future;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.http.HClient;
+import com.att.cadi.http.HX509SS;
+import com.att.cadi.locator.DME2Locator;
+import com.att.cadi.locator.PropertyLocator;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+import aaf.v2_0.Perms;
+
+public class ConnectivityTest {
+ private static final String PROD = "PROD";
+ private static final String SRV_RESOLVE = "https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=%s/routeOffer=%s";
+ private static final String GW_RESOLVE = "https://DME2RESOLVE/service=com.att.authz.authz-gw/version=2.0/envContext=%s/routeOffer=%s";
+
+ public static void main(String[] args) {
+ if(args.length<2) {
+ System.out.println("Usage: ConnectivityTester <TEST|IST|PROD> <cadi_prop_files>");
+ } else {
+ print(true,"START OF CONNECTIVITY TESTS",new Date().toString(),System.getProperty("user.name"),
+ "Note: All API Calls are /authz/perms/user/<MechID/Alias of the caller>");
+
+ final String aaf_env = args[0];
+ args[1]=Config.CADI_PROP_FILES+'='+args[1];
+
+ PropAccess pa = new PropAccess(args);
+ String user = pa.getProperty(Config.AAF_MECHID);
+ String pass = pa.getProperty(Config.AAF_MECHPASS);
+ String alias = pa.getProperty(Config.CADI_ALIAS);
+ if(user==null) {
+ user=alias;
+ }
+ RosettaEnv env = new RosettaEnv(pa.getProperties());
+
+ try {
+ RosettaDF<Perms> permsDF = env.newDataFactory(Perms.class);
+ SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(pa);
+ HBasicAuthSS hbass = new HBasicAuthSS(pa,si);
+ if(hbass.getID()==null) {
+ hbass=null; // not configured with ID.
+ }
+ HX509SS hxss=null;
+ AAFCon<?> aafcon;
+
+ try {
+ hxss = new HX509SS(user,si);
+ } catch(Exception e) {
+ e.printStackTrace();
+ print(false,"Continuing");
+ }
+ String aafurl;
+ if(user==null || (pass==null && alias==null)) {
+ System.out.printf("ERROR: DME2 Client cannot be tested with out %s and %s properties"
+ , Config.AAF_MECHID, Config.AAF_MECHPASS );
+ } else {
+ if("TEST".equals(aaf_env) || "IST".equals(aaf_env) || "PROD".equals(aaf_env)) {
+ DME2Manager dm = null;
+ print(false,"Attempt DME2Manager Load");
+ if(Class.forName("com.att.aft.dme2.api.DME2Manager")==null) {
+ print(true,"DME2 jar is not available: Skipping DME2 Tests");
+ } else { // DME2 Client Tests
+ pass=pa.decrypt(pass,false);
+ // Out of the box DME2
+ aafurl = String.format(SRV_RESOLVE, aaf_env, PROD.equals(aaf_env)?"DEFAULT":"BAU_SE");
+ print(true,"TEST CADI Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ print(true,"Find and TEST Connections with DME2Locator",aafurl);
+ DME2Locator dl = new DME2Locator(pa,dm,aafurl);
+ connectTest(dl);
+
+ dm = new DME2Manager("DME2Manager",pa.getProperties());
+
+ dme2RawTest(dm, aafurl,user,pass);
+
+ // URL specific Variant
+ if((aafurl = specificDME2URL(dl, aafurl))!=null) {
+ print(true,"TEST Specific DME2 CADI Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ dme2RawTest(dm,aafurl,user,pass);
+ }
+
+ print(true,"CADI Direct AAFConDME2 Object Usage",aafurl);
+ try {
+ pa.setProperty(Config.AAF_URL,aafurl);
+ aafcon = new AAFConDME2(pa);
+ test(aafcon,permsDF,user);
+ } catch(Throwable t) {
+ t.printStackTrace();
+ }
+
+ // find a direct client to code a Direct HTTP with
+ //
+ if(hbass!=null) {
+ print(true,"CADI Http DME2Locator Client Coding Methodology BasicAuth",aafurl);
+ hClientTest(dl,hbass,user);
+ }
+ if(hxss!=null) {
+ print(true,"CADI Http DME2Locator Client Coding Methodology X509",aafurl);
+ hClientTest(dl,hxss,user);
+ }
+
+ // ##### PROXY CHECKS
+ aafurl = String.format(GW_RESOLVE, aaf_env, PROD.equals(aaf_env)?"DEFAULT":"BAU_SE");
+ print(true,"TEST PROXY DME2 CADI Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+
+ dme2RawTest(dm, aafurl,user,pass);
+
+ // URL specific Variant
+ dl = new DME2Locator(pa,dm,aafurl);
+ if((aafurl = specificDME2URL(dl, aafurl))!=null) {
+ print(true,"TEST PROXY Specific DME2 CADI Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ dme2RawTest(dm,aafurl,user,pass);
+ }
+ }
+ }
+
+ // Prop Locator
+ PropertyLocator pl = servicePropLocator(aaf_env);
+ connectTest(pl);
+ URI uri = pl.get(pl.best());
+ if(uri!=null) {
+ aafurl = uri.toString();
+ print(true,"TEST Service PropertyLocator based Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ if(hbass!=null) {
+ print(true,"CADI Service Http PropLocator Client Coding Methodology Basic Auth",aafurl);
+ hClientTest(pl,hbass, user);
+ print(true,"CADI Service Http PropLocator Client Coding Methodology /authn/basicAuth",aafurl);
+ basicAuthTest(pl,hbass);
+ }
+ if(hxss!=null) {
+ print(true,"CADI Service Http PropLocator Client Coding Methodology X509",aafurl);
+ hClientTest(pl,hxss, user);
+ }
+ }
+ pl = proxyPropLocator(aaf_env);
+ connectTest(pl);
+ uri = pl.get(pl.best());
+ if(uri!=null) {
+ aafurl = uri.toString();
+ print(true,"TEST PROXY PropertyLocator based Config",aafurl);
+ aafcon = testConfig(pa,aafurl);
+ test(aafcon,permsDF,user);
+
+ if(hbass!=null) {
+ print(true,"CADI PROXY Http PropLocator Client Coding Methodology Basic Auth",aafurl);
+ hClientTest(pl,hbass, user);
+ print(true,"CADI PROXY Http PropLocator Client Coding Methodology /proxy/authn/basicAuth",aafurl);
+ basicAuthTest(pl,hbass);
+ }
+ if(hxss!=null) {
+ print(true,"CADI PROXY Http PropLocator Client Coding Methodology X509",aafurl);
+ hClientTest(pl,hxss, user);
+ }
+ }
+ }
+
+ } catch(Exception e) {
+ e.printStackTrace(System.err);
+ } finally {
+ print(true,"END OF TESTS");
+ }
+ }
+ }
+
+ private static void print(Boolean strong, String ... args) {
+ PrintStream out = System.out;
+ out.println();
+ if(strong) {
+ for(int i=0;i<70;++i) {
+ out.print('=');
+ }
+ out.println();
+ }
+ for(String s : args) {
+ out.print(strong?"== ":"------ ");
+ out.print(s);
+ if(!strong) {
+ out.print(" ------");
+ }
+ out.println();
+ }
+ if(strong) {
+ for(int i=0;i<70;++i) {
+ out.print('=');
+ }
+ }
+ out.println();
+ }
+
+ private static void test(AAFCon<?> aafcon,RosettaDF<Perms> permsDF,String user) {
+ if(aafcon==null) {
+ print(false,"AAFCon is null");
+ } else {
+ try {
+ print(false,"Calling with AAFCon");
+ Future<Perms> fp = aafcon.client("2.0").read("/authz/perms/user/"+user, Perms.class, permsDF);
+ if(fp.get(4000)) {
+ System.out.printf("Found %d Permission(s)\n",fp.value.getPerm().size());
+ } else {
+ System.out.printf("Error: %d %s\n",fp.code(),fp.body());
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ }
+
+ private static AAFCon<?> testConfig(PropAccess pa, String aafurl) {
+ try {
+ pa.setProperty(Config.AAF_URL, aafurl);
+ Lur lur = Config.configLur(pa);
+ Config.configHttpTaf(pa, TrustChecker.NOTRUST, null, lur);
+ if(lur != null) {
+ Field f = null;
+ try {
+ f = lur.getClass().getField("aaf");
+ return (AAFCon<?>)f.get(lur);
+ } catch (Exception nsfe) {
+ }
+ }
+
+ } catch(Throwable t) {
+ t.printStackTrace();
+ }
+ return null;
+ }
+
+ private static String specificDME2URL(Locator<URI> loc, String aafurl) throws LocatorException {
+ Item item = loc.best();
+ if(item!=null) {
+ URI uri = loc.get(item);
+ return aafurl.replace("DME2RESOLVE", String.format("%s:%d",uri.getHost(),uri.getPort()));
+ }
+ return null;
+ }
+
+ private static void connectTest(Locator<URI> dl) throws LocatorException {
+ URI uri;
+ Socket socket;
+ print(false,"TCP/IP Connect test to all Located Services");
+ for(Item li = dl.first();li!=null;li=dl.next(li)) {
+ if((uri = dl.get(li)) == null) {
+ System.out.println("Locator Item empty");
+ } else {
+ try {
+ socket = new Socket();
+ socket.connect(new InetSocketAddress(uri.getHost(), uri.getPort()),3000);
+ System.out.printf("Can Connect a Socket to %s %d\n",uri.getHost(),uri.getPort());
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.printf("Could not close Socket Connection: %s\n",e1.getMessage());
+ }
+ } catch (IOException e) {
+ System.out.printf("Cannot Connect a Socket to %s %d: %s\n",uri.getHost(),uri.getPort(),e.getMessage());
+ }
+ }
+ }
+ }
+
+ private static PropertyLocator servicePropLocator(String env) throws LocatorException {
+ String purls;
+ switch(env) {
+ case "LOCAL":
+ try {
+ purls="https://"+InetAddress.getLocalHost().getHostName()+":8100";
+ } catch (UnknownHostException e) {
+ throw new LocatorException(e);
+ }
+ break;
+ case "DEV":
+ purls="https://aaf.dev.att.com:8100,https://aaf.dev.att.com:8101";
+ break;
+ case "TEST":
+ purls="https://aaftest.test.att.com:8100,https://aaftest.test.att.com:8101";
+ break;
+ case "IST":
+ purls="https://aafist.test.att.com:8100,https://aafist.test.att.com:8101";
+ break;
+ case PROD:
+ purls="https://aaf.it.att.com:8100,https://aaf.it.att.com:8101";
+ break;
+ default:
+ if(env.contains(".")) {
+ purls="https://"+env+":8100";
+ } else {
+ throw new LocatorException(ConnectivityTest.class.getSimpleName() + ": unknown Env");
+ }
+ }
+ System.out.printf("Creating a PropertyLocator for %s\n",purls);
+ return new PropertyLocator(purls);
+ }
+
+ private static PropertyLocator proxyPropLocator(String env) throws LocatorException {
+ String purls;
+ switch(env) {
+ case "LOCAL":
+ try {
+ purls="https://"+InetAddress.getLocalHost().getHostAddress()+":8100";
+ } catch (UnknownHostException e) {
+ throw new LocatorException(e);
+ }
+ break;
+ case "DEV":
+ purls="https://aaf.dev.att.com:8095/proxy";
+ break;
+ case "TEST":
+ purls="https://aaftest.test.att.com:8095/proxy";
+ break;
+ case "IST":
+ purls="https://aafist.test.att.com:8095/proxy";
+ break;
+ case PROD:
+ purls="https://aaf.it.att.com:8095/proxy";
+ break;
+ default:
+ if(env.contains(".")) {
+ purls="https://"+env+":8095/proxy";
+ } else {
+ throw new LocatorException(ConnectivityTest.class.getSimpleName() + ": unknown Env");
+ }
+
+ }
+ System.out.printf("Creating a PropertyLocator for %s\n",purls);
+ return new PropertyLocator(purls);
+ }
+
+
+
+
+ private static void hClientTest(Locator<URI> dl, SecuritySetter<HttpURLConnection> ss, String user) {
+ try {
+ URI uri = dl.get(dl.best());
+ System.out.println("Resolved to: " + uri);
+ HClient client = new HClient(ss, uri, 3000);
+ client.setMethod("GET");
+ client.setPathInfo("/authz/perms/user/"+user);
+ client.send();
+ Future<String> future = client.futureReadString();
+ if(future.get(7000)) {
+ System.out.println(future.body());
+ } else {
+ System.out.println(future.code() + ":" + future.body());
+ }
+ } catch (CadiException | LocatorException | APIException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private static void basicAuthTest(PropertyLocator dl, SecuritySetter<HttpURLConnection> ss) {
+ try {
+ URI uri = dl.get(dl.best());
+ System.out.println("Resolved to: " + uri);
+ HClient client = new HClient(ss, uri, 3000);
+ client.setMethod("GET");
+ client.setPathInfo("/authn/basicAuth");
+ client.addHeader("Accept", "text/plain");
+ client.send();
+
+
+ Future<String> future = client.futureReadString();
+ if(future.get(7000)) {
+ System.out.println("BasicAuth Validated");
+ } else {
+ System.out.println("Failure " + future.code() + ":" + future.body());
+ }
+ } catch (CadiException | LocatorException | APIException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // Regular DME2Client Coding Style
+ private static void dme2RawTest(DME2Manager dm, String aafurl, String user, String pass) {
+ try {
+ if(dm==null) {
+ return;
+ }
+ URI uri = new URI(aafurl);
+ print(true,"DME2 Direct Client Coding Methodology",uri.toString());
+ DME2Client client = dm.newClient( uri, 3000);
+ client.setMethod("GET"); // FYI, DME2 defaults to "POST"
+ client.setContext("/authz/perms/user/"+user); // DME2 direct requires separate setting of Context from URI
+ if(pass!=null) { // rely on Cert if no pass
+ client.setCredentials(user, pass);
+ }
+ client.setPayload(""); // DME2 will not send without something
+ String resp = client.sendAndWait(7000);
+ System.out.println(resp);
+ } catch(Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/PermEval.java b/aaf/src/main/java/com/att/cadi/aaf/PermEval.java
new file mode 100644
index 0000000..b661df4
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/PermEval.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * ============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.cadi.aaf;
+
+import com.att.inno.env.util.Split;
+
+
+public class PermEval {
+ public static final char START_REGEX_CHAR = '!';
+ public static final char START_INST_KEY_CHAR=':';
+ public static final char ALT_START_INST_KEY_CHAR='/';
+
+ public static final char LIST_SEP = ',';
+ public static final String INST_KEY_REGEX = new StringBuilder().append(START_INST_KEY_CHAR).toString();
+ public static final String ASTERIX = "*";
+
+ /**
+ * Evaluate Instance
+ *
+ * Instance can be more complex. It can be a string, a Regular Expression, or a ":" separated Key
+ * who's parts can also be a String, Regular Expression.
+ *
+ * sInst = Server's Instance
+ * In order to prevent false matches, keys must be the same length to count as equal
+ * Changing this will break existing users, like Cassandra. 9-4-2015
+ */
+ public static boolean evalInstance(String sInst, String pInst) {
+ if(sInst==null || pInst == null) {
+ return false;
+ }
+ if(ASTERIX.equals(sInst)) {
+ return true; // If Server's String is "*", then it accepts every Instance
+ }
+ char firstChar = pInst.charAt(0);
+ char startChar = firstChar==ALT_START_INST_KEY_CHAR?ALT_START_INST_KEY_CHAR:START_INST_KEY_CHAR;
+ switch(pInst.charAt(0)) { // First char
+ case START_REGEX_CHAR: // Evaluate as Regular Expression
+ String pItem = pInst.substring(1);
+ for(String sItem : Split.split(LIST_SEP,sInst)) { // allow for "," definition in Action
+ return sItem.matches(pItem);
+ }
+
+ case START_INST_KEY_CHAR: // Evaluate a special Key field, i.e.:xyz:*:!df.*
+ case ALT_START_INST_KEY_CHAR: // Also allow '/' as special Key Field, i.e. /xyz/*/!.*
+ if(sInst.charAt(0)==startChar) { // To compare key-to-key, both strings must be keys
+ String[] skeys=Split.split(startChar,sInst);
+ String[] pkeys=Split.split(startChar,pInst);
+ if(skeys.length!=pkeys.length) return false;
+
+ boolean pass = true;
+ for(int i=1;pass && i<skeys.length;++i) { // We start at 1, because the first one, being ":" is always ""
+ if(ASTERIX.equals(skeys[i]))continue; // Server data accepts all for this key spot
+ pass = false;
+ for(String sItem : Split.split(LIST_SEP,skeys[i])) { // allow for "," definition in Action
+ if(pkeys[i].length()==0) {
+ if(pass=sItem.length()==0) {
+ break; // Both Empty, keep checking
+ }
+// } else if(pkeys[i].charAt(0)==START_REGEX_CHAR) {
+// if(pass=sItem.matches(pkeys[i].substring(1))) {
+// break; // Matches, keep checking
+// }
+ } else if(sItem.charAt(0)==START_REGEX_CHAR) { // Check Server side when wildcarding like *
+ if(pass=pkeys[i].matches(sItem.substring(1))) {
+ break; // Matches, keep checking
+ }
+ } else if(skeys[i].endsWith(ASTERIX)) {
+ if(pass=endAsterixCompare(skeys[i],pkeys[i])) {
+ break;
+ }
+ } else {
+ if(pass=sItem.equals(pkeys[i]))
+ break; // Equal, keep checking
+ }
+ }
+ }
+ return pass; // return whether passed all key checks
+ }
+ return false; // if first chars aren't the same, further String compare not necessary
+ default: // Evaluate as String Compare
+ for(String sItem : Split.split(LIST_SEP,sInst)) { // allow for "," separator //TODO is this only for actions?
+ if(sItem.endsWith(ASTERIX)) {
+ if(endAsterixCompare(sInst, pInst));
+ } else if(sItem.equals(pInst)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private static boolean endAsterixCompare(String sInst, String pInst) {
+ final int len = sInst.length()-1;
+ if(pInst.length()<len) {
+ return false;
+ }
+ for(int j=0;j<len;++j) {
+ if(pInst.charAt(j)!=sInst.charAt(j)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Evaluate Action
+ *
+ * sAction = Stored Action...
+ * pAction = Present Action... the Permission to validate against.
+ * Action is not quite as complex. But we write it in this function so it can be consistent
+ */
+ public static boolean evalAction(String sAction,String pAction) {
+ if(ASTERIX.equals(sAction))return true; // If Server's String is "*", then it accepts every Action
+ for(String sItem : Split.split(LIST_SEP,sAction)) { // allow for "," definition in Action
+ if (pAction.charAt(0)==START_REGEX_CHAR? // First char
+ sItem.matches(pAction.substring(1)): // Evaluate as Regular Expression
+ sItem.equals(pAction)) // Evaluate as String Compare
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Split.split by Char
+ *
+ * Note: I read the String Split.split and Pattern Split.split code, and we can do this more efficiently for a single Character
+ */
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/cert/AAFListedCertIdentity.java b/aaf/src/main/java/com/att/cadi/aaf/cert/AAFListedCertIdentity.java
new file mode 100644
index 0000000..ecdaf24
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/cert/AAFListedCertIdentity.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.cert;
+
+
+import java.security.Principal;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.TreeMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Hash;
+import com.att.cadi.aaf.v2_0.AAFCon;
+import com.att.cadi.client.Future;
+import com.att.cadi.config.Config;
+import com.att.cadi.principal.X509Principal;
+import com.att.cadi.taf.cert.CertIdentity;
+import com.att.cadi.taf.cert.X509Taf;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Chrono;
+import com.att.inno.env.util.Split;
+
+import aaf.v2_0.Certs;
+import aaf.v2_0.Certs.Cert;
+import aaf.v2_0.Users;
+import aaf.v2_0.Users.User;
+
+public class AAFListedCertIdentity implements CertIdentity {
+ //TODO should 8 hours be configurable?
+ private static final long EIGHT_HOURS = 1000*60*60*8;
+ private static final String AAF_VERSION = "2.0";
+
+ private static Map<ByteArrayHolder,String> certs = null;
+
+ // Did this to add other Trust Mechanisms
+ // Trust mechanism set by Property:
+ private static final String[] authMechanisms = new String[] {"tguard","basicAuth","csp"};
+ private static String[] certIDs;
+
+ private static Map<String,Set<String>> trusted =null;
+
+ public AAFListedCertIdentity(Access access, AAFCon<?> aafcon) throws APIException {
+ synchronized(AAFListedCertIdentity.class) {
+ if(certIDs==null) {
+ String cip = access.getProperty(Config.AAF_CERT_IDS, null);
+ if(cip!=null) {
+ certIDs = Split.split(',',cip);
+ }
+ }
+ if(certIDs!=null && certs==null) {
+ TimerTask cu = new CertUpdate(aafcon);
+ cu.run(); // want this to run in this thread first...
+ new Timer("AAF Identity Refresh Timer",true).scheduleAtFixedRate(cu, EIGHT_HOURS,EIGHT_HOURS);
+ }
+ }
+ }
+
+ public static Set<String> trusted(String authMech) {
+ return trusted.get(authMech);
+ }
+
+ public Principal identity(HttpServletRequest req, X509Certificate cert, byte[] certBytes) throws CertificateException {
+ if(cert==null && certBytes==null)return null;
+ if(certBytes==null)certBytes = cert.getEncoded();
+ byte[] fingerprint = X509Taf.getFingerPrint(certBytes);
+ String id = certs.get(new ByteArrayHolder(fingerprint));
+ if(id!=null) { // Caller is Validated
+ return new X509Principal(id,cert,certBytes);
+ }
+ return null;
+ }
+
+ private static class ByteArrayHolder implements Comparable<ByteArrayHolder> {
+ private byte[] ba;
+ public ByteArrayHolder(byte[] ba) {
+ this.ba = ba;
+ }
+ public int compareTo(ByteArrayHolder b) {
+ return Hash.compareTo(ba, b.ba);
+ }
+ }
+
+ private class CertUpdate extends TimerTask {
+
+ private AAFCon<?> aafcon;
+ public CertUpdate(AAFCon<?> con) {
+ aafcon = con;
+ }
+
+ @Override
+ public void run() {
+ try {
+ TreeMap<ByteArrayHolder, String> newCertsMap = new TreeMap<ByteArrayHolder,String>();
+ Map<String,Set<String>> newTrustMap = new TreeMap<String,Set<String>>();
+ Set<String> userLookup = new HashSet<String>();
+ for(String s : certIDs) {
+ userLookup.add(s);
+ }
+ for(String authMech : authMechanisms) {
+ Future<Users> fusr = aafcon.client(AAF_VERSION).read("/authz/users/perm/com.att.aaf.trust/"+authMech+"/authenticate", Users.class, aafcon.usersDF);
+ if(fusr.get(5000)) {
+ List<User> users = fusr.value.getUser();
+ if(users.isEmpty()) {
+ aafcon.access.log(Level.WARN, "AAF Lookup-No IDs in Role com.att.aaf.trustForID <> "+authMech);
+ } else {
+ aafcon.access.log(Level.INFO,"Loading Trust Authentication Info for",authMech);
+ Set<String> hsUser = new HashSet<String>();
+ for(User u : users) {
+ userLookup.add(u.getId());
+ hsUser.add(u.getId());
+ }
+ newTrustMap.put(authMech,hsUser);
+ }
+ } else {
+ aafcon.access.log(Level.WARN, "Could not get Users in Perm com.att.trust|tguard|authenticate",fusr.code(),fusr.body());
+ }
+
+ }
+
+ for(String u : userLookup) {
+ Future<Certs> fc = aafcon.client(AAF_VERSION).read("/authn/cert/id/"+u, Certs.class, aafcon.certsDF);
+ XMLGregorianCalendar now = Chrono.timeStamp();
+ if(fc.get(5000)) {
+ List<Cert> certs = fc.value.getCert();
+ if(certs.isEmpty()) {
+ aafcon.access.log(Level.WARN, "No Cert Associations for",u);
+ } else {
+ for(Cert c : fc.value.getCert()) {
+ XMLGregorianCalendar then =c.getExpires();
+ if(then !=null && then.compare(now)>0) {
+ newCertsMap.put(new ByteArrayHolder(c.getFingerprint()), c.getId());
+ aafcon.access.log(Level.INIT,"Associating "+ c.getId() + " expiring " + Chrono.dateOnlyStamp(c.getExpires()) + " with " + c.getX500());
+ }
+ }
+ }
+ } else {
+ aafcon.access.log(Level.WARN, "Could not get Certificates for",u);
+ }
+ }
+
+ certs = newCertsMap;
+ trusted = newTrustMap;
+ } catch(Exception e) {
+ aafcon.access.log(e, "Failure to update Certificate Identities from AAF");
+ }
+ }
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/client/ErrMessage.java b/aaf/src/main/java/com/att/cadi/aaf/client/ErrMessage.java
new file mode 100644
index 0000000..7fc776a
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/client/ErrMessage.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.client;
+
+import java.io.PrintStream;
+
+import aaf.v2_0.Error;
+
+import com.att.cadi.client.Future;
+import com.att.cadi.util.Vars;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+public class ErrMessage {
+ private RosettaDF<Error> errDF;
+
+ public ErrMessage(RosettaEnv env) throws APIException {
+ errDF = env.newDataFactory(Error.class);
+ }
+
+ /**
+ * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.
+ *
+ * This code will create a meaningful string from this format.
+ *
+ * @param ps
+ * @param df
+ * @param r
+ * @throws APIException
+ */
+ public void printErr(PrintStream ps, String attErrJson) throws APIException {
+ StringBuilder sb = new StringBuilder();
+ Error err = errDF.newData().in(TYPE.JSON).load(attErrJson).asObject();
+ ps.println(toMsg(sb,err));
+ }
+
+ /**
+ * AT&T Requires a specific Error Format for RESTful Services, which AAF complies with.
+ *
+ * This code will create a meaningful string from this format.
+ *
+ * @param sb
+ * @param df
+ * @param r
+ * @throws APIException
+ */
+ public StringBuilder toMsg(StringBuilder sb, String attErrJson) throws APIException {
+ return toMsg(sb,errDF.newData().in(TYPE.JSON).load(attErrJson).asObject());
+ }
+
+ public StringBuilder toMsg(Future<?> future) {
+ return toMsg(new StringBuilder(),future);
+ }
+
+ public StringBuilder toMsg(StringBuilder sb, Future<?> future) {
+ try {
+ toMsg(sb,errDF.newData().in(TYPE.JSON).load(future.body()).asObject());
+ } catch(Exception e) {
+ //just print what we can
+ sb.append(future.code());
+ sb.append(": ");
+ sb.append(future.body());
+ }
+ return sb;
+ }
+
+ public StringBuilder toMsg(StringBuilder sb, Error err) {
+ sb.append(err.getMessageId());
+ sb.append(' ');
+ String[] vars = new String[err.getVariables().size()];
+ err.getVariables().toArray(vars);
+ Vars.convert(sb, err.getText(),vars);
+ return sb;
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/client/Examples.java b/aaf/src/main/java/com/att/cadi/aaf/client/Examples.java
new file mode 100644
index 0000000..e8a4756
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/client/Examples.java
@@ -0,0 +1,445 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.client;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.GregorianCalendar;
+
+import aaf.v2_0.Approval;
+import aaf.v2_0.Approvals;
+import aaf.v2_0.CredRequest;
+import aaf.v2_0.Keys;
+import aaf.v2_0.NsRequest;
+import aaf.v2_0.Nss;
+import aaf.v2_0.Nss.Ns;
+import aaf.v2_0.Perm;
+import aaf.v2_0.PermKey;
+import aaf.v2_0.PermRequest;
+import aaf.v2_0.Perms;
+import aaf.v2_0.Pkey;
+import aaf.v2_0.Request;
+import aaf.v2_0.Role;
+import aaf.v2_0.RoleKey;
+import aaf.v2_0.RolePermRequest;
+import aaf.v2_0.RoleRequest;
+import aaf.v2_0.Roles;
+import aaf.v2_0.UserRole;
+import aaf.v2_0.UserRoleRequest;
+import aaf.v2_0.UserRoles;
+import aaf.v2_0.Users;
+import aaf.v2_0.Users.User;
+
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.util.Chrono;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+public class Examples {
+ public static <C> String print(RosettaEnv env, String nameOrContentType, boolean optional) throws APIException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+ // Discover ClassName
+ String className = null;
+ String version = null;
+ TYPE type = TYPE.JSON; // default
+ if(nameOrContentType.startsWith("application/")) {
+ for(String ct : nameOrContentType.split("\\s*,\\s*")) {
+ for(String elem : ct.split("\\s*;\\s*")) {
+ if(elem.endsWith("+json")) {
+ type = TYPE.JSON;
+ className = elem.substring(elem.indexOf('/')+1, elem.length()-5);
+ } else if(elem.endsWith("+xml")) {
+ type = TYPE.XML;
+ className = elem.substring(elem.indexOf('/')+1, elem.length()-4);
+ } else if(elem.startsWith("version=")) {
+ version = elem.substring(8);
+ }
+ }
+ if(className!=null && version!=null)break;
+ }
+ if(className==null) {
+ throw new APIException(nameOrContentType + " does not contain Class Information");
+ }
+ } else {
+ className = nameOrContentType;
+ }
+
+ // No Void.class in aaf.v2_0 package causing errors when trying to use a newVoidv2_0
+ // method similar to others in this class. This makes it work, but is it right?
+ if ("Void".equals(className)) return "";
+
+ if("1.1".equals(version)) {
+ version = "v1_0";
+ } else if(version!=null) {
+ version = "v" + version.replace('.', '_');
+ } else {
+ version = "v2_0";
+ }
+
+ Class<?> cls;
+ try {
+ cls = Examples.class.getClassLoader().loadClass("aaf."+version+'.'+className);
+ } catch (ClassNotFoundException e) {
+ throw new APIException(e);
+ }
+
+ Method meth;
+ try {
+ meth = Examples.class.getDeclaredMethod("new"+cls.getSimpleName()+version,boolean.class);
+ } catch (Exception e) {
+ throw new APIException("ERROR: " + cls.getName() + " does not have an Example in Code. Request from AAF Developers");
+ }
+
+ RosettaDF<C> df = env.newDataFactory(cls);
+ df.option(Data.PRETTY);
+
+ Object data = meth.invoke(null,optional);
+
+ @SuppressWarnings("unchecked")
+ String rv = df.newData().load((C)data).out(type).asString();
+// Object obj = df.newData().in(type).load(rv).asObject();
+ return rv;
+ }
+
+ /*
+ * Set Base Class Request (easier than coding over and over)
+ */
+ private static void setOptional(Request req) {
+ GregorianCalendar gc = new GregorianCalendar();
+ req.setStart(Chrono.timeStamp(gc));
+ gc.add(GregorianCalendar.MONTH, 6);
+ req.setEnd(Chrono.timeStamp(gc));
+// req.setForce("false");
+
+ }
+
+ @SuppressWarnings("unused")
+ private static Request newRequestv2_0(boolean optional) {
+ Request r = new Request();
+ setOptional(r);
+ return r;
+ }
+ @SuppressWarnings("unused")
+ private static RolePermRequest newRolePermRequestv2_0(boolean optional) {
+ RolePermRequest rpr = new RolePermRequest();
+ Pkey pkey = new Pkey();
+ pkey.setType("com.att.myns.mytype");
+ pkey.setInstance("myInstance");
+ pkey.setAction("myAction");
+ rpr.setPerm(pkey);
+ rpr.setRole("com.att.myns.myrole");
+ if(optional)setOptional(rpr);
+ return rpr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Roles newRolesv2_0(boolean optional) {
+ Role r;
+ Pkey p;
+ Roles rs = new Roles();
+ rs.getRole().add(r = new Role());
+ r.setName("com.att.myns.myRole");
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myOtherAction");
+
+ rs.getRole().add(r = new Role());
+ r.setName("com.att.myns.myOtherRole");
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myOtherType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myOthertype");
+ p.setInstance("myInstance");
+ p.setAction("myOtherAction");
+
+ return rs;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static PermRequest newPermRequestv2_0(boolean optional) {
+ PermRequest pr = new PermRequest();
+ pr.setType("com.att.myns.myType");
+ pr.setInstance("myInstance");
+ pr.setAction("myAction");
+ if(optional) {
+ pr.setDescription("Short and meaningful verbiage about the Permission");
+
+ setOptional(pr);
+ }
+ return pr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Perm newPermv2_0(boolean optional) {
+ Perm pr = new Perm();
+ pr.setType("com.att.myns.myType");
+ pr.setInstance("myInstance");
+ pr.setAction("myAction");
+ pr.getRoles().add("com.att.myns.myRole");
+ pr.getRoles().add("com.att.myns.myRole2");
+ pr.setDescription("This is my description, and I'm sticking with it");
+ if(optional) {
+ pr.setDescription("Short and meaningful verbiage about the Permission");
+ }
+ return pr;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static PermKey newPermKeyv2_0(boolean optional) {
+ PermKey pr = new PermKey();
+ pr.setType("com.att.myns.myType");
+ pr.setInstance("myInstance");
+ pr.setAction("myAction");
+ return pr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Perms newPermsv2_0(boolean optional) {
+ Perms perms = new Perms();
+ Perm p;
+ perms.getPerm().add(p=new Perm());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+ p.getRoles().add("com.att.myns.myRole");
+ p.getRoles().add("com.att.myns.myRole2");
+
+
+ perms.getPerm().add(p=new Perm());
+ p.setType("com.att.myns.myOtherType");
+ p.setInstance("myInstance");
+ p.setAction("myOtherAction");
+ p.getRoles().add("com.att.myns.myRole");
+ p.getRoles().add("com.att.myns.myRole2");
+
+ return perms;
+
+ }
+
+ @SuppressWarnings("unused")
+ private static UserRoleRequest newUserRoleRequestv2_0(boolean optional) {
+ UserRoleRequest urr = new UserRoleRequest();
+ urr.setRole("com.att.myns.myRole");
+ urr.setUser("ab1234@csp.att.com");
+ if(optional) setOptional(urr);
+ return urr;
+ }
+
+ @SuppressWarnings("unused")
+ private static NsRequest newNsRequestv2_0(boolean optional) {
+ NsRequest nr = new NsRequest();
+ nr.setName("com.att.myns");
+ nr.getResponsible().add("ab1234@csp.att.com");
+ nr.getResponsible().add("cd5678@csp.att.com");
+ nr.getAdmin().add("zy9876@csp.att.com");
+ nr.getAdmin().add("xw5432@csp.att.com");
+ if(optional) {
+ nr.setDescription("This is my Namespace to set up");
+ nr.setType("APP");
+ setOptional(nr);
+ }
+ return nr;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static Nss newNssv2_0(boolean optional) {
+ Ns ns;
+
+ Nss nss = new Nss();
+ nss.getNs().add(ns = new Nss.Ns());
+ ns.setName("com.att.myns");
+ ns.getResponsible().add("ab1234@csp.att.com");
+ ns.getResponsible().add("cd5678@csp.att.com");
+ ns.getAdmin().add("zy9876@csp.att.com");
+ ns.getAdmin().add("xw5432@csp.att.com");
+ ns.setDescription("This is my Namespace to set up");
+
+ nss.getNs().add(ns = new Nss.Ns());
+ ns.setName("com.att.myOtherNs");
+ ns.getResponsible().add("ab1234@csp.att.com");
+ ns.getResponsible().add("cd5678@csp.att.com");
+ ns.getAdmin().add("zy9876@csp.att.com");
+ ns.getAdmin().add("xw5432@csp.att.com");
+
+ return nss;
+ }
+ @SuppressWarnings("unused")
+ private static RoleRequest newRoleRequestv2_0(boolean optional) {
+ RoleRequest rr = new RoleRequest();
+ rr.setName("com.att.myns.myRole");
+ if(optional) {
+ rr.setDescription("This is my Role");
+ setOptional(rr);
+ }
+ return rr;
+ }
+
+ @SuppressWarnings("unused")
+ private static CredRequest newCredRequestv2_0(boolean optional) {
+ CredRequest cr = new CredRequest();
+ cr.setId("myID@fully.qualified.domain");
+ if(optional) {
+ cr.setType(2);
+ cr.setEntry("0x125AB256344CE");
+ } else {
+ cr.setPassword("This is my provisioned password");
+ }
+
+ return cr;
+ }
+
+ @SuppressWarnings("unused")
+ private static Users newUsersv2_0(boolean optional) {
+ User user;
+
+ Users users = new Users();
+ users.getUser().add(user = new Users.User());
+ user.setId("ab1234@csp.att.com");
+ GregorianCalendar gc = new GregorianCalendar();
+ user.setExpires(Chrono.timeStamp(gc));
+
+ users.getUser().add(user = new Users.User());
+ user.setId("zy9876@csp.att.com");
+ user.setExpires(Chrono.timeStamp(gc));
+
+ return users;
+ }
+
+ @SuppressWarnings("unused")
+ private static Role newRolev2_0(boolean optional) {
+ Role r = new Role();
+ Pkey p;
+ r.setName("com.att.myns.myRole");
+ r.getPerms().add(p = new Pkey());
+ p.setType("com.att.myns.myType");
+ p.setInstance("myInstance");
+ p.setAction("myAction");
+
+ return r;
+ }
+
+ @SuppressWarnings("unused")
+ private static RoleKey newRoleKeyv2_0(boolean optional) {
+ RoleKey r = new RoleKey();
+ Pkey p;
+ r.setName("com.att.myns.myRole");
+ return r;
+ }
+
+ @SuppressWarnings("unused")
+ private static Keys newKeysv2_0(boolean optional) {
+ Keys ks = new Keys();
+ ks.getKey().add("Reponse 1");
+ ks.getKey().add("Response 2");
+ return ks;
+ }
+
+ @SuppressWarnings("unused")
+ private static UserRoles newUserRolesv2_0(boolean optional) {
+ UserRoles urs = new UserRoles();
+ UserRole ur = new UserRole();
+ ur.setUser("xy1234");
+ ur.setRole("com.test.myapp.myRole");
+ ur.setExpires(Chrono.timeStamp());
+ urs.getUserRole().add(ur);
+
+ ur = new UserRole();
+ ur.setUser("yx4321");
+ ur.setRole("com.test.yourapp.yourRole");
+ ur.setExpires(Chrono.timeStamp());
+ urs.getUserRole().add(ur);
+ return urs;
+ }
+
+
+ @SuppressWarnings("unused")
+ private static Approvals newApprovalsv2_0(boolean optional) {
+ Approvals as = new Approvals();
+ Approval a = new Approval();
+ a.setApprover("MyApprover");
+ a.setId("MyID");
+ a.setMemo("My memo (and then some)");
+ a.setOperation("MyOperation");
+ a.setStatus("MyStatus");
+ a.setTicket("MyTicket");
+ a.setType("MyType");
+ a.setUpdated(Chrono.timeStamp());
+ a.setUser("MyUser");
+ as.getApprovals().add(a);
+ a = new Approval();
+ a.setApprover("MyApprover2");
+ a.setId("MyID2");
+ a.setMemo("My memo (and then some)2");
+ a.setOperation("MyOperation2");
+ a.setStatus("MyStatus2");
+ a.setTicket("MyTicket2");
+ a.setType("MyType2");
+ a.setUpdated(Chrono.timeStamp());
+ a.setUser("MyUser2");
+ as.getApprovals().add(a);
+ return as;
+ }
+
+ @SuppressWarnings("unused")
+ private static Approval newApprovalv2_0(boolean optional) {
+ Approval a = new Approval();
+ a.setApprover("MyApprover");
+ a.setId("MyID");
+ a.setMemo("My memo (and then some)");
+ a.setOperation("MyOperation");
+ a.setStatus("MyStatus");
+ a.setTicket("MyTicket");
+ a.setType("MyType");
+ a.setUpdated(Chrono.timeStamp());
+ a.setUser("MyUser");
+ return a;
+ }
+
+
+
+ @SuppressWarnings("unused")
+ private static aaf.v2_0.Error newErrorv2_0(boolean optional) {
+ aaf.v2_0.Error err = new aaf.v2_0.Error();
+ err.setMessageId("SVC1403");
+ err.setText("MyText %s, %s: The last three digits are usually the HTTP Code");
+ err.getVariables().add("Variable 1");
+ err.getVariables().add("Variable 2");
+ return err;
+ }
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java b/aaf/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java
new file mode 100644
index 0000000..4193d43
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/marshal/CertMarshal.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.marshal;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import aaf.v2_0.Certs.Cert;
+
+import com.att.rosetta.marshal.FieldDateTime;
+import com.att.rosetta.marshal.FieldHexBinary;
+import com.att.rosetta.marshal.FieldString;
+import com.att.rosetta.marshal.ObjMarshal;
+
+public class CertMarshal extends ObjMarshal<Cert> {
+ public CertMarshal() {
+ add(new FieldHexBinary<Cert>("fingerprint") {
+ @Override
+ protected byte[] data(Cert t) {
+ return t.getFingerprint();
+ }
+ });
+
+ add(new FieldString<Cert>("id") {
+ @Override
+ protected String data(Cert t) {
+ return t.getId();
+ }
+ });
+
+ add(new FieldString<Cert>("x500") {
+ @Override
+ protected String data(Cert t) {
+ return t.getX500();
+ }
+ });
+
+ add(new FieldDateTime<Cert>("expires") {
+ @Override
+ protected XMLGregorianCalendar data(Cert t) {
+ return t.getExpires();
+ }
+ });
+
+
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java b/aaf/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.java
new file mode 100644
index 0000000..16fc580
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/marshal/CertsMarshal.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.cadi.aaf.marshal;
+
+import java.util.List;
+
+import aaf.v2_0.Certs;
+import aaf.v2_0.Certs.Cert;
+
+import com.att.rosetta.marshal.ObjArray;
+import com.att.rosetta.marshal.ObjMarshal;
+
+public class CertsMarshal extends ObjMarshal<Certs> {
+
+ public CertsMarshal() {
+ add(new ObjArray<Certs,Cert>("cert",new CertMarshal()) {
+ @Override
+ protected List<Cert> data(Certs t) {
+ return t.getCert();
+ }
+ });
+ }
+
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java
new file mode 100644
index 0000000..db60495
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFAuthn.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.v2_0;
+
+import java.io.IOException;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CadiException;
+import com.att.cadi.GetCred;
+import com.att.cadi.Hash;
+import com.att.cadi.User;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.config.Config;
+import com.att.cadi.lur.ConfigPrincipal;
+import com.att.inno.env.APIException;
+
+public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {
+ private AAFCon<CLIENT> con;
+ private String realm;
+
+ /**
+ * Configure with Standard AAF properties, Stand alone
+ * @param con
+ * @throws Exception
+ */
+ // Package on purpose
+ AAFAuthn(AAFCon<CLIENT> con) throws Exception {
+ super(con.access,con.cleanInterval,con.highCount,con.usageRefreshTriggerCount);
+ this.con = con;
+
+ try {
+ setRealm();
+ } catch (APIException e) {
+ if(e.getCause() instanceof DME2Exception) {
+ // Can't contact AAF, assume default
+ realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());
+ }
+ }
+ }
+
+ /**
+ * Configure with Standard AAF properties, but share the Cache (with AAF Lur)
+ * @param con
+ * @throws Exception
+ */
+ // Package on purpose
+ AAFAuthn(AAFCon<CLIENT> con, AbsUserCache<AAFPermission> cache) throws Exception {
+ super(cache);
+ this.con = con;
+ try {
+ setRealm();
+ } catch (Exception e) {
+ if(e.getCause() instanceof DME2Exception) {
+ access.log(e);
+ // Can't contact AAF, assume default
+ realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());
+ }
+ }
+ }
+
+ private void setRealm() throws Exception {
+ // Make a call without security set to get the 401 response, which
+ // includes the Realm of the server
+ // This also checks on Connectivity early on.
+ Future<String> fp = con.client(AAFCon.AAF_LATEST_VERSION).read("/authn/basicAuth", "text/plain");
+ if(fp.get(con.timeout)) {
+ throw new Exception("Do not preset Basic Auth Information for AAFAuthn");
+ } else {
+ if(fp.code()==401) {
+ realm = fp.header("WWW-Authenticate");
+ if(realm!=null && realm.startsWith("Basic realm=\"")) {
+ realm = realm.substring(13, realm.length()-1);
+ } else {
+ realm = "unknown.com";
+ }
+ }
+ }
+ }
+
+ /**
+ * Return Native Realm of AAF Instance.
+ *
+ * @return
+ */
+ public String getRealm() {
+ return realm;
+ }
+
+ /**
+ * Returns null if ok, or an Error String;
+ *
+ * @param user
+ * @param password
+ * @return
+ * @throws IOException
+ * @throws CadiException
+ * @throws Exception
+ */
+ public String validate(String user, String password) throws IOException, CadiException {
+ User<AAFPermission> usr = getUser(user);
+ if(password.startsWith("enc:???")) {
+ password = access.decrypt(password, true);
+ }
+
+ byte[] bytes = password.getBytes();
+ if(usr != null && usr.principal != null && usr.principal.getName().equals(user)
+ && usr.principal instanceof GetCred) {
+
+ if(Hash.isEqual(((GetCred)usr.principal).getCred(),bytes)) {
+ return null;
+ } else {
+ remove(usr);
+ usr = null;
+ }
+ }
+
+ AAFCachedPrincipal cp = new AAFCachedPrincipal(this,con.app, user, bytes, con.cleanInterval);
+ // Since I've relocated the Validation piece in the Principal, just revalidate, then do Switch
+ // Statement
+ switch(cp.revalidate()) {
+ case REVALIDATED:
+ if(usr!=null) {
+ usr.principal = cp;
+ } else {
+ addUser(new User<AAFPermission>(cp,con.timeout));
+ }
+ return null;
+ case INACCESSIBLE:
+ return "AAF Inaccessible";
+ case UNVALIDATED:
+ return "User/Pass combo invalid for " + user;
+ case DENIED:
+ return "AAF denies API for " + user;
+ default:
+ return "AAFAuthn doesn't handle Principal " + user;
+ }
+ }
+
+ private class AAFCachedPrincipal extends ConfigPrincipal implements CachedPrincipal {
+ private long expires,timeToLive;
+
+ public AAFCachedPrincipal(AAFAuthn<?> aaf, String app, String name, byte[] pass, int timeToLive) {
+ super(name,pass);
+ this.timeToLive = timeToLive;
+ expires = timeToLive + System.currentTimeMillis();
+ }
+
+ public Resp revalidate() {
+ if(con.isDisabled()) {
+ return Resp.DENIED;
+ }
+ try {
+ Miss missed = missed(getName());
+ if(missed==null || missed.mayContinue(getCred())) {
+ Rcli<CLIENT> client = con.client(AAFCon.AAF_LATEST_VERSION).forUser(con.basicAuth(getName(), new String(getCred())));
+ Future<String> fp = client.read(
+ "/authn/basicAuth",
+ "text/plain"
+ );
+ if(fp.get(con.timeout)) {
+ expires = System.currentTimeMillis() + timeToLive;
+ addUser(new User<AAFPermission>(this, expires));
+ return Resp.REVALIDATED;
+ } else {
+ addMiss(getName(), getCred());
+ return Resp.UNVALIDATED;
+ }
+ } else {
+ return Resp.UNVALIDATED;
+ }
+ } catch (Exception e) {
+ con.access.log(e);
+ return Resp.INACCESSIBLE;
+ }
+ }
+
+ public long expires() {
+ return expires;
+ }
+ };
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java
new file mode 100644
index 0000000..573c85e
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFCon.java
@@ -0,0 +1,396 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.v2_0;
+
+import java.net.URI;
+import java.security.Principal;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.CadiException;
+import com.att.cadi.CadiWrap;
+import com.att.cadi.Connector;
+import com.att.cadi.LocatorException;
+import com.att.cadi.Lur;
+import com.att.cadi.PropAccess;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.marshal.CertsMarshal;
+import com.att.cadi.client.AbsBasicAuth;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.lur.EpiLur;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.util.Vars;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.util.Split;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+import aaf.v2_0.Certs;
+import aaf.v2_0.Error;
+import aaf.v2_0.Perms;
+import aaf.v2_0.Users;
+
+public abstract class AAFCon<CLIENT> implements Connector {
+ public static final String AAF_LATEST_VERSION = "2.0";
+
+ final public PropAccess access;
+ // Package access
+ final public int timeout, cleanInterval, connTimeout;
+ final public int highCount, userExpires, usageRefreshTriggerCount;
+ private Map<String,Rcli<CLIENT>> clients = new ConcurrentHashMap<String,Rcli<CLIENT>>();
+ final public RosettaDF<Perms> permsDF;
+ final public RosettaDF<Certs> certsDF;
+ final public RosettaDF<Users> usersDF;
+ final public RosettaDF<Error> errDF;
+ private String realm;
+ public final String app;
+ protected SecuritySetter<CLIENT> ss;
+ protected SecurityInfoC<CLIENT> si;
+
+ private DisableCheck disableCheck;
+
+ private AAFLurPerm lur;
+
+ private RosettaEnv env;
+ protected abstract URI initURI();
+ protected abstract void setInitURI(String uriString) throws CadiException;
+
+ /**
+ * Use this call to get the appropriate client based on configuration (DME2, HTTP, future)
+ *
+ * @param apiVersion
+ * @return
+ * @throws CadiException
+ */
+ public Rcli<CLIENT> client(String apiVersion) throws CadiException {
+ Rcli<CLIENT> client = clients.get(apiVersion);
+ if(client==null) {
+ client = rclient(initURI(),ss);
+ client.apiVersion(apiVersion)
+ .readTimeout(connTimeout);
+ clients.put(apiVersion, client);
+ }
+ return client;
+ }
+
+ /**
+ * Use this API when you have permission to have your call act as the end client's ID.
+ *
+ * Your calls will get 403 errors if you do not have this permission. it is a special setup, rarely given.
+ *
+ * @param apiVersion
+ * @param req
+ * @return
+ * @throws CadiException
+ */
+ public Rcli<CLIENT> clientAs(String apiVersion, ServletRequest req) throws CadiException {
+ Rcli<CLIENT> cl = client(apiVersion);
+ return cl.forUser(transferSS(((HttpServletRequest)req).getUserPrincipal()));
+ }
+
+ protected AAFCon(AAFCon<CLIENT> copy) {
+ access = copy.access;
+ timeout = copy.timeout;
+ cleanInterval = copy.cleanInterval;
+ connTimeout = copy.connTimeout;
+ highCount = copy.highCount;
+ userExpires = copy.userExpires;
+ usageRefreshTriggerCount = copy.usageRefreshTriggerCount;
+ permsDF = copy.permsDF;
+ certsDF = copy.certsDF;
+ usersDF = copy.usersDF;
+ errDF = copy.errDF;
+ app = copy.app;
+ ss = copy.ss;
+ si = copy.si;
+ env = copy.env;
+ disableCheck = copy.disableCheck;
+ realm = copy.realm;
+ }
+
+ protected AAFCon(PropAccess access, String tag, SecurityInfoC<CLIENT> si) throws CadiException{
+ if(tag==null) {
+ throw new CadiException("AAFCon cannot be constructed with a tag=null");
+ }
+ try {
+ this.access = access;
+ this.si = si;
+ this.ss = si.defSS;
+ if(ss==null) {
+ String mechid = access.getProperty(Config.AAF_MECHID, null);
+ String encpass = access.getProperty(Config.AAF_MECHPASS, null);
+ if(encpass==null) {
+ String alias = access.getProperty(Config.CADI_ALIAS, mechid);
+ if(alias==null) {
+ throw new CadiException(Config.CADI_ALIAS + " or " + Config.AAF_MECHID + " required.");
+ }
+ set(si.defSS=x509Alias(alias));
+ } else {
+ if(mechid!=null && encpass !=null) {
+ set(si.defSS=basicAuth(mechid, encpass));
+ } else {
+ set(si.defSS=new SecuritySetter<CLIENT>() {
+
+ @Override
+ public String getID() {
+ return "";
+ }
+
+ @Override
+ public void setSecurity(CLIENT client) throws CadiException {
+ throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+ });
+ }
+ }
+ }
+
+ timeout = Integer.parseInt(access.getProperty(Config.AAF_READ_TIMEOUT, Config.AAF_READ_TIMEOUT_DEF));
+ cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));
+ highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());
+ connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());
+ userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());
+ usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based
+
+ String str = access.getProperty(tag,null);
+ if(str==null) {
+ throw new CadiException(tag + " property is required.");
+ }
+ setInitURI(str);
+
+ app=reverseDomain(ss.getID());
+ realm="openecomp.org";
+
+ env = new RosettaEnv();
+ permsDF = env.newDataFactory(Perms.class);
+ usersDF = env.newDataFactory(Users.class);
+ certsDF = env.newDataFactory(Certs.class);
+ certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling
+ errDF = env.newDataFactory(Error.class);
+ } catch (APIException e) {
+ throw new CadiException("AAFCon cannot be configured",e);
+ }
+ }
+
+ public RosettaEnv env() {
+ return env;
+ }
+
+ /**
+ * Return the backing AAFCon, if there is a Lur Setup that is AAF.
+ *
+ * If there is no AAFLur setup, it will return "null"
+ * @param servletRequest
+ * @return
+ */
+ public static final AAFCon<?> obtain(Object servletRequest) {
+ if(servletRequest instanceof CadiWrap) {
+ Lur lur = ((CadiWrap)servletRequest).getLur();
+ if(lur != null) {
+ if(lur instanceof EpiLur) {
+ AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);
+ if(aal!=null) {
+ return aal.aaf;
+ }
+ } else {
+ if(lur instanceof AbsAAFLur) {
+ return ((AbsAAFLur<?>)lur).aaf;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public abstract AAFCon<CLIENT> clone(String url) throws CadiException;
+
+ public AAFAuthn<CLIENT> newAuthn() throws APIException {
+ try {
+ return new AAFAuthn<CLIENT>(this);
+ } catch (APIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) throws APIException {
+ try {
+ return new AAFAuthn<CLIENT>(this,c);
+ } catch (APIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ public AAFLurPerm newLur() throws CadiException {
+ try {
+ if(lur==null) {
+ return new AAFLurPerm(this);
+ } else {
+ return new AAFLurPerm(this,lur);
+ }
+ } catch (CadiException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {
+ try {
+ return new AAFLurPerm(this,c);
+ } catch (APIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ /**
+ * Take a Fully Qualified User, and get a Namespace from it.
+ * @param user
+ * @return
+ */
+ public static String reverseDomain(String user) {
+ StringBuilder sb = null;
+ String[] split = Split.split('.',user);
+ int at;
+ for(int i=split.length-1;i>=0;--i) {
+ if(sb == null) {
+ sb = new StringBuilder();
+ } else {
+ sb.append('.');
+ }
+
+ if((at = split[i].indexOf('@'))>0) {
+ sb.append(split[i].subSequence(at+1, split[i].length()));
+ } else {
+ sb.append(split[i]);
+ }
+ }
+
+ return sb==null?"":sb.toString();
+ }
+
+ protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;
+
+ public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
+
+
+ public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;
+
+ public abstract SecuritySetter<CLIENT> transferSS(Principal principal) throws CadiException;
+
+ public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;
+
+ public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;
+
+
+ public String getRealm() {
+ return realm;
+
+ }
+
+ public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {
+ this.ss = ss;
+ if(ss instanceof AbsBasicAuth) {
+ disableCheck = (ss instanceof AbsBasicAuth)?
+ new DisableCheck() {
+ AbsBasicAuth<?> aba = (AbsBasicAuth<?>)ss;
+ @Override
+ public boolean isDisabled() {
+ return aba.isDenied();
+ }
+ }:
+ new DisableCheck() {
+ @Override
+ public boolean isDisabled() {
+ return this.isDisabled();
+ }
+ };
+ }
+ for(Rcli<CLIENT> client : clients.values()) {
+ client.setSecuritySetter(ss);
+ }
+ return ss;
+ }
+
+ public SecurityInfoC<CLIENT> securityInfo() {
+ return si;
+ }
+
+ public String defID() {
+ if(ss!=null) {
+ return ss.getID();
+ }
+ return "unknown";
+ }
+
+ public void invalidate() throws CadiException {
+ for(Rcli<CLIENT> client : clients.values()) {
+ client.invalidate();
+ clients.remove(client);
+ }
+ }
+
+ public String readableErrMsg(Future<?> f) {
+ String text = f.body();
+ if(text==null || text.length()==0) {
+ text = f.code() + ": **No Message**";
+ } else if(text.contains("%")) {
+ try {
+ Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();
+ return Vars.convert(err.getText(),err.getVariables());
+ } catch (APIException e){
+ // just return the body below
+ }
+ }
+ return text;
+ }
+
+ private interface DisableCheck {
+ public boolean isDisabled();
+ };
+
+ public boolean isDisabled() {
+ return disableCheck.isDisabled();
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java
new file mode 100644
index 0000000..7092613
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConDME2.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.v2_0;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.util.Properties;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.CadiException;
+import com.att.cadi.LocatorException;
+import com.att.cadi.PropAccess;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.dme2.DME2BasicAuth;
+import com.att.cadi.dme2.DME2TransferSS;
+import com.att.cadi.dme2.DME2x509SS;
+import com.att.cadi.dme2.DRcli;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.inno.env.APIException;
+
+public class AAFConDME2 extends AAFCon<DME2Client>{
+ private DME2Manager manager;
+ private boolean isProxy;
+ private URI initURI;
+
+ public AAFConDME2(PropAccess access) throws CadiException, GeneralSecurityException, IOException{
+ super(access,Config.AAF_URL,new SecurityInfoC<DME2Client> (access));
+ manager = newManager(access);
+ setIsProxy();
+ }
+
+ public AAFConDME2(PropAccess access, String url) throws CadiException, GeneralSecurityException, IOException{
+ super(access,url,new SecurityInfoC<DME2Client> (access));
+ manager = newManager(access);
+ setIsProxy();
+ }
+
+ public AAFConDME2(PropAccess access, SecurityInfoC<DME2Client> si) throws CadiException {
+ super(access,Config.AAF_URL,si);
+ manager = newManager(access);
+ setIsProxy();
+ }
+
+ public AAFConDME2(PropAccess access, String url, SecurityInfoC<DME2Client> si) throws CadiException {
+ super(access,url,si);
+ manager = newManager(access);
+ setIsProxy();
+ }
+
+ /**
+ * Construct a Connector based on the AAF one. This is for remote access to OTHER than AAF,
+ * but using Credentials, etc
+ */
+ private AAFConDME2(AAFCon<DME2Client> aafcon, String url) throws CadiException {
+ super(aafcon);
+ try {
+ initURI = new URI(url);
+ } catch (URISyntaxException e) {
+ throw new CadiException(e);
+ }
+ manager = newManager(access);
+ }
+
+ /**
+ * Create a Connector based on the AAF one. This is for remote access to OTHER than AAF,
+ * but using Credentials, etc
+ */
+ public AAFCon<DME2Client> clone(String url) throws CadiException {
+ return new AAFConDME2(this,url);
+ }
+
+ private void setIsProxy() {
+ String str;
+ if((str=access.getProperty(Config.AAF_URL, null))!=null) {
+ isProxy = str.contains("service=com.att.authz.authz-gw/version=");
+ }
+ }
+
+ private DME2Manager newManager(PropAccess access) throws CadiException {
+ Properties props = access.getDME2Properties();
+ // Critical that TLS Settings not ignored
+ try {
+ return new DME2Manager("AAFCon",props);
+ } catch (DME2Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)
+ */
+ @Override
+ public SecuritySetter<DME2Client> basicAuth(String user, String password) throws CadiException {
+ if(password.startsWith("enc:???")) {
+ try {
+ password = access.decrypt(password, true);
+ } catch (IOException e) {
+ throw new CadiException("Error Decrypting Password",e);
+ }
+ }
+
+ try {
+ return set(new DME2BasicAuth(user,password,si));
+ } catch (IOException e) {
+ throw new CadiException("Error setting up DME2BasicAuth",e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)
+ */
+ @Override
+ protected Rcli<DME2Client> rclient(URI uri, SecuritySetter<DME2Client> ss) {
+ DRcli dc = new DRcli(uri, ss);
+ dc.setProxy(isProxy);
+ dc.setManager(manager);
+ return dc;
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> transferSS(Principal principal) throws CadiException {
+ try {
+ return principal==null?ss:new DME2TransferSS(principal, app, si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating DME2TransferSS",e);
+ }
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> basicAuthSS(BasicPrincipal principal) throws CadiException {
+ try {
+ return new DME2BasicAuth(principal,si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating DME2BasicAuth",e);
+ }
+
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> x509Alias(String alias) throws CadiException {
+ try {
+ presetProps(access, alias);
+ return new DME2x509SS(alias,si);
+ } catch (Exception e) {
+ throw new CadiException("Error creating DME2x509SS",e);
+ }
+ }
+
+ @Override
+ public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ // NOTE: DME2 had Retry Logic embedded lower.
+ try {
+ return (retryable.code(rclient(initURI,ss)));
+ } catch (ConnectException e) {
+ // DME2 should catch
+ try {
+ manager.refresh();
+ } catch (Exception e1) {
+ throw new CadiException(e1);
+ }
+ throw new CadiException(e);
+ }
+ }
+
+ public static void presetProps(PropAccess access, String alias) throws IOException {
+ System.setProperty(Config.AFT_DME2_CLIENT_SSL_CERT_ALIAS, alias);
+ if(System.getProperty(Config.AFT_DME2_CLIENT_IGNORE_SSL_CONFIG)==null) {
+ access.getDME2Properties();
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#initURI()
+ */
+ @Override
+ protected URI initURI() {
+ return initURI;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#setInitURI(java.lang.String)
+ */
+ @Override
+ protected void setInitURI(String uriString) throws CadiException {
+ try {
+ initURI = new URI(uriString);
+ } catch (URISyntaxException e) {
+ throw new CadiException(e);
+ }
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java
new file mode 100644
index 0000000..5454773
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFConHttp.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.v2_0;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.LocatorException;
+import com.att.cadi.PropAccess;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.AbsTransferSS;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.http.HMangr;
+import com.att.cadi.http.HRcli;
+import com.att.cadi.http.HTransferSS;
+import com.att.cadi.http.HX509SS;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.inno.env.APIException;
+
+public class AAFConHttp extends AAFCon<HttpURLConnection> {
+ private final HMangr hman;
+
+ public AAFConHttp(PropAccess access) throws CadiException, GeneralSecurityException, IOException {
+ super(access,Config.AAF_URL,new SecurityInfoC<HttpURLConnection>(access));
+ hman = new HMangr(access,Config.loadLocator(access, access.getProperty(Config.AAF_URL,null)));
+ }
+
+ public AAFConHttp(PropAccess access, String tag) throws CadiException, GeneralSecurityException, IOException {
+ super(access,tag,new SecurityInfoC<HttpURLConnection>(access));
+ hman = new HMangr(access,Config.loadLocator(access, access.getProperty(tag,null)));
+ }
+
+ public AAFConHttp(PropAccess access, String urlTag, SecurityInfoC<HttpURLConnection> si) throws CadiException {
+ super(access,urlTag,si);
+ hman = new HMangr(access,Config.loadLocator(access, access.getProperty(urlTag,null)));
+ }
+
+ public AAFConHttp(PropAccess access, Locator<URI> locator) throws CadiException, GeneralSecurityException, IOException {
+ super(access,Config.AAF_URL,new SecurityInfoC<HttpURLConnection>(access));
+ hman = new HMangr(access,locator);
+ }
+
+ public AAFConHttp(PropAccess access, Locator<URI> locator, SecurityInfoC<HttpURLConnection> si) throws CadiException {
+ super(access,Config.AAF_URL,si);
+ hman = new HMangr(access,locator);
+ }
+
+ public AAFConHttp(PropAccess access, Locator<URI> locator, SecurityInfoC<HttpURLConnection> si, String tag) throws CadiException {
+ super(access,tag,si);
+ hman = new HMangr(access, locator);
+ }
+
+ private AAFConHttp(AAFCon<HttpURLConnection> aafcon, String url) {
+ super(aafcon);
+ hman = new HMangr(aafcon.access,Config.loadLocator(access, url));
+ }
+
+ @Override
+ public AAFCon<HttpURLConnection> clone(String url) {
+ return new AAFConHttp(this,url);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuth(java.lang.String, java.lang.String)
+ */
+ @Override
+ public SecuritySetter<HttpURLConnection> basicAuth(String user, String password) throws CadiException {
+ if(password.startsWith("enc:???")) {
+ try {
+ password = access.decrypt(password, true);
+ } catch (IOException e) {
+ throw new CadiException("Error decrypting password",e);
+ }
+ }
+ try {
+ return new HBasicAuthSS(user,password,si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating HBasicAuthSS",e);
+ }
+ }
+
+ public SecuritySetter<HttpURLConnection> x509Alias(String alias) throws APIException, CadiException {
+ try {
+ return set(new HX509SS(alias,si));
+ } catch (Exception e) {
+ throw new CadiException("Error creating X509SS",e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#rclient(java.net.URI, com.att.cadi.SecuritySetter)
+ */
+ @Override
+ protected Rcli<HttpURLConnection> rclient(URI ignoredURI, SecuritySetter<HttpURLConnection> ss) throws CadiException {
+ if(hman.loc==null) {
+ throw new CadiException("No Locator set in AAFConHttp");
+ }
+ try {
+ return new HRcli(hman, hman.loc.best() ,ss);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ @Override
+ public AbsTransferSS<HttpURLConnection> transferSS(Principal principal) throws CadiException {
+ return new HTransferSS(principal, app,si);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#basicAuthSS(java.security.Principal)
+ */
+ @Override
+ public SecuritySetter<HttpURLConnection> basicAuthSS(BasicPrincipal principal) throws CadiException {
+ try {
+ return new HBasicAuthSS(principal,si);
+ } catch (IOException e) {
+ throw new CadiException("Error creating HBasicAuthSS",e);
+ }
+ }
+
+ public HMangr hman() {
+ return hman;
+ }
+
+ @Override
+ public <RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ return hman.best(ss, (Retryable<RET>)retryable);
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#initURI()
+ */
+ @Override
+ protected URI initURI() {
+ try {
+ Item item = hman.loc.best();
+ if(item!=null) {
+ return hman.loc.get(item);
+ }
+ } catch (LocatorException e) {
+ access.log(e, "Error in AAFConHttp obtaining initial URI");
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.aaf.v2_0.AAFCon#setInitURI(java.lang.String)
+ */
+ @Override
+ protected void setInitURI(String uriString) throws CadiException {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java
new file mode 100644
index 0000000..db03347
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFLurPerm.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.v2_0;
+
+import java.net.ConnectException;
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.Map;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.CadiException;
+import com.att.cadi.Permission;
+import com.att.cadi.User;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.cadi.lur.LocalPermission;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Split;
+
+import aaf.v2_0.Perm;
+import aaf.v2_0.Perms;
+
+/**
+ * Use AAF Service as Permission Service.
+ *
+ * This Lur goes after AAF Permissions, which are elements of Roles, not the Roles themselves.
+ *
+ * If you want a simple Role Lur, use AAFRoleLur
+ *
+ *
+ */
+public class AAFLurPerm extends AbsAAFLur<AAFPermission> {
+ /**
+ * Need to be able to transmutate a Principal into either ATTUID or MechID, which are the only ones accepted at this
+ * point by AAF. There is no "domain", aka, no "@att.com" in "ab1234@att.com".
+ *
+ * The only thing that matters here for AAF is that we don't waste calls with IDs that obviously aren't valid.
+ * Thus, we validate that the ID portion follows the rules before we waste time accessing AAF remotely
+ * @throws APIException
+ * @throws URISyntaxException
+ * @throws DME2Exception
+ */
+ // Package on purpose
+ AAFLurPerm(AAFCon<?> con) throws CadiException, DME2Exception, URISyntaxException, APIException {
+ super(con);
+ }
+
+ // Package on purpose
+ AAFLurPerm(AAFCon<?> con, AbsUserCache<AAFPermission> auc) throws DME2Exception, URISyntaxException, APIException {
+ super(con,auc);
+ }
+
+ protected User<AAFPermission> loadUser(Principal p) {
+ // Note: The rules for AAF is that it only stores permissions for ATTUID and MechIDs, which don't
+ // have domains. We are going to make the Transitive Class (see this.transmutative) to convert
+ Principal principal = transmutate.mutate(p);
+ if(principal==null)return null; // if not a valid Transmutated credential, don't bother calling...
+ return loadUser(p, p.getName());
+ }
+
+ protected User<AAFPermission> loadUser(String name) {
+ return loadUser((Principal)null, name);
+ }
+
+ private User<AAFPermission> loadUser(final Principal prin, final String name) {
+
+ //TODO Create a dynamic way to declare domains supported.
+ final long start = System.nanoTime();
+ final boolean[] success = new boolean[]{false};
+
+// new Exception("loadUser").printStackTrace();
+ try {
+ return aaf.best(new Retryable<User<AAFPermission>>() {
+ @Override
+ public User<AAFPermission> code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+ Future<Perms> fp = client.read("/authz/perms/user/"+name,aaf.permsDF);
+
+ // In the meantime, lookup User, create if necessary
+ User<AAFPermission> user = getUser(name);
+ Principal p;
+ if(prin == null) {
+ p = new Principal() {// Create a holder for lookups
+ private String n = name;
+ public String getName() {
+ return n;
+ }
+ };
+ } else {
+ p = prin;
+ }
+
+ if(user==null) {
+ addUser(user = new User<AAFPermission>(p,aaf.userExpires)); // no password
+ }
+
+ // OK, done all we can, now get content
+ if(fp.get(aaf.timeout)) {
+ success[0]=true;
+ Map<String, Permission> newMap = user.newMap();
+ boolean willLog = aaf.access.willLog(Level.DEBUG);
+ for(Perm perm : fp.value.getPerm()) {
+ user.add(newMap,new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));
+ if(willLog) {
+ aaf.access.log(Level.DEBUG, name,"has '",perm.getType(),'|',perm.getInstance(),'|',perm.getAction(),'\'');
+ }
+ }
+ user.setMap(newMap);
+ user.renewPerm();
+ } else {
+ int code;
+ switch(code=fp.code()) {
+ case 401:
+ aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
+ break;
+ default:
+ aaf.access.log(Access.Level.ERROR, code, fp.body());
+ }
+ }
+
+ return user;
+ }
+ });
+ } catch (Exception e) {
+ aaf.access.log(e,"Calling","/authz/perms/user/"+name);
+ success[0]=false;
+ return null;
+ } finally {
+ float time = (System.nanoTime()-start)/1000000f;
+ aaf.access.log(Level.INFO, success[0]?"Loaded":"Load Failure",name,"from AAF in",time,"ms");
+ }
+ }
+
+ public Resp reload(User<AAFPermission> user) {
+ final String name = user.principal.getName();
+ long start = System.nanoTime();
+ boolean success = false;
+ try {
+ Future<Perms> fp = aaf.client(AAFCon.AAF_LATEST_VERSION).read(
+ "/authz/perms/user/"+name,
+ aaf.permsDF
+ );
+
+ // OK, done all we can, now get content
+ if(fp.get(aaf.timeout)) {
+ success = true;
+ Map<String,Permission> newMap = user.newMap();
+ boolean willLog = aaf.access.willLog(Level.DEBUG);
+ for(Perm perm : fp.value.getPerm()) {
+ user.add(newMap, new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction()));
+ if(willLog) {
+ aaf.access.log(Level.DEBUG, name,"has",perm.getType(),perm.getInstance(),perm.getAction());
+ }
+ }
+ user.renewPerm();
+ return Resp.REVALIDATED;
+ } else {
+ int code;
+ switch(code=fp.code()) {
+ case 401:
+ aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
+ break;
+ default:
+ aaf.access.log(Access.Level.ERROR, code, fp.body());
+ }
+ return Resp.UNVALIDATED;
+ }
+ } catch (Exception e) {
+ aaf.access.log(e,"Calling","/authz/perms/user/"+name);
+ return Resp.INACCESSIBLE;
+ } finally {
+ float time = (System.nanoTime()-start)/1000000f;
+ aaf.access.log(Level.AUDIT, success?"Reloaded":"Reload Failure",name,"from AAF in",time,"ms");
+ }
+ }
+
+ @Override
+ protected boolean isCorrectPermType(Permission pond) {
+ return pond instanceof AAFPermission;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.Lur#createPerm(java.lang.String)
+ */
+ @Override
+ public Permission createPerm(String p) {
+ String[] params = Split.split('|', p);
+ if(params.length==3) {
+ return new AAFPermission(params[0],params[1],params[2]);
+ } else {
+ return new LocalPermission(p);
+ }
+ }
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java
new file mode 100644
index 0000000..35df38f
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTaf.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.v2_0;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachedPrincipal;
+import com.att.cadi.CachedPrincipal.Resp;
+import com.att.cadi.GetCred;
+import com.att.cadi.Hash;
+import com.att.cadi.Taf.LifeForm;
+import com.att.cadi.User;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.principal.CachedBasicPrincipal;
+import com.att.cadi.taf.HttpTaf;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TafResp.RESP;
+import com.att.cadi.taf.basic.BasicHttpTafResp;
+
+public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpTaf {
+// private static final String INVALID_AUTH_TOKEN = "Invalid Auth Token";
+// private static final String AUTHENTICATING_SERVICE_UNAVAILABLE = "Authenticating Service unavailable";
+ private AAFCon<CLIENT> aaf;
+ private boolean warn;
+
+ public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning) {
+ super(con.access,con.cleanInterval,con.highCount, con.usageRefreshTriggerCount);
+ aaf = con;
+ warn = turnOnWarning;
+ }
+
+ public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning, AbsUserCache<AAFPermission> other) {
+ super(other);
+ aaf = con;
+ warn = turnOnWarning;
+ }
+
+ public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
+ //TODO Do we allow just anybody to validate?
+
+ // Note: Either Carbon or Silicon based LifeForms ok
+ String authz = req.getHeader("Authorization");
+ if(authz != null && authz.startsWith("Basic ")) {
+ if(warn&&!req.isSecure())aaf.access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");
+ try {
+ CachedBasicPrincipal bp;
+ if(req.getUserPrincipal() instanceof CachedBasicPrincipal) {
+ bp = (CachedBasicPrincipal)req.getUserPrincipal();
+ } else {
+ bp = new CachedBasicPrincipal(this,authz,aaf.getRealm(),aaf.userExpires);
+ }
+ // First try Cache
+ User<AAFPermission> usr = getUser(bp);
+ if(usr != null && usr.principal != null) {
+ if(usr.principal instanceof GetCred) {
+ if(Hash.isEqual(bp.getCred(),((GetCred)usr.principal).getCred())) {
+ return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by cached AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);
+ }
+ }
+ }
+
+ Miss miss = missed(bp.getName());
+ if(miss!=null && !miss.mayContinue(bp.getCred())) {
+ return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+ "User/Pass Retry limit exceeded"),
+ RESP.FAIL,resp,aaf.getRealm(),true);
+ }
+
+ Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_LATEST_VERSION).forUser(aaf.basicAuthSS(bp));
+ Future<String> fp = userAAF.read("/authn/basicAuth", "text/plain");
+ if(fp.get(aaf.timeout)) {
+ if(usr!=null) {
+ usr.principal = bp;
+ } else {
+ addUser(new User<AAFPermission>(bp,aaf.userExpires));
+ }
+ return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);
+ } else {
+ // Note: AddMiss checks for miss==null, and is part of logic
+ boolean rv= addMiss(bp.getName(),bp.getCred());
+ if(rv) {
+ return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+ "User/Pass combo invalid via AAF"),
+ RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),true);
+ } else {
+ return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+ "User/Pass combo invalid via AAF - Retry limit exceeded"),
+ RESP.FAIL,resp,aaf.getRealm(),true);
+ }
+ }
+ } catch (IOException e) {
+ String msg = buildMsg(null,req,"Invalid Auth Token");
+ aaf.access.log(Level.WARN,msg,'(', e.getMessage(), ')');
+ return new BasicHttpTafResp(aaf.access,null,msg, RESP.TRY_AUTHENTICATING, resp, aaf.getRealm(),true);
+ } catch (Exception e) {
+ String msg = buildMsg(null,req,"Authenticating Service unavailable");
+ aaf.access.log(Level.WARN,msg,'(', e.getMessage(), ')');
+ return new BasicHttpTafResp(aaf.access,null,msg, RESP.FAIL, resp, aaf.getRealm(),false);
+ }
+ }
+ return new BasicHttpTafResp(aaf.access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),false);
+ }
+
+ private String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {
+ StringBuilder sb = new StringBuilder();
+ for(Object s : msg) {
+ sb.append(s.toString());
+ }
+ if(pr!=null) {
+ sb.append(" for ");
+ sb.append(pr.getName());
+ }
+ sb.append(" from ");
+ sb.append(req.getRemoteAddr());
+ sb.append(':');
+ sb.append(req.getRemotePort());
+ return sb.toString();
+ }
+
+
+
+ public Resp revalidate(CachedPrincipal prin) {
+ // !!!! TEST THIS.. Things may not be revalidated, if not BasicPrincipal
+ if(prin instanceof BasicPrincipal) {
+ Future<String> fp;
+ try {
+ Rcli<CLIENT> userAAF = aaf.client(AAFCon.AAF_LATEST_VERSION).forUser(aaf.transferSS(prin));
+ fp = userAAF.read("/authn/basicAuth", "text/plain");
+ return fp.get(aaf.timeout)?Resp.REVALIDATED:Resp.UNVALIDATED;
+ } catch (Exception e) {
+ aaf.access.log(e, "Cannot Revalidate",prin.getName());
+ return Resp.INACCESSIBLE;
+ }
+ }
+ return Resp.NOT_MINE;
+ }
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java
new file mode 100644
index 0000000..3bc4faf
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AAFTrustChecker.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.v2_0;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import com.att.cadi.Access;
+import com.att.cadi.Lur;
+import com.att.cadi.TrustChecker;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.config.Config;
+import com.att.cadi.principal.TrustPrincipal;
+import com.att.cadi.taf.TafResp;
+import com.att.cadi.taf.TrustNotTafResp;
+import com.att.cadi.taf.TrustTafResp;
+import com.att.inno.env.Env;
+import com.att.inno.env.util.Split;
+
+public class AAFTrustChecker implements TrustChecker {
+ private final String tag, id;
+ private final AAFPermission perm;
+ private Lur lur;
+
+ /**
+ *
+ * Instance will be replaced by Identity
+ * @param lur
+ *
+ * @param tag
+ * @param perm
+ */
+ public AAFTrustChecker(final Env env) {
+ tag = env.getProperty(Config.CADI_USER_CHAIN_TAG, Config.CADI_USER_CHAIN);
+ id = env.getProperty(Config.CADI_ALIAS,env.getProperty(Config.AAF_MECHID)); // share between components
+ String str = env.getProperty(Config.CADI_TRUST_PERM);
+ AAFPermission temp=null;
+ if(str!=null) {
+ String[] sp = Split.splitTrim('|', str);
+ if(sp.length==3) {
+ temp = new AAFPermission(sp[0],sp[1],sp[2]);
+ }
+ }
+ perm=temp;
+ }
+
+ public AAFTrustChecker(final Access access) {
+ tag = access.getProperty(Config.CADI_USER_CHAIN_TAG, Config.CADI_USER_CHAIN);
+ id = access.getProperty(Config.CADI_ALIAS,access.getProperty(Config.AAF_MECHID,null)); // share between components
+ String str = access.getProperty(Config.CADI_TRUST_PERM,null);
+ AAFPermission temp=null;
+ if(str!=null) {
+ String[] sp = Split.splitTrim('|', str);
+ if(sp.length==3) {
+ temp = new AAFPermission(sp[0],sp[1],sp[2]);
+ }
+ }
+ perm=temp;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.TrustChecker#setLur(com.att.cadi.Lur)
+ */
+ @Override
+ public void setLur(Lur lur) {
+ this.lur = lur;
+ }
+
+ @Override
+ public TafResp mayTrust(TafResp tresp, HttpServletRequest req) {
+ String user_info = req.getHeader(tag);
+ if(user_info !=null ) {
+ String[] info = Split.split(',', user_info);
+ if(info.length>0) {
+ String[] flds = Split.splitTrim(':',info[0]);
+ if(flds.length>3 && "AS".equals(flds[3])) { // is it set for "AS"
+ String pn = tresp.getPrincipal().getName();
+ if(pn.equals(id) // We do trust our own App Components: if a trust entry is made with self, always accept
+ || lur.fish(tresp.getPrincipal(), perm)) { // Have Perm set by Config.CADI_TRUST_PERM
+ return new TrustTafResp(tresp,
+ new TrustPrincipal(tresp.getPrincipal(), flds[0]),
+ " " + flds[0] + " validated using " + flds[2] + " by " + flds[1] + ','
+ );
+ } else if(pn.equals(flds[0])) { // Ignore if same identity
+ return tresp;
+ } else {
+ return new TrustNotTafResp(tresp, tresp.getPrincipal().getName() + " requested trust as "
+ + flds[0] + ", but does not have Authorization");
+ }
+ }
+ }
+ }
+ return tresp;
+ }
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java
new file mode 100644
index 0000000..8626588
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/aaf/v2_0/AbsAAFLur.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * ============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.cadi.aaf.v2_0;
+
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.AbsUserCache;
+import com.att.cadi.Access.Level;
+import com.att.cadi.CachingLur;
+import com.att.cadi.Permission;
+import com.att.cadi.StrLur;
+import com.att.cadi.Transmutate;
+import com.att.cadi.User;
+import com.att.cadi.config.Config;
+import com.att.cadi.aaf.AAFPermission;
+import com.att.cadi.aaf.AAFTransmutate;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Split;
+
+public abstract class AbsAAFLur<PERM extends Permission> extends AbsUserCache<PERM> implements StrLur, CachingLur<PERM> {
+ protected static final byte[] BLANK_PASSWORD = new byte[0];
+ protected static final Transmutate<Principal> transmutate = new AAFTransmutate();
+ private String[] debug = null;
+ public AAFCon<?> aaf;
+ private String[] supports;
+
+ public AbsAAFLur(AAFCon<?> con) throws DME2Exception, URISyntaxException, APIException {
+ super(con.access, con.cleanInterval, con.highCount, con.usageRefreshTriggerCount);
+ aaf = con;
+ setLur(this);
+ supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");
+ }
+
+ public AbsAAFLur(AAFCon<?> con, AbsUserCache<PERM> auc) throws DME2Exception, URISyntaxException, APIException {
+ super(auc);
+ aaf = con;
+ setLur(this);
+ supports = con.access.getProperty(Config.AAF_DOMAIN_SUPPORT, Config.AAF_DOMAIN_SUPPORT_DEF).split("\\s*:\\s*");
+ }
+
+ @Override
+ public void setDebug(String ids) {
+ this.debug = ids==null?null:Split.split(',', ids);
+ }
+
+ protected abstract User<PERM> loadUser(Principal bait);
+ protected abstract User<PERM> loadUser(String name);
+ public final boolean supports(String userName) {
+ if(userName!=null) {
+ for(String s : supports) {
+ if(userName.endsWith(s))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected abstract boolean isCorrectPermType(Permission pond);
+
+ // This is where you build AAF CLient Code. Answer the question "Is principal "bait" in the "pond"
+ public boolean fish(Principal bait, Permission pond) {
+ return fish(bait.getName(), pond);
+ }
+
+ public void fishAll(Principal bait, List<Permission> perms) {
+ fishAll(bait.getName(),perms);
+ }
+
+ // This is where you build AAF CLient Code. Answer the question "Is principal "bait" in the "pond"
+ public boolean fish(String bait, Permission pond) {
+ if(isDebug(bait)) {
+ boolean rv = false;
+ StringBuilder sb = new StringBuilder("Log for ");
+ sb.append(bait);
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null) {
+ sb.append("\n\tUser is not in Cache");
+ } else {
+ if(user.noPerms())sb.append("\n\tUser has no Perms");
+ if(user.permExpired()) {
+ sb.append("\n\tUser's perm expired [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ } else {
+ sb.append("\n\tUser's perm expires [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ }
+ }
+ if(user==null || (user.noPerms() && user.permExpired())) {
+ user = loadUser(bait);
+ sb.append("\n\tloadUser called");
+ }
+ if(user==null) {
+ sb.append("\n\tUser was not Loaded");
+ } else if(user.contains(pond)) {
+ sb.append("\n\tUser contains ");
+ sb.append(pond.getKey());
+ rv = true;
+ } else {
+ sb.append("\n\tUser does not contain ");
+ sb.append(pond.getKey());
+ List<Permission> perms = new ArrayList<Permission>();
+ user.copyPermsTo(perms);
+ for(Permission p : perms) {
+ sb.append("\n\t\t");
+ sb.append(p.getKey());
+ }
+ }
+ } else {
+ sb.append("AAF Lur does not support [");
+ sb.append(bait);
+ sb.append("]");
+ }
+ aaf.access.log(Level.INFO, sb);
+ return rv;
+ } else {
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null || (user.noPerms() && user.permExpired())) {
+ user = loadUser(bait);
+ }
+ return user==null?false:user.contains(pond);
+ }
+ return false;
+ }
+ }
+
+ public void fishAll(String bait, List<Permission> perms) {
+ if(isDebug(bait)) {
+ StringBuilder sb = new StringBuilder("Log for ");
+ sb.append(bait);
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null) {
+ sb.append("\n\tUser is not in Cache");
+ } else {
+ if(user.noPerms())sb.append("\n\tUser has no Perms");
+ if(user.permExpired()) {
+ sb.append("\n\tUser's perm expired [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ } else {
+ sb.append("\n\tUser's perm expires [");
+ sb.append(new Date(user.permExpires()));
+ sb.append(']');
+ }
+ }
+ if(user==null || (user.noPerms() && user.permExpired())) {
+ user = loadUser(bait);
+ sb.append("\n\tloadUser called");
+ }
+ if(user==null) {
+ sb.append("\n\tUser was not Loaded");
+ } else {
+ sb.append("\n\tCopying Perms ");
+ user.copyPermsTo(perms);
+ for(Permission p : perms) {
+ sb.append("\n\t\t");
+ sb.append(p.getKey());
+ }
+ }
+ } else {
+ sb.append("AAF Lur does not support [");
+ sb.append(bait);
+ sb.append("]");
+ }
+ aaf.access.log(Level.INFO, sb);
+ } else {
+ if(supports(bait)) {
+ User<PERM> user = getUser(bait);
+ if(user==null || (user.noPerms() && user.permExpired())) user = loadUser(bait);
+ if(user!=null) {
+ user.copyPermsTo(perms);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void remove(String user) {
+ super.remove(user);
+ }
+
+ private boolean isDebug(String bait) {
+ if(debug!=null) {
+ if(debug.length==1 && "all".equals(debug[0]))return true;
+ for(String s : debug) {
+ if(s.equals(bait))return true;
+ }
+ }
+ return false;
+ }
+ /**
+ * This special case minimizes loops, avoids multiple Set hits, and calls all the appropriate Actions found.
+ *
+ * @param bait
+ * @param obj
+ * @param type
+ * @param instance
+ * @param actions
+ */
+ public<A> void fishOneOf(String bait, A obj, String type, String instance, List<Action<A>> actions) {
+ User<PERM> user = getUser(bait);
+ if(user==null || (user.noPerms() && user.permExpired()))user = loadUser(bait);
+// return user==null?false:user.contains(pond);
+ if(user!=null) {
+ ReuseAAFPermission perm = new ReuseAAFPermission(type,instance);
+ for(Action<A> action : actions) {
+ perm.setAction(action.getName());
+ if(user.contains(perm)) {
+ if(action.exec(obj))return;
+ }
+ }
+ }
+ }
+
+ public static interface Action<A> {
+ public String getName();
+ /**
+ * Return false to continue, True to end now
+ * @return
+ */
+ public boolean exec(A a);
+ }
+
+ private class ReuseAAFPermission extends AAFPermission {
+ public ReuseAAFPermission(String type, String instance) {
+ super(type,instance,null);
+ }
+
+ public void setAction(String s) {
+ action = s;
+ }
+
+ /**
+ * This function understands that AAF Keys are hierarchical, :A:B:C,
+ * Cassandra follows a similar method, so we'll short circuit and do it more efficiently when there isn't a first hit
+ * @return
+ */
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/cm/ArtifactDir.java b/aaf/src/main/java/com/att/cadi/cm/ArtifactDir.java
new file mode 100644
index 0000000..39854d6
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/ArtifactDir.java
@@ -0,0 +1,288 @@
+/*******************************************************************************
+ * ============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.cadi.cm;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+import com.att.inno.env.util.Chrono;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+public abstract class ArtifactDir implements PlaceArtifact {
+
+ protected static final String C_R = "\n";
+ protected File dir;
+ private List<String> encodeds = new ArrayList<String>();
+
+ private Symm symm;
+ // This checks for multiple passes of Dir on the same objects. Run clear after done.
+ protected static Map<String,Object> processed = new HashMap<String,Object>();
+
+
+ /**
+ * Note: Derived Classes should ALWAYS call "super.place(cert,arti)" first, and
+ * then "placeProperties(arti)" just after they implement
+ */
+ @Override
+ public final boolean place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ validate(arti);
+
+ try {
+ // Obtain/setup directory as required
+ dir = new File(arti.getDir());
+ if(processed.get("dir")==null) {
+ if(!dir.exists()) {
+ Chmod.to755.chmod(dir);
+ if(!dir.mkdirs()) {
+ throw new CadiException("Could not create " + dir);
+ }
+ }
+
+ // Also place cm_url and Host Name
+ addProperty(Config.CM_URL,trans.getProperty(Config.CM_URL));
+ addProperty(Config.HOSTNAME,arti.getMachine());
+ //addProperty(Config.AAF_ENV,certInfo.getEnv());
+ // Obtain Issuers
+ boolean first = true;
+ StringBuilder issuers = new StringBuilder();
+// for(String dn : certInfo.getCaIssuerDNs()) {
+// if(first) {
+// first=false;
+// } else {
+// issuers.append(':');
+// }
+// issuers.append(dn);
+// }
+ addProperty(Config.CADI_X509_ISSUERS,issuers.toString());
+ }
+ symm = (Symm)processed.get("symm");
+ if(symm==null) {
+ // CADI Key Gen
+ File f = new File(dir,arti.getAppName() + ".keyfile");
+ if(!f.exists()) {
+ write(f,Chmod.to400,Symm.baseCrypt().keygen());
+ }
+ symm = Symm.obtain(f);
+
+ addEncProperty("ChallengePassword", certInfo.getChallenge());
+
+ processed.put("symm",symm);
+ }
+
+ _place(trans, certInfo,arti);
+
+ placeProperties(arti);
+
+ processed.put("dir",dir);
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+
+ /**
+ * Derived Classes implement this instead, so Dir can process first, and write any Properties last
+ * @param cert
+ * @param arti
+ * @return
+ * @throws CadiException
+ */
+ protected abstract boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException;
+
+ protected void addProperty(String tag, String value) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ sb.append(tag);
+ sb.append('=');
+ sb.append(value);
+ encodeds.add(sb.toString());
+ }
+
+ protected void addEncProperty(String tag, String value) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ sb.append(tag);
+ sb.append('=');
+ sb.append("enc:???");
+ sb.append(symm.enpass(value));
+ encodeds.add(sb.toString());
+ }
+
+ protected void write(File f, Chmod c, String ... data) throws IOException {
+ f.setWritable(true,true);
+
+ FileOutputStream fos = new FileOutputStream(f);
+ PrintStream ps = new PrintStream(fos);
+ try {
+ for(String s : data) {
+ ps.print(s);
+ }
+ } finally {
+ ps.close();
+ c.chmod(f);
+ }
+ }
+
+ protected void write(File f, Chmod c, byte[] bytes) throws IOException {
+ f.setWritable(true,true);
+
+ FileOutputStream fos = new FileOutputStream(f);
+ try {
+ fos.write(bytes);
+ } finally {
+ fos.close();
+ c.chmod(f);
+ }
+ }
+
+ protected void write(File f, Chmod c, KeyStore ks, char[] pass ) throws IOException, CadiException {
+ f.setWritable(true,true);
+
+ FileOutputStream fos = new FileOutputStream(f);
+ try {
+ ks.store(fos, pass);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ } finally {
+ fos.close();
+ c.chmod(f);
+ }
+ }
+
+
+ private void validate(Artifact a) throws CadiException {
+ StringBuilder sb = new StringBuilder();
+ if(a.getDir()==null) {
+ sb.append("File Artifacts require a path");
+ }
+
+ if(a.getAppName()==null) {
+ if(sb.length()>0) {
+ sb.append('\n');
+ }
+ sb.append("File Artifacts require an AAF Namespace");
+ }
+
+ if(sb.length()>0) {
+ throw new CadiException(sb.toString());
+ }
+ }
+
+ private boolean placeProperties(Artifact arti) throws CadiException {
+ if(encodeds.size()==0) {
+ return true;
+ }
+ boolean first=processed.get("dir")==null;
+ try {
+ File f = new File(dir,arti.getAppName()+".props");
+ if(f.exists()) {
+ if(first) {
+ f.delete();
+ } else {
+ f.setWritable(true);
+ }
+ }
+ // Append if not first
+ PrintWriter pw = new PrintWriter(new FileWriter(f,!first));
+
+ // Write a Header
+ if(first) {
+ for(int i=0;i<60;++i) {
+ pw.print('#');
+ }
+ pw.println();
+ pw.println("# Properties Generated by AT&T Certificate Manager");
+ pw.print("# by ");
+ pw.println(System.getProperty("user.name"));
+ pw.print("# on ");
+ pw.println(Chrono.dateStamp());
+ pw.println("# @copyright 2016, AT&T");
+ for(int i=0;i<60;++i) {
+ pw.print('#');
+ }
+ pw.println();
+ for(String prop : encodeds) {
+ if( prop.startsWith("cm_")
+ || prop.startsWith(Config.HOSTNAME)
+ || prop.startsWith(Config.AAF_ENV)) {
+ pw.println(prop);
+ }
+ }
+ }
+
+ try {
+ for(String prop : encodeds) {
+ if(prop.startsWith("cadi")) {
+ pw.println(prop);
+ }
+ }
+ } finally {
+ pw.close();
+ }
+ Chmod.to644.chmod(f);
+
+ if(first) {
+ // Challenge
+ f = new File(dir,arti.getAppName()+".chal");
+ if(f.exists()) {
+ f.delete();
+ }
+ pw = new PrintWriter(new FileWriter(f));
+ try {
+ for(String prop : encodeds) {
+ if(prop.startsWith("Challenge")) {
+ pw.println(prop);
+ }
+ }
+ } finally {
+ pw.close();
+ }
+ Chmod.to400.chmod(f);
+ }
+ } catch(Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+
+ public static void clear() {
+ processed.clear();
+ }
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/cm/CertException.java b/aaf/src/main/java/com/att/cadi/cm/CertException.java
new file mode 100644
index 0000000..a2694ce
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/CertException.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.cadi.cm;
+
+public class CertException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1373028409048516401L;
+
+ public CertException() {
+ }
+
+ public CertException(String message) {
+ super(message);
+ }
+
+ public CertException(Throwable cause) {
+ super(cause);
+ }
+
+ public CertException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/cm/CmAgent.java b/aaf/src/main/java/com/att/cadi/cm/CmAgent.java
new file mode 100644
index 0000000..424ef83
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/CmAgent.java
@@ -0,0 +1,711 @@
+/*******************************************************************************
+ * ============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.cadi.cm;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import com.att.cadi.PropAccess;
+import com.att.cadi.Symm;
+import com.att.cadi.aaf.client.ErrMessage;
+import com.att.cadi.aaf.v2_0.AAFCon;
+import com.att.cadi.aaf.v2_0.AAFConHttp;
+import com.att.cadi.client.Future;
+import com.att.cadi.config.Config;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.sso.AAFSSO;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.Env;
+import com.att.inno.env.TimeTaken;
+import com.att.inno.env.Trans;
+import com.att.inno.env.util.Chrono;
+import com.att.inno.env.util.Split;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+import certman.v1_0.Artifacts;
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+import certman.v1_0.CertificateRequest;
+
+public class CmAgent {
+ private static final String PRINT = "print";
+ private static final String FILE = "file";
+ private static final String PKCS12 = "pkcs12";
+ private static final String JKS = "jks";
+ private static final String SCRIPT="script";
+
+ private static final String CM_VER = "1.0";
+ public static final int PASS_SIZE = 24;
+ private static int TIMEOUT;
+
+ private static RosettaDF<CertificateRequest> reqDF;
+ private static RosettaDF<CertInfo> certDF;
+ private static RosettaDF<Artifacts> artifactsDF;
+ private static ErrMessage errMsg;
+ private static Map<String,PlaceArtifact> placeArtifact;
+ private static RosettaEnv env;
+
+ public static void main(String[] args) {
+ int exitCode = 0;
+ try {
+ AAFSSO aafsso = new AAFSSO(args);
+ if(aafsso.loginOnly()) {
+ aafsso.setLogDefault();
+ aafsso.writeFiles();
+ System.out.println("AAF SSO information created in ~/.aaf");
+ } else {
+ PropAccess access = aafsso.access();
+ env = new RosettaEnv(access.getProperties());
+ Deque<String> cmds = new ArrayDeque<String>();
+ for(String p : args) {
+ if(p.indexOf('=')<0) {
+ cmds.add(p);
+ }
+ }
+
+ if(cmds.size()==0) {
+ aafsso.setLogDefault();
+ System.out.println("Usage: java -jar <cadi-aaf-*-full.jar> cmd [<tag=value>]*");
+ System.out.println(" create <mechID> [<machine>]");
+ System.out.println(" read <mechID> [<machine>]");
+ System.out.println(" update <mechID> [<machine>]");
+ System.out.println(" delete <mechID> [<machine>]");
+ System.out.println(" copy <mechID> <machine> <newmachine>[,<newmachine>]*");
+ System.out.println(" place <mechID> [<machine>]");
+ System.out.println(" showpass <mechID> [<machine>]");
+ System.out.println(" check <mechID> [<machine>]");
+ System.exit(1);
+ }
+
+ TIMEOUT = Integer.parseInt(env.getProperty(Config.AAF_CONN_TIMEOUT, "5000"));
+
+ reqDF = env.newDataFactory(CertificateRequest.class);
+ artifactsDF = env.newDataFactory(Artifacts.class);
+ certDF = env.newDataFactory(CertInfo.class);
+ errMsg = new ErrMessage(env);
+
+ placeArtifact = new HashMap<String,PlaceArtifact>();
+ placeArtifact.put(JKS, new PlaceArtifactInKeystore(JKS));
+ placeArtifact.put(PKCS12, new PlaceArtifactInKeystore(PKCS12));
+ placeArtifact.put(FILE, new PlaceArtifactInFiles());
+ placeArtifact.put(PRINT, new PlaceArtifactOnStream(System.out));
+ placeArtifact.put(SCRIPT, new PlaceArtifactScripts());
+
+ Trans trans = env.newTrans();
+ try {
+ // show Std out again
+ aafsso.setLogDefault();
+ aafsso.setStdErrDefault();
+
+ // if CM_URL can be obtained, add to sso.props, if written
+ String cm_url = getProperty(access,env,false, Config.CM_URL,Config.CM_URL+": ");
+ if(cm_url!=null) {
+ aafsso.addProp(Config.CM_URL, cm_url);
+ }
+ aafsso.writeFiles();
+
+ AAFCon<?> aafcon = new AAFConHttp(access,Config.CM_URL);
+
+ String cmd = cmds.removeFirst();
+ if("place".equals(cmd)) {
+ placeCerts(trans,aafcon,cmds);
+ } else if("create".equals(cmd)) {
+ createArtifact(trans, aafcon,cmds);
+ } else if("read".equals(cmd)) {
+ readArtifact(trans, aafcon, cmds);
+ } else if("copy".equals(cmd)) {
+ copyArtifact(trans, aafcon, cmds);
+ } else if("update".equals(cmd)) {
+ updateArtifact(trans, aafcon, cmds);
+ } else if("delete".equals(cmd)) {
+ deleteArtifact(trans, aafcon, cmds);
+ } else if("showpass".equals(cmd)) {
+ showPass(trans,aafcon,cmds);
+ } else if("check".equals(cmd)) {
+ try {
+ exitCode = check(trans,aafcon,cmds);
+ } catch (Exception e) {
+ exitCode = 1;
+ throw e;
+ }
+ } else {
+ AAFSSO.cons.printf("Unknown command \"%s\"\n", cmd);
+ }
+ } finally {
+ StringBuilder sb = new StringBuilder();
+ trans.auditTrail(4, sb, Trans.REMOTE);
+ if(sb.length()>0) {
+ trans.info().log("Trans Info\n",sb);
+ }
+ }
+ aafsso.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if(exitCode!=0) {
+ System.exit(exitCode);
+ }
+ }
+
+ private static String getProperty(PropAccess pa, Env env, boolean secure, String tag, String prompt, Object ... def) {
+ String value;
+ if((value=pa.getProperty(tag))==null) {
+ if(secure) {
+ value = new String(AAFSSO.cons.readPassword(prompt, def));
+ } else {
+ value = AAFSSO.cons.readLine(prompt,def).trim();
+ }
+ if(value!=null) {
+ if(value.length()>0) {
+ pa.setProperty(tag,value);
+ env.setProperty(tag,value);
+ } else if(def.length==1) {
+ value=def[0].toString();
+ pa.setProperty(tag,value);
+ env.setProperty(tag,value);
+ }
+ }
+ }
+ return value;
+ }
+
+ private static String mechID(Deque<String> cmds) {
+ if(cmds.size()<1) {
+ String alias = env.getProperty(Config.CADI_ALIAS);
+ return alias!=null?alias:AAFSSO.cons.readLine("MechID: ");
+ }
+ return cmds.removeFirst();
+ }
+
+ private static String machine(Deque<String> cmds) throws UnknownHostException {
+ if(cmds.size()>0) {
+ return cmds.removeFirst();
+ } else {
+ String mach = env.getProperty(Config.HOSTNAME);
+ return mach!=null?mach:InetAddress.getLocalHost().getHostName();
+ }
+ }
+
+ private static String[] machines(Deque<String> cmds) {
+ String machines;
+ if(cmds.size()>0) {
+ machines = cmds.removeFirst();
+ } else {
+ machines = AAFSSO.cons.readLine("Machines (sep by ','): ");
+ }
+ return Split.split(',', machines);
+ }
+
+ private static void createArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ Artifacts artifacts = new Artifacts();
+ Artifact arti = new Artifact();
+ artifacts.getArtifact().add(arti);
+ arti.setMechid(mechID!=null?mechID:AAFSSO.cons.readLine("MechID: "));
+ arti.setMachine(machine!=null?machine:AAFSSO.cons.readLine("Machine (%s): ",InetAddress.getLocalHost().getHostName()));
+ arti.setCa(AAFSSO.cons.readLine("CA: (%s): ","aaf"));
+
+ String resp = AAFSSO.cons.readLine("Types [file,jks,script] (%s): ", "jks");
+ for(String s : Split.splitTrim(',', resp)) {
+ arti.getType().add(s);
+ }
+ // Always do Script
+ if(!resp.contains(SCRIPT)) {
+ arti.getType().add(SCRIPT);
+ }
+
+ // Note: Sponsor is set on Creation by CM
+ String configRootName = AAFCon.reverseDomain(arti.getMechid());
+ arti.setAppName(AAFSSO.cons.readLine("Namespace (%s): ",configRootName));
+ arti.setDir(AAFSSO.cons.readLine("Directory (%s): ", System.getProperty("user.dir")));
+ arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", System.getProperty("user.name")));
+ arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renewal Days (%s):", "30")));
+ arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (mailto owner):", "")));
+
+ TimeTaken tt = trans.start("Create Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> future = aafcon.client(CM_VER).create("/cert/artifacts", artifactsDF, artifacts);
+ if(future.get(TIMEOUT)) {
+ trans.info().printf("Call to AAF Certman successful %s, %s",arti.getMechid(), arti.getMachine());
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s",
+ errMsg.toMsg(future));
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static String toNotification(String notification) {
+ if(notification==null) {
+ notification="";
+ } else if(notification.length()>0) {
+ if(notification.indexOf(':')<0) {
+ notification = "mailto:" + notification;
+ }
+ }
+ return notification;
+ }
+
+
+ private static void readArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Read Artifact", Env.SUB);
+ try {
+ Future<Artifacts> future = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+
+ if(future.get(TIMEOUT)) {
+ boolean printed = false;
+ for(Artifact a : future.value.getArtifact()) {
+ AAFSSO.cons.printf("MechID: %s\n",a.getMechid());
+ AAFSSO.cons.printf(" Sponsor: %s\n",a.getSponsor());
+ AAFSSO.cons.printf("Machine: %s\n",a.getMachine());
+ AAFSSO.cons.printf("CA: %s\n",a.getCa());
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for(String t : a.getType()) {
+ if(first) {first=false;}
+ else{sb.append(',');}
+ sb.append(t);
+ }
+ AAFSSO.cons.printf("Types: %s\n",sb);
+ AAFSSO.cons.printf("Namespace: %s\n",a.getAppName());
+ AAFSSO.cons.printf("Directory: %s\n",a.getDir());
+ AAFSSO.cons.printf("O/S User: %s\n",a.getOsUser());
+ AAFSSO.cons.printf("Renew Days: %d\n",a.getRenewDays());
+ AAFSSO.cons.printf("Notification %s\n",a.getNotification());
+ printed = true;
+ }
+ if(!printed) {
+ AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(future));
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static void copyArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+ String[] newmachs = machines(cmds);
+ if(newmachs==null || newmachs == null) {
+ trans.error().log("No machines listed to copy to");
+ } else {
+ TimeTaken tt = trans.start("Copy Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> future = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+
+ if(future.get(TIMEOUT)) {
+ boolean printed = false;
+ for(Artifact a : future.value.getArtifact()) {
+ for(String m : newmachs) {
+ a.setMachine(m);
+ Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, future.value);
+ if(fup.get(TIMEOUT)) {
+ trans.info().printf("Copy of %s %s successful to %s",mechID,machine,m);
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s",
+ errMsg.toMsg(fup));
+ }
+
+ printed = true;
+ }
+ }
+ if(!printed) {
+ AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(future));
+ }
+ } finally {
+ tt.done();
+ }
+ }
+ }
+
+ private static void updateArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Update Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> fread = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+
+ if(fread.get(TIMEOUT)) {
+ Artifacts artifacts = new Artifacts();
+ for(Artifact a : fread.value.getArtifact()) {
+ Artifact arti = new Artifact();
+ artifacts.getArtifact().add(arti);
+
+ AAFSSO.cons.printf("For %s on %s\n", a.getMechid(),a.getMachine());
+ arti.setMechid(a.getMechid());
+ arti.setMachine(a.getMachine());
+ arti.setCa(AAFSSO.cons.readLine("CA: (%s): ",a.getCa()));
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for(String t : a.getType()) {
+ if(first) {first=false;}
+ else{sb.append(',');}
+ sb.append(t);
+ }
+
+ String resp = AAFSSO.cons.readLine("Types [file,jks,pkcs12] (%s): ", sb);
+ for(String s : Split.splitTrim(',', resp)) {
+ arti.getType().add(s);
+ }
+ // Always do Script
+ if(!resp.contains(SCRIPT)) {
+ arti.getType().add(SCRIPT);
+ }
+
+ // Note: Sponsor is set on Creation by CM
+ arti.setAppName(AAFSSO.cons.readLine("Namespace (%s): ",a.getAppName()));
+ arti.setDir(AAFSSO.cons.readLine("Directory (%s): ", a.getDir()));
+ arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", a.getOsUser()));
+ arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renew Days (%s):", a.getRenewDays())));
+ arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (%s):", a.getNotification())));
+
+ }
+ if(artifacts.getArtifact().size()==0) {
+ AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);
+ } else {
+ Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, artifacts);
+ if(fup.get(TIMEOUT)) {
+ trans.info().printf("Call to AAF Certman successful %s, %s",mechID,machine);
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s",
+ errMsg.toMsg(fup));
+ }
+ }
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s %s, %s",
+ errMsg.toMsg(fread),mechID,machine);
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static void deleteArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechid = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Delete Artifact", Env.REMOTE);
+ try {
+ Future<Void> future = aafcon.client(CM_VER)
+ .delete("/cert/artifacts/"+mechid+"/"+machine,"application/json" );
+
+ if(future.get(TIMEOUT)) {
+ trans.info().printf("Call to AAF Certman successful %s, %s",mechid,machine);
+ } else {
+ trans.error().printf("Call to AAF Certman failed, %s %s, %s",
+ errMsg.toMsg(future),mechid,machine);
+ }
+ } finally {
+ tt.done();
+ }
+ }
+
+
+
+ private static boolean placeCerts(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ boolean rv = false;
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Place Artifact", Env.REMOTE);
+ try {
+ Future<Artifacts> acf = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+ if(acf.get(TIMEOUT)) {
+ // Have to wait for JDK 1.7 source...
+ //switch(artifact.getType()) {
+ if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
+ AAFSSO.cons.printf("===> There are no artifacts for %s %s", mechID, machine);
+ } else {
+ for(Artifact a : acf.value.getArtifact()) {
+ String osID = System.getProperty("user.name");
+ if(a.getOsUser().equals(osID)) {
+ CertificateRequest cr = new CertificateRequest();
+ cr.setMechid(a.getMechid());
+ cr.setSponsor(a.getSponsor());
+ cr.getFqdns().add(a.getMachine());
+ Future<String> f = aafcon.client(CM_VER)
+ .setQueryParams("withTrust")
+ .updateRespondString("/cert/" + a.getCa(),reqDF, cr);
+ if(f.get(TIMEOUT)) {
+ CertInfo capi = certDF.newData().in(TYPE.JSON).load(f.body()).asObject();
+ for(String type : a.getType()) {
+ PlaceArtifact pa = placeArtifact.get(type);
+ if(pa!=null) {
+ if(rv = pa.place(trans, capi, a)) {
+ notifyPlaced(a,rv);
+ }
+ }
+ }
+ // Cover for the above multiple pass possibilities with some static Data, then clear per Artifact
+ } else {
+ trans.error().log(errMsg.toMsg(f));
+ }
+ } else {
+ trans.error().log("You must be OS User \"" + a.getOsUser() +"\" to place Certificates on this box");
+ }
+ }
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(acf));
+ }
+ } finally {
+ tt.done();
+ }
+ return rv;
+ }
+
+ private static void notifyPlaced(Artifact a, boolean rv) {
+
+
+ }
+
+ private static void showPass(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Show Password", Env.REMOTE);
+ try {
+ Future<Artifacts> acf = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+ if(acf.get(TIMEOUT)) {
+ // Have to wait for JDK 1.7 source...
+ //switch(artifact.getType()) {
+ if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
+ AAFSSO.cons.printf("No Artifacts found for %s on %s", mechID, machine);
+ } else {
+ String id = aafcon.defID();
+ boolean allowed;
+ for(Artifact a : acf.value.getArtifact()) {
+ allowed = id!=null && (id.equals(a.getSponsor()) ||
+ (id.equals(a.getMechid())
+ && aafcon.securityInfo().defSS.getClass().isAssignableFrom(HBasicAuthSS.class)));
+ if(!allowed) {
+ Future<String> pf = aafcon.client(CM_VER).read("/cert/may/" +
+ a.getAppName() + ".certman|"+a.getCa()+"|showpass","*/*");
+ if(pf.get(TIMEOUT)) {
+ allowed = true;
+ } else {
+ trans.error().log(errMsg.toMsg(pf));
+ }
+ }
+ if(allowed) {
+ File dir = new File(a.getDir());
+ Properties props = new Properties();
+ FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));
+ try {
+ props.load(fis);
+ fis.close();
+ fis = new FileInputStream(new File(dir,a.getAppName()+".chal"));
+ props.load(fis);
+ } finally {
+ fis.close();
+ }
+
+ File f = new File(dir,a.getAppName()+".keyfile");
+ if(f.exists()) {
+ Symm symm = Symm.obtain(f);
+
+ for(Iterator<Entry<Object,Object>> iter = props.entrySet().iterator(); iter.hasNext();) {
+ Entry<Object,Object> en = iter.next();
+ if(en.getValue().toString().startsWith("enc:???")) {
+ System.out.printf("%s=%s\n", en.getKey(), symm.depass(en.getValue().toString()));
+ }
+ }
+ } else {
+ trans.error().printf("%s.keyfile must exist to read passwords for %s on %s",
+ f.getAbsolutePath(),a.getMechid(), a.getMachine());
+ }
+ }
+ }
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(acf));
+ }
+ } finally {
+ tt.done();
+ }
+
+ }
+
+
+ /**
+ * Check returns Error Codes, so that Scripts can know what to do
+ *
+ * 0 - Check Complete, nothing to do
+ * 1 - General Error
+ * 2 - Error for specific Artifact - read check.msg
+ * 10 - Certificate Updated - check.msg is email content
+ *
+ * @param trans
+ * @param aafcon
+ * @param cmds
+ * @return
+ * @throws Exception
+ */
+ private static int check(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
+ int exitCode=1;
+ String mechID = mechID(cmds);
+ String machine = machine(cmds);
+
+ TimeTaken tt = trans.start("Check Certificate", Env.REMOTE);
+ try {
+
+ Future<Artifacts> acf = aafcon.client(CM_VER)
+ .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
+ if(acf.get(TIMEOUT)) {
+ // Have to wait for JDK 1.7 source...
+ //switch(artifact.getType()) {
+ if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
+ AAFSSO.cons.printf("No Artifacts found for %s on %s", mechID, machine);
+ } else {
+ String id = aafcon.defID();
+ GregorianCalendar now = new GregorianCalendar();
+ for(Artifact a : acf.value.getArtifact()) {
+ if(id.equals(a.getMechid())) {
+ File dir = new File(a.getDir());
+ Properties props = new Properties();
+ FileInputStream fis = new FileInputStream(new File(dir,a.getAppName()+".props"));
+ try {
+ props.load(fis);
+ } finally {
+ fis.close();
+ }
+
+ String prop;
+ File f;
+
+ if((prop=props.getProperty(Config.CADI_KEYFILE))==null ||
+ !(f=new File(prop)).exists()) {
+ trans.error().printf("Keyfile must exist to check Certificates for %s on %s",
+ a.getMechid(), a.getMachine());
+ } else {
+ String ksf = props.getProperty(Config.CADI_KEYSTORE);
+ String ksps = props.getProperty(Config.CADI_KEYSTORE_PASSWORD);
+ if(ksf==null || ksps == null) {
+ trans.error().printf("Properties %s and %s must exist to check Certificates for %s on %s",
+ Config.CADI_KEYSTORE, Config.CADI_KEYSTORE_PASSWORD,a.getMechid(), a.getMachine());
+ } else {
+ KeyStore ks = KeyStore.getInstance("JKS");
+ Symm symm = Symm.obtain(f);
+
+ fis = new FileInputStream(ksf);
+ try {
+ ks.load(fis,symm.depass(ksps).toCharArray());
+ } finally {
+ fis.close();
+ }
+ X509Certificate cert = (X509Certificate)ks.getCertificate(mechID);
+ String msg = null;
+
+ if(cert==null) {
+ msg = String.format("X509Certificate does not exist for %s on %s in %s",
+ a.getMechid(), a.getMachine(), ksf);
+ trans.error().log(msg);
+ exitCode = 2;
+ } else {
+ GregorianCalendar renew = new GregorianCalendar();
+ renew.setTime(cert.getNotAfter());
+ renew.add(GregorianCalendar.DAY_OF_MONTH,-1*a.getRenewDays());
+ if(renew.after(now)) {
+ msg = String.format("X509Certificate for %s on %s has been checked on %s. It expires on %s; it will not be renewed until %s.\n",
+ a.getMechid(), a.getMachine(),Chrono.dateOnlyStamp(now),cert.getNotAfter(),Chrono.dateOnlyStamp(renew));
+ trans.info().log(msg);
+ exitCode = 0; // OK
+ } else {
+ trans.info().printf("X509Certificate for %s on %s expiration, %s, needs Renewal.\n",
+ a.getMechid(), a.getMachine(),cert.getNotAfter());
+ cmds.offerLast(mechID);
+ cmds.offerLast(machine);
+ if(placeCerts(trans,aafcon,cmds)) {
+ msg = String.format("X509Certificate for %s on %s has been renewed. Ensure services using are refreshed.\n",
+ a.getMechid(), a.getMachine());
+ exitCode = 10; // Refreshed
+ } else {
+ msg = String.format("X509Certificate for %s on %s attempted renewal, but failed. Immediate Investigation is required!\n",
+ a.getMechid(), a.getMachine());
+ exitCode = 1; // Error Renewing
+ }
+ }
+ }
+ if(msg!=null) {
+ FileOutputStream fos = new FileOutputStream(a.getDir()+'/'+a.getAppName()+".msg");
+ try {
+ fos.write(msg.getBytes());
+ } finally {
+ fos.close();
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ } else {
+ trans.error().log(errMsg.toMsg(acf));
+ exitCode=1;
+ }
+ } finally {
+ tt.done();
+ }
+ return exitCode;
+ }
+
+}
+
+
+
+
diff --git a/aaf/src/main/java/com/att/cadi/cm/Factory.java b/aaf/src/main/java/com/att/cadi/cm/Factory.java
new file mode 100644
index 0000000..178cc81
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/Factory.java
@@ -0,0 +1,449 @@
+/*******************************************************************************
+ * ============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.cadi.cm;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Collection;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+import com.att.cadi.Symm;
+import com.att.inno.env.Env;
+import com.att.inno.env.TimeTaken;
+import com.att.inno.env.Trans;
+
+public class Factory {
+ private static final String PRIVATE_KEY_HEADER = "PRIVATE KEY";
+ public static final String KEY_ALGO = "RSA";
+ public static final String SIG_ALGO = "SHA256withRSA";
+
+ public static final int KEY_LENGTH = 2048;
+ private static final KeyPairGenerator keygen;
+ private static final KeyFactory keyFactory;
+ private static final CertificateFactory certificateFactory;
+ private static final SecureRandom random;
+
+
+ private static final Symm base64 = Symm.base64.copy(64);
+
+ static {
+ random = new SecureRandom();
+ KeyPairGenerator tempKeygen;
+ try {
+ tempKeygen = KeyPairGenerator.getInstance(KEY_ALGO);//,"BC");
+ tempKeygen.initialize(KEY_LENGTH, random);
+ } catch (NoSuchAlgorithmException e) {
+ tempKeygen = null;
+ e.printStackTrace(System.err);
+ }
+ keygen = tempKeygen;
+
+ KeyFactory tempKeyFactory;
+ try {
+ tempKeyFactory=KeyFactory.getInstance(KEY_ALGO);//,"BC"
+ } catch (NoSuchAlgorithmException e) {
+ tempKeyFactory = null;
+ e.printStackTrace(System.err);
+ };
+ keyFactory = tempKeyFactory;
+
+ CertificateFactory tempCertificateFactory;
+ try {
+ tempCertificateFactory = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ tempCertificateFactory = null;
+ e.printStackTrace(System.err);
+ }
+ certificateFactory = tempCertificateFactory;
+
+
+ }
+
+
+ public static KeyPair generateKeyPair(Trans trans) {
+ TimeTaken tt;
+ if(trans!=null) {
+ tt = trans.start("Generate KeyPair", Env.SUB);
+ } else {
+ tt = null;
+ }
+ try {
+ return keygen.generateKeyPair();
+ } finally {
+ if(tt!=null) {
+ tt.done();
+ }
+ }
+ }
+
+ private static final String LINE_END = "-----\n";
+
+ protected static String textBuilder(String kind, byte[] bytes) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ sb.append("-----BEGIN ");
+ sb.append(kind);
+ sb.append(LINE_END);
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ base64.encode(bais, baos);
+ sb.append(new String(baos.toByteArray()));
+
+ if(sb.charAt(sb.length()-1)!='\n') {
+ sb.append('\n');
+ }
+ sb.append("-----END ");
+ sb.append(kind);
+ sb.append(LINE_END);
+ return sb.toString();
+ }
+
+ public static PrivateKey toPrivateKey(Trans trans, String pk) throws IOException, CertException {
+ byte[] bytes = decode(new StringReader(pk));
+ return toPrivateKey(trans, bytes);
+ }
+
+ public static PrivateKey toPrivateKey(Trans trans, byte[] bytes) throws IOException, CertException {
+ TimeTaken tt=trans.start("Reconstitute Private Key", Env.SUB);
+ try {
+ return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
+ } catch (InvalidKeySpecException e) {
+ throw new CertException("Translating Private Key from PKCS8 KeySpec",e);
+ } finally {
+ tt.done();
+ }
+ }
+
+ public static PrivateKey toPrivateKey(Trans trans, File file) throws IOException, CertException {
+ TimeTaken tt = trans.start("Decode Private Key File", Env.SUB);
+ try {
+ return toPrivateKey(trans,decode(file));
+ }finally {
+ tt.done();
+ }
+ }
+
+ public static String toString(Trans trans, PrivateKey pk) throws IOException {
+// PKCS8EncodedKeySpec pemContents = new PKCS8EncodedKeySpec(pk.getEncoded());
+ trans.debug().log("Private Key to String");
+ return textBuilder(PRIVATE_KEY_HEADER,pk.getEncoded());
+ }
+
+ public static PublicKey toPublicKey(Trans trans, String pk) throws IOException {
+ TimeTaken tt = trans.start("Reconstitute Public Key", Env.SUB);
+ try {
+ ByteArrayInputStream bais = new ByteArrayInputStream(pk.getBytes());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Symm.base64noSplit.decode(bais, baos);
+
+ return keyFactory.generatePublic(new X509EncodedKeySpec(baos.toByteArray()));
+ } catch (InvalidKeySpecException e) {
+ trans.error().log(e,"Translating Public Key from X509 KeySpec");
+ return null;
+ } finally {
+ tt.done();
+ }
+ }
+
+ public static String toString(Trans trans, PublicKey pk) throws IOException {
+ trans.debug().log("Public Key to String");
+ return textBuilder("PUBLIC KEY",pk.getEncoded());
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(String x509) throws CertificateException {
+ return toX509Certificate(x509.getBytes());
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(List<String> x509s) throws CertificateException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ for(String x509 : x509s) {
+ baos.write(x509.getBytes());
+ }
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ return toX509Certificate(new ByteArrayInputStream(baos.toByteArray()));
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(byte[] x509) throws CertificateException {
+ return certificateFactory.generateCertificates(new ByteArrayInputStream(x509));
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(Trans trans, File file) throws CertificateException, FileNotFoundException {
+ FileInputStream fis = new FileInputStream(file);
+ try {
+ return toX509Certificate(fis);
+ } finally {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ }
+ }
+
+ public static Collection<? extends Certificate> toX509Certificate(InputStream is) throws CertificateException {
+ return certificateFactory.generateCertificates(is);
+ }
+
+ public static String toString(Trans trans, Certificate cert) throws IOException, CertException {
+ if(trans.debug().isLoggable()) {
+ StringBuilder sb = new StringBuilder("Certificate to String");
+ if(cert instanceof X509Certificate) {
+ sb.append(" - ");
+ sb.append(((X509Certificate)cert).getSubjectDN());
+ }
+ trans.debug().log(sb);
+ }
+ try {
+ if(cert==null) {
+ throw new CertException("Certificate not built");
+ }
+ return textBuilder("CERTIFICATE",cert.getEncoded());
+ } catch (CertificateEncodingException e) {
+ throw new CertException(e);
+ }
+ }
+
+ public static Cipher pkCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {
+ return Cipher.getInstance(KEY_ALGO);
+ }
+
+ public static Cipher pkCipher(Key key, boolean encrypt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+ Cipher cipher = Cipher.getInstance(KEY_ALGO);
+ cipher.init(encrypt?Cipher.ENCRYPT_MODE:Cipher.DECRYPT_MODE,key);
+ return cipher;
+ }
+
+ public static byte[] strip(Reader rdr) throws IOException {
+ BufferedReader br = new BufferedReader(rdr);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ String line;
+ while((line=br.readLine())!=null) {
+ if(line.length()>0 &&
+ !line.startsWith("-----") &&
+ line.indexOf(':')<0) { // Header elements
+ baos.write(line.getBytes());
+ }
+ }
+ return baos.toByteArray();
+ }
+
+ public static class StripperInputStream extends InputStream {
+ private Reader created;
+ private BufferedReader br;
+ private int idx;
+ private String line;
+
+ public StripperInputStream(Reader rdr) {
+ if(rdr instanceof BufferedReader) {
+ br = (BufferedReader)rdr;
+ } else {
+ br = new BufferedReader(rdr);
+ }
+ created = null;
+ }
+
+ public StripperInputStream(File file) throws FileNotFoundException {
+ this(new FileReader(file));
+ created = br;
+ }
+
+ public StripperInputStream(InputStream is) throws FileNotFoundException {
+ this(new InputStreamReader(is));
+ created = br;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if(line==null || idx>=line.length()) {
+ while((line=br.readLine())!=null) {
+ if(line.length()>0 &&
+ !line.startsWith("-----") &&
+ line.indexOf(':')<0) { // Header elements
+ break;
+ }
+ }
+
+ if(line==null) {
+ return -1;
+ }
+ idx = 0;
+ }
+ return line.charAt(idx++);
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.InputStream#close()
+ */
+ @Override
+ public void close() throws IOException {
+ if(created!=null) {
+ created.close();
+ }
+ }
+ }
+
+ public static class Base64InputStream extends InputStream {
+ private InputStream created;
+ private InputStream is;
+ private byte trio[];
+ private byte duo[];
+ private int idx;
+
+
+ public Base64InputStream(File file) throws FileNotFoundException {
+ this(new FileInputStream(file));
+ created = is;
+ }
+
+ public Base64InputStream(InputStream is) throws FileNotFoundException {
+ this.is = is;
+ trio = new byte[3];
+ idx = 4;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if(duo==null || idx>=duo.length) {
+ int read = is.read(trio);
+ if(read==-1) {
+ return -1;
+ }
+ duo = Symm.base64.decode(trio);
+ if(duo==null || duo.length==0) {
+ return -1;
+ }
+ idx=0;
+ }
+
+ return duo[idx++];
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.InputStream#close()
+ */
+ @Override
+ public void close() throws IOException {
+ if(created!=null) {
+ created.close();
+ }
+ }
+ }
+
+ public static byte[] decode(byte[] bytes) throws IOException {
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Symm.base64.decode(bais, baos);
+ return baos.toByteArray();
+ }
+
+ public static byte[] decode(File f) throws IOException {
+ FileReader fr = new FileReader(f);
+ try {
+ return Factory.decode(fr);
+ } finally {
+ fr.close();
+ }
+
+ }
+ public static byte[] decode(Reader rdr) throws IOException {
+ return decode(strip(rdr));
+ }
+
+
+ public static byte[] binary(File file) throws IOException {
+ DataInputStream dis = new DataInputStream(new FileInputStream(file));
+ try {
+ byte[] bytes = new byte[(int)file.length()];
+ dis.readFully(bytes);
+ return bytes;
+ } finally {
+ dis.close();
+ }
+ }
+
+
+ public static byte[] sign(Trans trans, byte[] bytes, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {
+ TimeTaken tt = trans.start("Sign Data", Env.SUB);
+ try {
+ Signature sig = Signature.getInstance(SIG_ALGO);
+ sig.initSign(pk, random);
+ sig.update(bytes);
+ return sig.sign();
+ } finally {
+ tt.done();
+ }
+ }
+
+ public static String toSignatureString(byte[] signed) throws IOException {
+ return textBuilder("SIGNATURE", signed);
+ }
+
+ public static boolean verify(Trans trans, byte[] bytes, byte[] signature, PublicKey pk) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ TimeTaken tt = trans.start("Verify Data", Env.SUB);
+ try {
+ Signature sig = Signature.getInstance(SIG_ALGO);
+ sig.initVerify(pk);
+ sig.update(bytes);
+ return sig.verify(signature);
+ } finally {
+ tt.done();
+ }
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifact.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifact.java
new file mode 100644
index 0000000..b5a3fb0
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifact.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * ============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.cadi.cm;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+import com.att.cadi.CadiException;
+import com.att.inno.env.Trans;
+
+public interface PlaceArtifact {
+ public boolean place(Trans trans, CertInfo cert, Artifact arti) throws CadiException;
+}
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java
new file mode 100644
index 0000000..219eb4a
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInFiles.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * ============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.cadi.cm;
+
+import java.io.File;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+
+public class PlaceArtifactInFiles extends ArtifactDir {
+ @Override
+ public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ try {
+ // Setup Public Cert
+ File f = new File(dir,arti.getAppName()+".crt");
+ write(f,Chmod.to644,certInfo.getCerts().get(0),C_R);
+
+ // Setup Private Key
+ f = new File(dir,arti.getAppName()+".key");
+ write(f,Chmod.to400,certInfo.getPrivatekey(),C_R);
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+}
+
+
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.java
new file mode 100644
index 0000000..6859ba5
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactInKeystore.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.cadi.cm;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+public class PlaceArtifactInKeystore extends ArtifactDir {
+ private String kst;
+ //TODO get ROOT DNs or Trusted DNs from Certificate Manager.
+// private static String[] rootDNs = new String[]{
+// "CN=ATT CADI Root CA - Test, O=ATT, OU=CSO, C=US", // Lab. delete eventually
+// "CN=ATT AAF CADI TEST CA, OU=CSO, O=ATT, C=US",
+// "CN=ATT AAF CADI CA, OU=CSO, O=ATT, C=US"
+// };
+
+ public PlaceArtifactInKeystore(String kst) {
+ this.kst = kst;
+ }
+
+ @Override
+ public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ File fks = new File(dir,arti.getAppName()+'.'+kst);
+ try {
+ KeyStore jks = KeyStore.getInstance(kst);
+ if(fks.exists()) {
+ fks.delete();
+ }
+
+ // Get the Cert(s)... Might include Trust store
+ Collection<? extends Certificate> certColl = Factory.toX509Certificate(certInfo.getCerts());
+ X509Certificate[] certs = new X509Certificate[certColl.size()];
+ certColl.toArray(certs);
+
+
+ // Add CADI Keyfile Entry to Properties
+ addProperty(Config.CADI_KEYFILE,arti.getDir()+'/'+arti.getAppName() + ".keyfile");
+ // Set Keystore Password
+ addProperty(Config.CADI_KEYSTORE,fks.getAbsolutePath());
+ String keystorePass = Symm.randomGen(CmAgent.PASS_SIZE);
+ addEncProperty(Config.CADI_KEYSTORE_PASSWORD,keystorePass);
+ char[] keystorePassArray = keystorePass.toCharArray();
+ jks.load(null,keystorePassArray); // load in
+
+ // Add Private Key/Cert Entry for App
+ // Note: Java SSL security classes, while having a separate key from keystore,
+ // is documented to not actually work.
+ // java.security.UnrecoverableKeyException: Cannot recover key
+ // You can create a custom Key Manager to make it work, but Practicality
+ // dictates that you live with the default, meaning, they are the same
+ String keyPass = keystorePass; //Symm.randomGen(CmAgent.PASS_SIZE);
+ PrivateKey pk = Factory.toPrivateKey(trans, certInfo.getPrivatekey());
+ addEncProperty(Config.CADI_KEY_PASSWORD, keyPass);
+ addProperty(Config.CADI_ALIAS, arti.getMechid());
+// Set<Attribute> attribs = new HashSet<Attribute>();
+// if(kst.equals("pkcs12")) {
+// // Friendly Name
+// attribs.add(new PKCS12Attribute("1.2.840.113549.1.9.20", arti.getAppName()));
+// }
+//
+ KeyStore.ProtectionParameter protParam =
+ new KeyStore.PasswordProtection(keyPass.toCharArray());
+
+ KeyStore.PrivateKeyEntry pkEntry =
+ new KeyStore.PrivateKeyEntry(pk, new Certificate[] {certs[0]});
+ jks.setEntry(arti.getMechid(),
+ pkEntry, protParam);
+
+ // Write out
+ write(fks,Chmod.to400,jks,keystorePassArray);
+
+ // Change out to TrustStore
+ fks = new File(dir,arti.getAppName()+".trust."+kst);
+ jks = KeyStore.getInstance(kst);
+
+ // Set Truststore Password
+ addProperty(Config.CADI_TRUSTSTORE,fks.getAbsolutePath());
+ String trustStorePass = Symm.randomGen(CmAgent.PASS_SIZE);
+ addEncProperty(Config.CADI_TRUSTSTORE_PASSWORD,trustStorePass);
+ char[] truststorePassArray = trustStorePass.toCharArray();
+ jks.load(null,truststorePassArray); // load in
+
+ // Add Trusted Certificates
+ for(int i=1; i<certs.length;++i) {
+ jks.setCertificateEntry("cadi_root_" + arti.getCa() + '_' + i, certs[i]);
+ }
+ // Write out
+ write(fks,Chmod.to644,jks,truststorePassArray);
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return false;
+ }
+
+}
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.java
new file mode 100644
index 0000000..7815a8e
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactOnStream.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.cadi.cm;
+
+import java.io.PrintStream;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+import com.att.inno.env.Trans;
+
+public class PlaceArtifactOnStream implements PlaceArtifact {
+ private PrintStream out;
+
+ public PlaceArtifactOnStream(PrintStream printStream) {
+ out = printStream;
+ }
+
+ @Override
+ public boolean place(Trans trans, CertInfo capi, Artifact a) {
+ if(capi.getNotes()!=null && capi.getNotes().length()>0) {
+ trans.info().printf("Warning: %s\n",capi.getNotes());
+ }
+ out.printf("Challenge: %s\n",capi.getChallenge());
+ out.printf("PrivateKey:\n%s\n",capi.getPrivatekey());
+ out.println("Certificate Chain:");
+ for(String c : capi.getCerts()) {
+ out.println(c);
+ }
+ return true;
+ }
+}
diff --git a/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java
new file mode 100644
index 0000000..ab77ca2
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/cm/PlaceArtifactScripts.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * ============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.cadi.cm;
+
+import java.io.File;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.util.Chmod;
+import com.att.inno.env.Trans;
+import com.att.inno.env.util.Chrono;
+import com.att.inno.env.util.Split;
+
+import certman.v1_0.Artifacts.Artifact;
+import certman.v1_0.CertInfo;
+
+public class PlaceArtifactScripts extends ArtifactDir {
+ @Override
+ public boolean _place(Trans trans, CertInfo certInfo, Artifact arti) throws CadiException {
+ try {
+ // Setup check.sh script
+ String filename = arti.getAppName()+".check.sh";
+ File f1 = new File(dir,filename);
+ String email = arti.getNotification() + '\n';
+ if(email.startsWith("mailto:")) {
+ email=email.substring(7);
+ } else {
+ email=arti.getOsUser() + '\n';
+ }
+
+ StringBuilder classpath = new StringBuilder();
+ boolean first = true;
+ for(String pth : Split.split(File.pathSeparatorChar, System.getProperty("java.class.path"))) {
+ if(first) {
+ first=false;
+ } else {
+ classpath.append(File.pathSeparatorChar);
+ }
+ File f = new File(pth);
+ classpath.append(f.getCanonicalPath().replaceAll("[0-9]+\\.[0-9]+\\.[0-9]+","*"));
+ }
+
+ write(f1,Chmod.to644,
+ "#!/bin/bash " + f1.getCanonicalPath()+'\n',
+ "# Certificate Manager Check Script\n",
+ "# Check on Certificate, and renew if needed.\n",
+ "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',
+ "DIR="+arti.getDir()+'\n',
+ "APP="+arti.getAppName()+'\n',
+ "EMAIL="+email,
+ "CP=\""+classpath.toString()+"\"\n",
+ checkScript
+ );
+
+ // Setup check.sh script
+ File f2 = new File(dir,arti.getAppName()+".crontab.sh");
+ write(f2,Chmod.to644,
+ "#!/bin/bash " + f1.getCanonicalPath()+'\n',
+ "# Certificate Manager Crontab Loading Script\n",
+ "# Add/Update a Crontab entry, that adds a check on Certificate Manager generated Certificate nightly.\n",
+ "# Generated by Certificate Manager " + Chrono.timeStamp()+'\n',
+ "TFILE=\"/tmp/cmcron$$.temp\"\n",
+ "DIR=\""+arti.getDir()+"\"\n",
+ "CF=\""+arti.getAppName()+" Certificate Check Script\"\n",
+ "SCRIPT=\""+f1.getCanonicalPath()+"\"\n",
+ cronScript
+ );
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ return true;
+ }
+
+ private final static String checkScript =
+ "> $DIR/$APP.msg\n\n" +
+ "function mailit {\n" +
+ " printf \"$*\" | /bin/mail -s \"AAF Certman Notification for `uname -n`\" $EMAIL\n"+
+ "}\n\n" +
+ System.getProperty("java.home") + "/bin/" +"java -cp $CP " +
+ CmAgent.class.getName() +
+ " cadi_prop_files=$DIR/$APP.props check 2> $DIR/$APP.STDERR > $DIR/$APP.STDOUT\n" +
+ "case \"$?\" in\n" +
+ " 0)\n" +
+ " # Note: Validation will be mailed only the first day after any modification\n" +
+ " if [ \"`find $DIR -mtime 0 -name $APP.check.sh`\" != \"\" ] ; then\n" +
+ " mailit `echo \"Certficate Validated:\\n\\n\" | cat - $DIR/$APP.msg`\n" +
+ " else\n" +
+ " cat $DIR/$APP.msg\n" +
+ " fi\n" +
+ " ;;\n" +
+ " 1) mailit \"Error with Certificate Check:\\\\n\\\\nCheck logs $DIR/$APP.STDOUT and $DIR/$APP.STDERR on `uname -n`\"\n" +
+ " ;;\n" +
+ " 2) mailit `echo \"Certificate Check Error\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +
+ " ;;\n" +
+ " 10) mailit `echo \"Certificate Replaced\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +
+ " if [ -e $DIR/$APP.restart.sh ]; then\n" +
+ " # Note: it is THIS SCRIPT'S RESPONSIBILITY to notify upon success or failure as necessary!!\n" +
+ " /bin/sh $DIR/$APP.restart.sh\n" +
+ " fi\n" +
+ " ;;\n" +
+ " *) mailit `echo \"Unknown Error code for CM Agent\\\\n\\\\n\" | cat - $DIR/$APP.msg`\n" +
+ " ;;\n" +
+ " esac\n\n" +
+ " # Note: make sure to cover this sripts' exit Code\n";
+
+ private final static String cronScript =
+ "crontab -l | sed -n \"/#### BEGIN $CF/,/END $CF ####/!p\" > $TFILE\n" +
+ "# Note: Randomize Minutes (0-60) and hours (1-4)\n" +
+ "echo \"#### BEGIN $CF ####\" >> $TFILE\n" +
+ "echo \"$(( $RANDOM % 60)) $(( $(( $RANDOM % 3 )) + 1 )) * * * /bin/bash $SCRIPT " +
+ ">> $DIR/cronlog 2>&1 \" >> $TFILE\n" +
+ "echo \"#### END $CF ####\" >> $TFILE\n" +
+ "crontab $TFILE\n" +
+ "rm $TFILE\n";
+}
+
+
+
diff --git a/aaf/src/main/java/com/att/cadi/sso/AAFSSO.java b/aaf/src/main/java/com/att/cadi/sso/AAFSSO.java
new file mode 100644
index 0000000..5d0d342
--- /dev/null
+++ b/aaf/src/main/java/com/att/cadi/sso/AAFSSO.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.cadi.sso;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import com.att.cadi.Access.Level;
+import com.att.cadi.CadiException;
+import com.att.cadi.PropAccess;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.util.MyConsole;
+import com.att.cadi.util.SubStandardConsole;
+import com.att.cadi.util.TheConsole;
+
+
+public class AAFSSO {
+ public static final MyConsole cons = TheConsole.implemented()?new TheConsole():new SubStandardConsole();
+
+ private Properties diskprops = null; // use for temp storing User/Password on disk
+ private File dot_aaf = null, sso=null; // instantiated, if ever, with diskprops
+
+ boolean removeSSO=false;
+ boolean loginOnly = false;
+ private PropAccess access;
+ private StringBuilder err;
+ private String user,encrypted_pass;
+ private boolean use_X509;
+
+ private PrintStream os, stdout=null,stderr=null;
+
+ private Method close;
+
+ public AAFSSO(String[] args) throws IOException, CadiException {
+ List<String> larg = new ArrayList<String>(args.length);
+
+ // Cover for bash's need to escape *... (\\*)
+ // also, remove SSO if required
+ for (int i = 0; i < args.length; ++i) {
+ if ("\\*".equals(args[i])) {
+ args[i] = "*";
+ }
+
+ if("-logout".equalsIgnoreCase(args[i])) {
+ removeSSO=true;
+ } else if("-login".equalsIgnoreCase(args[i])) {
+ loginOnly = true;
+ } else {
+ larg.add(args[i]);
+ }
+ }
+
+ String[] nargs = new String[larg.size()];
+ larg.toArray(nargs);
+
+ dot_aaf = new File(System.getProperty("user.home")+"/.aaf");
+ if(!dot_aaf.exists()) {
+ dot_aaf.mkdirs();
+ }
+ File f = new File(dot_aaf,"sso.out");
+ os = new PrintStream(new FileOutputStream(f,true));
+ stdout = System.out;
+ stderr = System.err;
+ System.setOut(os);
+ System.setErr(os);
+
+ access = new PropAccess(os,nargs);
+ Config.setDefaultRealm(access);
+
+ user = access.getProperty(Config.AAF_MECHID);
+ encrypted_pass = access.getProperty(Config.AAF_MECHPASS);
+
+ File dot_aaf_kf = new File(dot_aaf,"keyfile");
+
+ sso = new File(dot_aaf,"sso.props");
+ if(removeSSO) {
+ if(dot_aaf_kf.exists()) {
+ dot_aaf_kf.setWritable(true,true);
+ dot_aaf_kf.delete();
+ }
+ if(sso.exists()) {
+ sso.delete();
+ }
+ System.out.println("AAF SSO information removed");
+ System.exit(0);
+ }
+
+ if(!dot_aaf_kf.exists()) {
+ FileOutputStream fos = new FileOutputStream(dot_aaf_kf);
+ try {
+ fos.write(Symm.encrypt.keygen());
+ dot_aaf_kf.setExecutable(false,false);
+ dot_aaf_kf.setWritable(false,false);
+ dot_aaf_kf.setReadable(false,false);
+ dot_aaf_kf.setReadable(true, true);
+ } finally {
+ fos.close();
+ }
+ }
+
+ String keyfile = access.getProperty(Config.CADI_KEYFILE); // in case it's CertificateMan props
+ if(keyfile==null) {
+ access.setProperty(Config.CADI_KEYFILE, dot_aaf_kf.getAbsolutePath());
+ }
+
+ String alias = access.getProperty(Config.CADI_ALIAS);
+ if(user==null && alias!=null && access.getProperty(Config.CADI_KEYSTORE_PASSWORD)!=null) {
+ user = alias;
+ access.setProperty(Config.AAF_MECHID, user);
+ use_X509 = true;
+ } else {
+ use_X509 = false;
+ Symm decryptor = Symm.obtain(dot_aaf_kf);
+ if (user==null) {
+ if(sso.exists() && sso.lastModified()>System.currentTimeMillis()-(8*60*60*1000 /* 8 hours */)) {
+ String cm_url = access.getProperty(Config.CM_URL); // SSO might overwrite...
+ FileInputStream fos = new FileInputStream(sso);
+ try {
+ access.load(fos);
+ user = access.getProperty(Config.AAF_MECHID);
+ encrypted_pass = access.getProperty(Config.AAF_MECHPASS);
+ // decrypt with .aaf, and re-encrypt with regular Keyfile
+ access.setProperty(Config.AAF_MECHPASS,
+ access.encrypt(decryptor.depass(encrypted_pass)));
+ if(cm_url!=null) { //Command line CM_URL Overwrites ssofile.
+ access.setProperty(Config.CM_URL, cm_url);
+ }
+ } finally {
+ fos.close();
+ }
+ } else {
+ diskprops = new Properties();
+ String realm = Config.getDefaultRealm();
+ // Turn on Console Sysout
+ System.setOut(stdout);
+ user=cons.readLine("aaf_id(%s@%s): ",System.getProperty("user.name"),realm);
+ if(user==null) {
+ user = System.getProperty("user.name")+'@'+realm;
+ } else if(user.length()==0) { //
+ user = System.getProperty("user.name")+'@' + realm;
+ } else if(user.indexOf('@')<0 && realm!=null) {
+ user = user+'@'+realm;
+ }
+ access.setProperty(Config.AAF_MECHID,user);
+ diskprops.setProperty(Config.AAF_MECHID,user);
+ encrypted_pass = new String(cons.readPassword("aaf_password: "));
+ System.setOut(os);
+ encrypted_pass = Symm.ENC+decryptor.enpass(encrypted_pass);
+ access.setProperty(Config.AAF_MECHPASS,encrypted_pass);
+ diskprops.setProperty(Config.AAF_MECHPASS,encrypted_pass);
+ diskprops.setProperty(Config.CADI_KEYFILE, access.getProperty(Config.CADI_KEYFILE));
+ }
+ }
+ }
+ if (user == null) {
+ err = new StringBuilder("Add -D" + Config.AAF_MECHID + "=<id> ");
+ }
+
+ if (encrypted_pass == null && alias==null) {
+ if (err == null) {
+ err = new StringBuilder();
+ } else {
+ err.append("and ");
+ }
+ err.append("-D" + Config.AAF_MECHPASS + "=<passwd> ");
+ }
+ }
+
+ public void setLogDefault() {
+ access.setLogLevel(PropAccess.DEFAULT);
+ if(stdout!=null) {
+ System.setOut(stdout);
+ }
+ }
+
+ public void setStdErrDefault() {
+ access.setLogLevel(PropAccess.DEFAULT);
+ if(stderr!=null) {
+ System.setErr(stderr);
+ }
+ }
+
+ public void setLogDefault(Level level) {
+ access.setLogLevel(level);
+ if(stdout!=null) {
+ System.setOut(stdout);
+ }
+ }
+
+ public boolean loginOnly() {
+ return loginOnly;
+ }
+
+ public void addProp(String key, String value) {
+ if(diskprops!=null) {
+ diskprops.setProperty(key, value);
+ }
+ }
+
+ public void writeFiles() throws IOException {
+ // Store Creds, if they work
+ if(diskprops!=null) {
+ if(!dot_aaf.exists()) {
+ dot_aaf.mkdirs();
+ }
+ FileOutputStream fos = new FileOutputStream(sso);
+ try {
+ diskprops.store(fos, "AAF Single Signon");
+ } finally {
+ fos.close();
+ sso.setWritable(false,false);
+ sso.setExecutable(false,false);
+ sso.setReadable(false,false);
+ sso.setReadable(true,true);
+ }
+ }
+ if(sso!=null) {
+ sso.setReadable(false,false);
+ sso.setWritable(false,false);
+ sso.setExecutable(false,false);
+ sso.setReadable(true,true);
+ sso.setWritable(true,true);
+ }
+ }
+
+ public PropAccess access() {
+ return access;
+ }
+
+ public StringBuilder err() {
+ return err;
+ }
+
+ public String user() {
+ return user;
+ }
+
+ public String enc_pass() {
+ return encrypted_pass;
+ }
+
+ public boolean useX509() {
+ return use_X509;
+ }
+
+ public void close() {
+ if(close!=null) {
+ try {
+ close.invoke(null);
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ // nothing to do here.
+ }
+ close = null;
+ }
+ }
+}