Merge "Moved null ref check to line before dereferencing"
authorJonathan Gathman <jonathan.gathman@att.com>
Wed, 3 Jul 2019 14:10:52 +0000 (14:10 +0000)
committerGerrit Code Review <gerrit@onap.org>
Wed, 3 Jul 2019 14:10:52 +0000 (14:10 +0000)
120 files changed:
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/FutureDAO.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsDAO.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/PermDAO.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/RoleDAO.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Function.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFLocator.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFUserPass.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectRegistrar.java
auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/AbsJUCass.java
auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/cass/JU_RoleDAO.java
auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFLur.java
auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFUserPass.java
auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/AAF_CM.java
auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/CA.java
auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java
auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/api/JU_API_Artifact.java
auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/api/JU_API_Cert.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/AAFcli.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Help.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Version.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersContact.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersInRole.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Delete.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByUser.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Cred.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/List.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForRoles.java
auth/auth-core/src/main/java/org/onap/aaf/auth/cache/Cache.java
auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTrans.java
auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransFilter.java
auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransImpl.java
auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransOnlyFilter.java
auth/auth-core/src/main/java/org/onap/aaf/auth/env/NullTrans.java
auth/auth-core/src/main/java/org/onap/aaf/auth/org/OrganizationFactory.java
auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/CachingFileAccess.java
auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TransFilter.java
auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TransOnlyFilter.java
auth/auth-core/src/main/java/org/onap/aaf/auth/server/AbsService.java
auth/auth-core/src/main/java/org/onap/aaf/auth/server/AbsServiceStarter.java
auth/auth-core/src/main/java/org/onap/aaf/auth/server/JettyServiceStarter.java
auth/auth-core/src/main/java/org/onap/aaf/auth/validation/Validator.java
auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransImpl.java
auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransOnlyFilter.java
auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_NullTrans.java
auth/auth-core/src/test/java/org/onap/aaf/auth/server/test/JU_AbsServiceStarter.java
auth/auth-fs/src/main/java/org/onap/aaf/auth/fs/AAF_FS.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/cui/CUI.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/AAF_GUI.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiDocs.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtiChangeAction.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CredDetail.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CredHistory.java [new file with mode: 0644]
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/Home.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsDetail.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsHistory.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PendingRequestsShow.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermDetail.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermHistory.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleDetail.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleHistory.java
auth/auth-gui/theme/onap/aaf5.css
auth/auth-gui/theme/onap/console.js
auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/AAF_Hello.java
auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/AAF_Locate.java
auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateServiceImpl.java
auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/AAF_OAuth.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/AAF_Service.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzCassServiceImpl.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzService.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_History.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/facade/AuthzFacade.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/facade/AuthzFacadeImpl.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/mapper/Mapper_2_0.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/validation/ServiceValidator.java
auth/docker/dbash.sh
auth/docker/dinstall.sh [new file with mode: 0644]
auth/docker/drun.sh
auth/helm/aaf-hello/aaf.sh
auth/helm/aaf-hello/values.yaml
auth/helm/aaf/Chart.yaml
auth/helm/aaf/templates/aaf-gui.yaml
auth/sample/bin/service.sh
auth/sample/cass_data/config.dat
cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/AAFPermission.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/TestConnectivity.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/client/ErrMessage.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFAuthn.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFTaf.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AbsAAFLocator.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/configure/Agent.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/configure/PlaceArtifactInKeystore.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenClientFactory.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/obasic/OBasicHttpTaf.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/register/RegistrationCreator.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/sso/AAFSSO.java
cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/v2_0/JU_AAFAuthn.java
cadi/aaf/src/test/resources/cadi.properties
cadi/core/src/main/java/org/onap/aaf/cadi/PropAccess.java
cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java
cadi/core/src/main/java/org/onap/aaf/cadi/config/RegistrationPropHolder.java
cadi/core/src/main/java/org/onap/aaf/cadi/config/SecurityInfo.java
cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiHTTPManip.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/AbsTafResp.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/LoginPageTafResp.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/NullTafResp.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/PuntTafResp.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/TafResp.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/TrustNotTafResp.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/TrustTafResp.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/basic/BasicHttpTaf.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/basic/BasicHttpTafResp.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/cert/X509Taf.java
cadi/core/src/main/java/org/onap/aaf/cadi/taf/dos/DenialOfServiceTafResp.java
cadi/core/src/test/java/org/onap/aaf/cadi/taf/test/JU_AbsTafResp.java
cadi/core/src/test/java/org/onap/aaf/cadi/taf/test/JU_EpiTaf.java
docs/sections/installation/AAF_6_running.rst [new file with mode: 0644]
docs/sections/release-notes.rst
misc/log4j/src/main/java/org/onap/aaf/misc/env/log4j/LogFileNamer.java

index 7831815..72c0e98 100644 (file)
@@ -90,9 +90,9 @@ public class FutureDAO extends CassDAOImpl<AuthzTrans,FutureDAO.Data> {
             data.memo         = row.getString(2);
             data.start        = row.getTimestamp(3);
             data.expires      = row.getTimestamp(4);
-            data.construct    = row.getBytes(5);
-            data.target_key   = row.getString(6);
-            data.target_date  = row.getTimestamp(7);
+            data.target_key   = row.getString(5);
+            data.target_date  = row.getTimestamp(6);
+            data.construct    = row.getBytes(7);
             return data;
         }
 
@@ -109,9 +109,9 @@ public class FutureDAO extends CassDAOImpl<AuthzTrans,FutureDAO.Data> {
             obj[++idx] = data.memo;
             obj[++idx] = data.start;
             obj[++idx] = data.expires;
-            obj[++idx] = data.construct;
             obj[++idx] = data.target_key;
             obj[++idx] = data.target_date;
+            obj[++idx] = data.construct;
         }
     }
 
index f769e38..10e7844 100644 (file)
@@ -64,6 +64,7 @@ public class NsDAO extends CassDAOImpl<AuthzTrans,NsDAO.Data> {
     public static final String TABLE = "ns";
     public static final String TABLE_ATTRIB = "ns_attrib";
     public static final int CACHE_SEG = 0x40; // yields segment 0x0-0x3F
+    public static final int USER = 0;
     public static final int ROOT = 1;
     public static final int COMPANY=2;
     public static final int APP = 3;
index 6e1057b..0033f8a 100644 (file)
@@ -93,11 +93,31 @@ public class PermDAO extends CassDAOImpl<AuthzTrans,PermDAO.Data> {
         }
 
         public String fullType() {
-            return ns + '.' + type;
+               StringBuilder sb = new StringBuilder();
+               if(ns==null) {
+                       sb.append('.');
+               } else {
+                       sb.append(ns);
+                       sb.append(ns.indexOf('@')<0?'.':':');
+               }
+               sb.append(type);
+               return sb.toString();
         }
         
         public String fullPerm() {
-            return ns + '.' + type + '|' + instance + '|' + action;
+               StringBuilder sb = new StringBuilder();
+               if(ns==null) {
+                       sb.append("null.");
+               } else {
+                       sb.append(ns);
+                       sb.append(ns.indexOf('@')<0?'.':':');
+               }
+               sb.append(type);
+               sb.append('|');
+               sb.append(instance);
+               sb.append('|');
+               sb.append(action);
+               return sb.toString();
         }
 
         public String encode() {
@@ -193,17 +213,26 @@ public class PermDAO extends CassDAOImpl<AuthzTrans,PermDAO.Data> {
             Data rv = new PermDAO.Data();
             if (rdns.isOKhasData()) {
                 switch(s.length) {
+                       case 4:
+                               rv.ns=s[0];
+                           rv.type=s[1];
+                           rv.instance=s[2];
+                           rv.action=s[3];
+                           break;
                     case 3:
+                               rv.ns=s[0];
                         rv.type=s[1];
                         rv.instance=s[2];
                         rv.action=s[3];
                         break;
                     case 2:
+                               rv.ns=s[0];
                         rv.type=s[1];
                         rv.instance=s[2];
                         rv.action=STAR;
                         break;
                     default:
+                               rv.ns=s[0];
                         rv.type=s[1];
                         rv.instance = STAR;
                         rv.action = STAR;
index 127dd4e..a5fa7a7 100644 (file)
@@ -106,7 +106,15 @@ public class RoleDAO extends CassDAOImpl<AuthzTrans,RoleDAO.Data> {
         }
         
         public String fullName() {
-            return ns + '.' + name;
+               StringBuilder sb = new StringBuilder();
+               if(ns==null) {
+                       sb.append('.');
+               } else {
+                       sb.append(ns);
+               sb.append(ns.indexOf('@')<0?'.':':'); 
+               }
+               sb.append(name);
+               return sb.toString();
         }
         
         public String encode() {
@@ -122,19 +130,29 @@ public class RoleDAO extends CassDAOImpl<AuthzTrans,RoleDAO.Data> {
          * @return
          */
         public static Result<Data> decode(AuthzTrans trans, Question q, String r) {
-            String[] ss = Split.splitTrim('|', r,2);
             Data data = new Data();
-            if (ss[1]==null) { // older 1 part encoding must be evaluated for NS
-                Result<NsSplit> nss = q.deriveNsSplit(trans, ss[0]);
-                if (nss.notOK()) {
-                    return Result.err(nss);
-                }
-                data.ns=nss.value.ns;
-                data.name=nss.value.name;
-            } else { // new 4 part encoding
-                data.ns=ss[0];
-                data.name=ss[1];
-            }
+               if(r.indexOf('@')>=0) {
+                       int colon = r.indexOf(':');
+                       if(colon<0) {
+                               return Result.err(Result.ERR_BadData, "%s is not a valid Role",r);
+                       } else {
+                               data.ns=r.substring(0, colon);
+                               data.name=r.substring(++colon);
+                       }
+               } else {
+                   String[] ss = Split.splitTrim('|', r,2);
+                   if (ss[1]==null) { // older 1 part encoding must be evaluated for NS
+                       Result<NsSplit> nss = q.deriveNsSplit(trans, ss[0]);
+                       if (nss.notOK()) {
+                           return Result.err(nss);
+                       }
+                       data.ns=nss.value.ns;
+                       data.name=nss.value.name;
+                   } else { // new 4 part encoding
+                       data.ns=ss[0];
+                       data.name=ss[1];
+                   }
+               }
             return Result.ok(data);
         }
 
index 43e121a..c59312c 100644 (file)
@@ -1060,8 +1060,8 @@ public class Function {
             } else if (!fullperm.roles.isEmpty()) {
                 return Result
                         .err(Status.ERR_DependencyExists,
-                                "Permission [%s.%s|%s|%s] cannot be deleted as it is attached to 1 or more roles.",
-                                fullperm.ns, fullperm.type, fullperm.instance, fullperm.action);
+                                "Permission [%s] cannot be deleted as it is attached to 1 or more roles.",
+                                fullperm.fullPerm());
             }
         }
 
index 2c98a9b..ae6f371 100644 (file)
@@ -187,6 +187,7 @@ public class Question {
     
     private final CacheInfoDAO cacheInfoDAO;
        private final int cldays;
+       private final boolean alwaysSpecial;
 
     public Question(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException {
         PERMS = trans.slot("USER_PERMS");
@@ -220,6 +221,8 @@ public class Question {
         AbsCassDAO.primePSIs(trans);
         
         cldays = Integer.parseInt(trans.getProperty(Config.AAF_CRED_WARN_DAYS, Config.AAF_CRED_WARN_DAYS_DFT));
+        
+        alwaysSpecial = Boolean.parseBoolean(trans.getProperty("aaf_always_special", Boolean.FALSE.toString()));
     }
 
     public void startTimers(AuthzEnv env) {
@@ -322,13 +325,22 @@ public class Question {
         return permDAO.readByType(trans, nss.value.ns, nss.value.name);
     }
 
-    public Result<List<PermDAO.Data>> getPermsByName(AuthzTrans trans,
-            String type, String instance, String action) {
-        Result<NsSplit> nss = deriveNsSplit(trans, type);
-        if (nss.notOK()) {
-            return Result.err(nss);
-        }
-        return permDAO.read(trans, nss.value.ns, nss.value.name, instance,action);
+    public Result<List<PermDAO.Data>> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
+       if(type.indexOf('@') >= 0) {
+               int colon = type.indexOf(':');
+               if(colon>=0) {
+                       return permDAO.read(trans, type.substring(0, colon),type.substring(colon+1), instance,action);
+               } else {
+                       return Result.err(Result.ERR_BadData, "%s is malformed",type);
+               }
+       } else {
+               Result<NsSplit> nss = deriveNsSplit(trans, type);
+               if (nss.notOK()) {
+                   return Result.err(nss);
+               }
+               
+               return permDAO.read(trans, nss.value.ns, nss.value.name, instance,action);
+       }
     }
 
     public Result<List<PermDAO.Data>> getPermsByRole(AuthzTrans trans, String role, boolean lookup) {
@@ -374,8 +386,14 @@ public class Question {
         return Result.ok(perms);
     }
 
-    public Result<List<RoleDAO.Data>> getRolesByName(AuthzTrans trans,
-            String role) {
+    public Result<List<RoleDAO.Data>> getRolesByName(AuthzTrans trans, String role) {
+       if(role.startsWith(trans.user()) ) {
+               if(role.endsWith(":user")) {
+                       return roleDAO.read(trans,trans.user(), "user");
+               } else {
+                       return Result.err(Result.ERR_BadData,"%s is a badly formatted role",role);
+               }
+       }
         Result<NsSplit> nss = deriveNsSplit(trans, role);
         if (nss.notOK()) {
             return Result.err(nss);
@@ -412,12 +430,7 @@ public class Question {
         if (r.isOKhasData()) {
             return Result.ok(r.value.get(0));
         } else {
-            int dot;
-            if (child==null) {
-                return Result.err(Status.ERR_NsNotFound, "No Namespace");
-            } else {
-                dot = child.lastIndexOf('.');
-            }
+            int dot = child.lastIndexOf('.');
             if (dot < 0) {
                 return Result.err(Status.ERR_NsNotFound, "No Namespace for [%s]", child);
             } else {
@@ -558,6 +571,9 @@ public class Question {
     }
 
     public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user, RoleDAO.Data rdd, Access access) {
+       if(trans.user().equals(rdd.ns)) {
+               return Result.ok((NsDAO.Data)null);
+       }
         Result<NsDAO.Data> rnsd = deriveNs(trans, rdd.ns);
         if (rnsd.isOK()) {
             return mayUser(trans, user, rnsd.value, rdd, access);
@@ -612,6 +628,17 @@ public class Question {
     }
 
     public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,PermDAO.Data pdd, Access access) {
+       if(pdd.ns.indexOf('@')>-1) {
+               if(user.equals(pdd.ns) || isGranted(trans,user,Define.ROOT_NS(),"access",pdd.instance,READ)) {
+                       NsDAO.Data ndd = new NsDAO.Data();
+                       ndd.name = user;
+                       ndd.type = NsDAO.USER;
+                       ndd.parent = "";
+                       return Result.ok(ndd);
+               } else {
+                       return Result.err(Result.ERR_Security,"Only a User may modify User");
+               }
+       }
         Result<NsDAO.Data> rnsd = deriveNs(trans, pdd.ns);
         if (rnsd.isOK()) {
             return mayUser(trans, user, rnsd.value, pdd, access);
@@ -831,6 +858,7 @@ public class Question {
                                     byte[] md5=Hash.hashMD5(cred);
                                     if (Hash.compareTo(md5,dbcred)==0) {
                                         checkLessThanDays(trans,cldays,now,cdd);
+                                        trans.setTag(cdd.tag);
                                         return Result.ok(cdd.expires);
                                     } else if (debug!=null) {
                                         load(debug, cdd);
@@ -844,6 +872,7 @@ public class Question {
     
                                     if (Hash.compareTo(hash,dbcred)==0) {
                                         checkLessThanDays(trans,cldays,now,cdd);
+                                        trans.setTag(cdd.tag);
                                         return Result.ok(cdd.expires);
                                     } else if (debug!=null) {
                                         load(debug, cdd);
@@ -858,34 +887,41 @@ public class Question {
                     } else {
                         if (expired==null || expired.before(cdd.expires)) {
                             expired = cdd.expires;
+                            trans.setTag(cdd.tag);
                         }
                     }
                 } // end for each
-                if (debug==null) {
-                    trans.audit().printf("No cred matches ip=%s, user=%s\n",trans.ip(),user);
-                } else {
-                    trans.audit().printf("No cred matches ip=%s, user=%s %s\n",trans.ip(),user,debug.toString());
-                }
+                
                 if (expired!=null) {
                     // Note: this is only returned if there are no good Credentials
                     rv = Result.err(Status.ERR_Security,
-                            "Credentials %s from %s expired %s",trans.user(), trans.ip(), Chrono.dateTime(expired));
+                            "Credentials expired %s",Chrono.utcStamp(expired));
+                } else {
+                       if (debug==null && alwaysSpecial) {
+                               debug = new StringBuilder();
+                       }
+                       if (debug!=null) {
+                               debug.append(trans.env().encryptor().encrypt(new String(cred)));
+                               rv = Result.err(Status.ERR_Security,String.format("invalid password - %s",debug.toString()));
+                       }
                 }
             }
         } else {
             return Result.err(result);
         }
-        return rv == null ? Result.create((Date) null, Status.ERR_Security, "Wrong credential") : rv;
+        return rv == null ? Result.err(Status.ERR_Security, "Wrong credential") : rv;
     }
 
 
     private void load(StringBuilder debug, Data cdd) {
-        debug.append("DB Entry: user=");
+        debug.append("\nDB Entry: user=");
         debug.append(cdd.id);
         debug.append(",type=");
         debug.append(cdd.type);
         debug.append(",expires=");
         debug.append(Chrono.dateTime(cdd.expires));
+        debug.append(",tag=");
+        debug.append(cdd.tag);
         debug.append('\n');
     }
 
index 9845967..2f1d150 100644 (file)
@@ -73,9 +73,11 @@ public class DirectAAFLocator extends AbsAAFLocator<AuthzTrans> {
         }
         
         try {
-               String aaf_url = access.getProperty(Config.AAF_URL, null);
-               if(aaf_url==null) {
-                       aaf_url = "https://"+Config.AAF_LOCATE_URL_TAG+"/%NS."+name;
+               String aaf_url;
+               if(name.indexOf('.')>=0) {
+               aaf_url = "https://"+Config.AAF_LOCATE_URL_TAG+'/'+name+':'+version;
+               } else {
+               aaf_url = "https://"+Config.AAF_LOCATE_URL_TAG+"/%NS."+name+':'+version;
                }
                RegistrationPropHolder rph = new RegistrationPropHolder(access,0);
                aaf_url = rph.replacements(getClass().getSimpleName(),aaf_url, null,null);
index 3ef532b..3c7d873 100644 (file)
@@ -52,28 +52,37 @@ public class DirectAAFUserPass implements CredVal {
 
     @Override
     public boolean validate(String user, Type type, byte[] pass, Object state) {
+               if(user==null || type==null || pass==null) {
+                       return false;
+               }
+       
             try {
                 AuthzTrans trans;
+                boolean transfer = false;
                 if (state !=null) {
                     if (state instanceof AuthzTrans) {
                         trans = (AuthzTrans)state;
                     } else {
                         trans = env.newTransNoAvg();
                         if (state instanceof HttpServletRequest) {
-                            trans.set((HttpServletRequest)state);
+                            trans.set((HttpServletRequest)state,null);
+                            transfer=true;
                         }
                     }
                 } else {
                     trans = env.newTransNoAvg();
                 }
                 Result<Date> result = question.doesUserCredMatch(trans, user, pass);
-                trans.logAuditTrail(env.info());
+                if(transfer) {
+                       ((HttpServletRequest)state).setAttribute("CRED_TAG", trans.getTag());
+                }
+                trans.logAuditTrail(env.debug());
                 switch(result.status) {
                     case OK:
                         return true;
                     default:
-                        String ip = trans.ip()==null?"":(", ip="+trans.ip());
-                        env.warn().log(user, "failed password validation" + ip + ':',result.errorString());
+                        String ip = trans.ip()==null?"":trans.ip();
+                        env.audit().printf("user=%s,tag=%s,ip=%s,msg=\"failed password validation: %s\"",user,trans.getTag(),ip,result.errorString());
                 }
             } catch (DAOException e) {
                 env.error().log(e,"Cannot validate user/pass from cassandra");
index ec5449d..9942109 100644 (file)
@@ -49,7 +49,7 @@ public class DirectRegistrar implements Registrant<AuthzEnv> {
                ldd.add(convert(me));
         }
     }
-    
+
     private LocateDAO.Data convert(MgmtEndpoint me) {
        LocateDAO.Data out = new LocateDAO.Data();
        out.name=me.getName();
index dea2ccd..bb0fcd4 100644 (file)
@@ -104,9 +104,6 @@ public class AbsJUCass {
         
         // Load special data here
         
-        // WebPhone
-        env.setProperty("java.naming.provider.url","ldap://ldap.webphone.att.com:389");
-        env.setProperty("com.sun.jndi.ldap.connect.pool","true");
         
         iterations = 0;
         
index 16f05aa..fa023af 100644 (file)
@@ -430,7 +430,7 @@ public class JU_RoleDAO {
        }
        
        @Test
-       public void testWasMOdified() {
+       public void testWasModified() {
                TimeTaken tt = Mockito.mock(TimeTaken.class);
                Mockito.doReturn(tt).when(trans).start("RoleDAO CREATE", Env.REMOTE);
                Mockito.doReturn(tt).when(trans).start("Clear Reset Deque", Env.SUB);
index 0507743..f0f3c5d 100644 (file)
@@ -237,7 +237,7 @@ public class JU_DirectAAFLur {
                
                assertFalse(pp.match(null));
                
-               pond = new AAFPermission("null.test", "name", "instance", "action");
-               pp.match(pond);
+               pond = new AAFPermission("test.test", "test", "test", "test");
+               assertTrue(pp.match(pond));
        }
 }
index ca0a891..c767aeb 100644 (file)
@@ -125,7 +125,7 @@ public class JU_DirectAAFUserPass {
                }
                boolean retVal = aafLocatorObj.validate(null, null, null, null);
                
-               assertTrue(retVal);
+               assertFalse(retVal);
        }       
        
        @Test
index 3727e34..7dea9f0 100644 (file)
@@ -244,11 +244,10 @@ public class AAF_CM extends AbsService<AuthzEnv, AuthzTrans> {
         try {
             Log4JLogIt logIt = new Log4JLogIt(args, "cm");
             PropAccess propAccess = new PropAccess(logIt,args);
-
             try {
-                   AAF_CM service = new AAF_CM(new AuthzEnv(propAccess));
-                   JettyServiceStarter<AuthzEnv,AuthzTrans> jss = new JettyServiceStarter<AuthzEnv,AuthzTrans>(service);
-                   jss.start();
+                   new JettyServiceStarter<AuthzEnv,AuthzTrans>(
+                       new AAF_CM(new AuthzEnv(propAccess)),true)
+                               .start();
                } catch (Exception e) {
                    propAccess.log(e);
                }
index 881c9be..10da10d 100644 (file)
@@ -47,6 +47,7 @@ public abstract class CA {
     public static final String ISSUING_CA = "Issuing CA";
     public static final String CM_CA_PREFIX = "cm_ca.";
     public static final String CM_CA_BASE_SUBJECT = ".baseSubject";
+    public static final String CM_CA_ENV_TAG = ".env_tag";
     protected static final String CM_PUBLIC_DIR = "cm_public_dir";
     private static final String CM_TRUST_CAS = "cm_trust_cas";
     protected static final String CM_BACKUP_CAS = "cm_backup_cas";
@@ -63,12 +64,15 @@ public abstract class CA {
     private String[] trustedCAs;
     private String[] caIssuerDNs;
     private List<RDN> rdns;
+    private final boolean env_tag;
 
 
     protected CA(Access access, String caName, String env) throws IOException, CertException {
         trustedCAs = new String[4]; // starting array
         this.name = caName;
         this.env = env;
+        this.env_tag = env==null || env.isEmpty()?false: 
+                       Boolean.parseBoolean(access.getProperty(CM_CA_ENV_TAG, Boolean.FALSE.toString()));
         permNS = CM_CA_PREFIX + name;
         permType = access.getProperty(permNS + ".perm_type",null);
         if (permType==null) {
@@ -189,6 +193,10 @@ public abstract class CA {
         return trustedCAs;
     }
     
+    public boolean shouldAddEnvTag() {
+       return env_tag; 
+    }
+    
     public String getEnv() {
         return env;
     }
index 18f062d..1f2b088 100644 (file)
@@ -193,7 +193,8 @@ public class CMService {
                 } else if (primary == null) {
                     return Result.err(Result.ERR_Denied, "Request not made from matching IP (%s)", trans.ip());
                 } else {
-                    host = primary.getHostAddress();
+                    String thost = primary.getHostName();
+                    host = thost==null?primary.getHostAddress():thost;
                 }
 
                 ArtiDAO.Data add = null;
@@ -296,6 +297,7 @@ public class CMService {
             CSRMeta csrMeta;
             try {
                 csrMeta = BCFactory.createCSRMeta(ca, req.value.mechid, email, fqdns);
+                csrMeta.environment(ca.getEnv());
                 X509andChain x509ac = ca.sign(trans, csrMeta);
                 if (x509ac == null) {
                     return Result.err(Result.ERR_ActionNotCompleted, "x509 Certificate not signed by CA");
index ab10e66..4ef85aa 100644 (file)
@@ -59,8 +59,9 @@ public class JU_API_Artifact {
     public static void setUp() {
         AuthzTrans trans = mock(AuthzTrans.class);
         req = mock(HttpServletRequest.class);
+        res = mock(HttpServletResponse.class);
         trans.setProperty("testTag", "UserValue");
-        trans.set(req);
+        trans.set(req,res);
     }
     
     @Rule
index 4963297..674e4ed 100644 (file)
@@ -59,8 +59,9 @@ public class JU_API_Cert {
     public static void setUp() {
         AuthzTrans trans = mock(AuthzTrans.class);
         req = mock(HttpServletRequest.class);
+        res = mock(HttpServletResponse.class);
         trans.setProperty("testTag", "UserValue");
-        trans.set(req);
+        trans.set(req,res);
     }
     
     @Rule
index edbe206..8fcea29 100644 (file)
@@ -94,6 +94,10 @@ public class AAFcli {
         this(access,new AuthzEnv(access.getProperties()),wtr,hman, si,ss);
     }
 
+    public AuthzEnv env() {
+       return env;
+    }
+    
     public AAFcli(Access access, AuthzEnv env, Writer wtr, HMangr hman, SecurityInfoC<HttpURLConnection> si, SecuritySetter<HttpURLConnection> ss) throws APIException {
         this.env = env;
         this.access = access;
@@ -328,7 +332,7 @@ public class AAFcli {
                             Thread.sleep((long)(delay+globalDelay));
                         }
                     } catch (Exception e) {
-                        if (expect.contains(-1)) {
+                       if (expect.contains(-1)) {
                             pw.println(e.getMessage());
                             ret = -1;
                         } else {
index 12cf063..49ffb51 100644 (file)
@@ -31,7 +31,7 @@ public class Help extends Cmd {
     private List<Cmd> cmds;
 
     public Help(AAFcli aafcli, List<Cmd> cmds) {
-        super(aafcli, "--help", 
+        super(aafcli, "help", 
             new Param("-d (more details)", false),
             new Param("command",false));
         this.cmds = cmds;
index 1b1b183..d4a82d5 100644 (file)
@@ -27,17 +27,18 @@ import org.onap.aaf.cadi.config.Config;
 import org.onap.aaf.misc.env.APIException;
 
 public class Version extends Cmd {
+    private final String version;
 
-
-    public Version(AAFcli aafcli) {
-        super(aafcli, "--version");
+       public Version(AAFcli aafcli) {
+        super(aafcli, "version");
+        version = aafcli.access.getProperty(Config.AAF_DEPLOYED_VERSION, Config.AAF_DEFAULT_API_VERSION);
     }
 
     @Override
     protected int _exec(int idx, String... args) throws CadiException, APIException, LocatorException {
         pw().println("AAF Command Line Tool");
         pw().print("Version: ");
-        pw().println(Config.AAF_DEFAULT_API_VERSION);
+        pw().println(version);
         return 200;
     }
 }
index eadf1c9..d6eb9b3 100644 (file)
@@ -117,7 +117,7 @@ public class ListUsersContact extends Cmd {
         indent+=4;
         detailLine(sb,indent,"Report Users associated with this Namespace's Roles");
         sb.append('\n');
-        detailLine(sb,indent,"If \"set details=true\" is specified, then all roles are printed ");
+        detailLine(sb,indent,"If \"details\" is specified, then all roles are printed ");
         detailLine(sb,indent,"with the associated users and expiration dates");
         indent-=4;
         api(sb,indent,HttpMethods.GET,"authz/nss/<ns>",Nss.class,true);
index c0838cb..b33f506 100644 (file)
@@ -117,7 +117,7 @@ public class ListUsersInRole extends Cmd {
         indent+=4;
         detailLine(sb,indent,"Report Users associated with this Namespace's Roles");
         sb.append('\n');
-        detailLine(sb,indent,"If \"set details=true\" is specified, then all roles are printed ");
+        detailLine(sb,indent,"If \"details\" is specified, then all roles are printed ");
         detailLine(sb,indent,"with the associated users and expiration dates");
         indent-=4;
         api(sb,indent,HttpMethods.GET,"authz/nss/<ns>",Nss.class,true);
index 0f0c001..3edc0e5 100644 (file)
@@ -59,8 +59,12 @@ public class Delete extends Cmd {
                 pk.setInstance(args[idx++]);
                 pk.setAction(args[idx++]);
         
-                // Set "Force" if set
-                setQueryParamsOn(client);
+                if(pk.getType().contains("@")) { // User Perm deletion... Must remove from hidden role
+                       client.setQueryParams("force");
+                } else {
+                       // Set "Force" if set
+                       setQueryParamsOn(client);
+                }
                 Future<PermRequest> fp = client.delete(
                         "/authz/perm", 
                         getDF(PermRequest.class),
index 325f45d..00972a1 100644 (file)
@@ -57,9 +57,9 @@ public class ListByUser extends Cmd {
                 }
                 if (aafcli.isDetailed()) {
                     if (sb==null) {
-                        sb = new StringBuilder('?');
+                        sb = new StringBuilder("?");
                     } else {
-                        sb.append('&');
+                        sb.append("&");
                     }
                     sb.append("ns");
                 }
index d41f0cf..a1cb3e7 100644 (file)
 
 package org.onap.aaf.auth.cmd.user;
 
+import java.util.List;
+
 import org.onap.aaf.auth.cmd.AAFcli;
 import org.onap.aaf.auth.cmd.Cmd;
 import org.onap.aaf.auth.cmd.Param;
 import org.onap.aaf.auth.rserv.HttpMethods;
 import org.onap.aaf.cadi.CadiException;
 import org.onap.aaf.cadi.LocatorException;
+import org.onap.aaf.cadi.aaf.client.ErrMessage;
 import org.onap.aaf.cadi.client.Future;
 import org.onap.aaf.cadi.client.Rcli;
 import org.onap.aaf.cadi.client.Retryable;
 import org.onap.aaf.misc.env.APIException;
 
 import aaf.v2_0.CredRequest;
+import aaf.v2_0.Error;
 
 public class Cred extends Cmd {
     public static final String ATTEMPT_FAILED_SPECIFICS_WITHELD = "Attempt Failed.  Specifics witheld.";
     private static final String CRED_PATH = "/authn/cred";
     private static final String[] options = {"add","del","reset","extend"/*,"clean"*/};
-    public Cred(User parent) {
+       private ErrMessage em;
+//     private RosettaDF<Error> errDF;
+    public Cred(User parent) throws APIException {
         super(parent,"cred",
                 new Param(optionsToString(options),true),
                 new Param("id",true),
                 new Param("password (! D|E)",false),
                 new Param("entry# (if multi)",false)
         );
+        em = new ErrMessage(aafcli.env());
     }
 
     @Override
@@ -59,8 +66,9 @@ public class Cred extends Cmd {
             if (idx>=args.length) throw new CadiException("Password Required");
             cr.setPassword(args[idx++]);
         }
-        if (args.length>idx)
+        if (args.length>idx) {
             cr.setEntry(args[idx]);
+        }
         
         // Set Start/End commands
         setStartEnd(cr);
@@ -114,6 +122,19 @@ public class Cred extends Cmd {
                     pw().println(']');
                 } else if (fp.code()==202) {
                         pw().println("Credential Action Accepted, but requires Approvals before actualizing");
+                } else if (fp.code()==300) {
+                       Error err = em.getError(fp);
+                       String text = err.getText();
+                       List<String> vars = err.getVariables();
+                       
+                       // IMPORTANT! We do this backward, because it is looking for string
+                       // %1 or %13.  If we replace %1 first, that messes up %13
+                       for(int i=vars.size()-1;i>0;--i) {
+                               text = text.replace("%"+(i+1), (i<10?" ":"") + i+") " + vars.get(i));
+                       }
+
+                       text = text.replace("%1",vars.get(0));
+                       pw().println(text);
                 } else if (fp.code()==406 && option==1) {
                         pw().println("You cannot delete this Credential");
                 } else {
index 6d99328..7daa51f 100644 (file)
@@ -62,14 +62,12 @@ public class List extends BaseCmd<User> {
             if (!aafcli.isTest()) {
                 date = Chrono.dateOnlyStamp(user.getExpires());
             }
-            String tag=null;
-            if(user.getType()<200) {
-               tag = user.getTag();
-            } else {
-               tag = "\n\tfingerprint: " + user.getTag();
-            }
+            String tag=user.getTag();
+            Integer type = user.getType();
             if(tag==null) {
                tag="";
+            } else if(type!=null && type>=200) {
+               tag = "\n\tfingerprint: " + tag;
             }
             pw().format(format, 
                     count? (Integer.valueOf(++idx) + ") " + user.getId()): user.getId(),
index b534240..4e539ac 100644 (file)
@@ -21,9 +21,6 @@
 
 package org.onap.aaf.auth.cmd.user;
 
-import java.util.Collections;
-import java.util.Comparator;
-
 import org.onap.aaf.auth.cmd.AAFcli;
 import org.onap.aaf.auth.cmd.Cmd;
 import org.onap.aaf.auth.cmd.Param;
@@ -36,7 +33,6 @@ import org.onap.aaf.cadi.client.Retryable;
 import org.onap.aaf.misc.env.APIException;
 
 import aaf.v2_0.Users;
-import aaf.v2_0.Users.User;
 
 /**
  * p
@@ -61,13 +57,6 @@ public class ListForRoles extends Cmd {
                         getDF(Users.class)
                         );
                 if (fp.get(AAFcli.timeout())) {
-                    if (aafcli.isTest())
-                        Collections.sort(fp.value.getUser(), new Comparator<User>() {
-                            @Override
-                            public int compare(User u1, User u2) {
-                                return u1.getId().compareTo(u2.getId());
-                            }            
-                        });
                     ((org.onap.aaf.auth.cmd.user.List)parent).report(fp.value,false, HEADER,role);
                     if (fp.code()==404)return 200;
                 } else {
index 9393e14..6a8ccf1 100644 (file)
@@ -31,7 +31,6 @@ import java.util.Set;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Level;
 
 import org.onap.aaf.misc.env.Env;
 import org.onap.aaf.misc.env.Trans;
@@ -153,7 +152,7 @@ public class Cache<TRANS extends Trans, DATA> {
             }
             
             if (count>0) {
-                env.info().log(Level.INFO, "Cache removed",count,"expired Cached Elements out of", total);
+                env.debug().log("Cache removed",count,"expired Cached Elements out of", total);
             }
 
             // If High (total) is reached during this period, increase the number of expired services removed for next time.
index 0256c1b..1a1e7f2 100644 (file)
@@ -24,6 +24,7 @@ package org.onap.aaf.auth.env;
 import java.util.Date;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.onap.aaf.auth.org.Organization;
 import org.onap.aaf.cadi.Lur;
@@ -39,11 +40,13 @@ public interface AuthzTrans extends TransStore {
         REQD_TYPE(int bit) {
             this.bit = bit;
         }
-    };
-    
-    public abstract AuthzTrans set(HttpServletRequest req);
+    }
+
+    public abstract AuthzTrans set(HttpServletRequest req, HttpServletResponse resp);
 
        public abstract HttpServletRequest hreq();
+       
+    public abstract HttpServletResponse hresp();
 
     public abstract String user();
 
@@ -76,5 +79,12 @@ public interface AuthzTrans extends TransStore {
     public abstract void logAuditTrail(LogTarget lt);
     
     public abstract Date now();
+    
+    public abstract void setTag(String tag);
+    
+    public abstract String getTag();
+
+       public abstract void clearCache();
+
 
 }
\ No newline at end of file
index b08e024..bda23e1 100644 (file)
@@ -23,8 +23,8 @@ package org.onap.aaf.auth.env;
 
 import java.security.Principal;
 
-import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.onap.aaf.auth.rserv.TransFilter;
 import org.onap.aaf.cadi.CadiException;
@@ -63,16 +63,15 @@ public class AuthzTransFilter extends TransFilter<AuthzTrans> {
     }
     
     @Override
-    protected AuthzTrans newTrans(HttpServletRequest req) {
+    protected AuthzTrans newTrans(HttpServletRequest req, HttpServletResponse resp) {
         AuthzTrans at = env.newTrans();
         at.setLur(getLur());
-        at.set(req);
+        at.set(req,resp);
         return at;
     }
 
     @Override
-    protected TimeTaken start(AuthzTrans trans, ServletRequest request) {
-        trans.set((HttpServletRequest)request);
+    protected TimeTaken start(AuthzTrans trans) {
         return trans.start("Trans " + //(context==null?"n/a":context.toString()) +
         " IP: " + trans.ip() +
         " Port: " + trans.port()
@@ -85,9 +84,9 @@ public class AuthzTransFilter extends TransFilter<AuthzTrans> {
     }
 
     @Override
-    protected void tallyHo(AuthzTrans trans) {
+    protected void tallyHo(AuthzTrans trans, String target) {
         Boolean b = trans.get(specialLogSlot, false);
-        LogTarget lt = b?trans.warn():trans.info();
+        LogTarget lt = b?trans.warn():trans.debug();
         
         if (lt.isLoggable()) {
             // Transaction is done, now post full Audit Trail
@@ -131,8 +130,11 @@ public class AuthzTransFilter extends TransFilter<AuthzTrans> {
             sb.append("user=");
             Principal p = trans.getUserPrincipal();
             if (p==null) {
-                sb.append("n/a");
+               lt=trans.warn();
+                sb.append(target);
+                sb.append("[None]");
             } else {
+               lt=trans.info();
                 sb.append(p.getName());
                 if (p instanceof TrustPrincipal) {
                     sb.append('(');
@@ -148,6 +150,11 @@ public class AuthzTransFilter extends TransFilter<AuthzTrans> {
                     sb.append(']');
                 }
             }
+            String tag = trans.getTag();
+            if(tag!=null) {
+                sb.append(",tag=");
+                sb.append(tag);
+            }
             sb.append(",ip=");
             sb.append(trans.ip());
             sb.append(",port=");
@@ -176,7 +183,7 @@ public class AuthzTransFilter extends TransFilter<AuthzTrans> {
                 sb.append('"');
             }
             
-            trans.warn().log(sb);
+            lt.log(sb);
         }
     }
 
index ce947be..0af760b 100644 (file)
@@ -24,6 +24,7 @@ package org.onap.aaf.auth.env;
 import java.util.Date;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.onap.aaf.auth.org.Organization;
 import org.onap.aaf.auth.org.OrganizationFactory;
@@ -37,23 +38,27 @@ public class AuthzTransImpl extends BasicTrans implements AuthzTrans {
        private static final String N_A = "n/a";
        private static final String BLANK = "";
        private HttpServletRequest hreq;
+       private HttpServletResponse hresp;
     private TaggedPrincipal user;
     private Lur lur;
     private Organization org;
     private int mask;
     private Date now;
+    private String tag;
     public AuthzTransImpl(AuthzEnv env) {
         super(env);
         org=null;
         mask=0;
+        tag=null;
     }
 
     /**
      * @see org.onap.aaf.auth.env.test.AuthTrans#set(javax.servlet.http.HttpServletRequest)
      */
     @Override
-    public AuthzTrans set(HttpServletRequest req) {
+    public AuthzTrans set(HttpServletRequest req, HttpServletResponse resp) {
        hreq = req;
+       hresp = resp;
         user = (TaggedPrincipal)req.getUserPrincipal();
         
         for (REQD_TYPE rt : REQD_TYPE.values()) {
@@ -68,11 +73,17 @@ public class AuthzTransImpl extends BasicTrans implements AuthzTrans {
         org=null;
         return this;
     }
+    
     @Override
     public HttpServletRequest hreq() {
        return hreq;
     }
-    
+
+    @Override
+    public HttpServletResponse hresp() {
+       return hresp;
+    }
+
     @Override
     public void setUser(TaggedPrincipal p) {
         user = p;
@@ -172,7 +183,7 @@ public class AuthzTransImpl extends BasicTrans implements AuthzTrans {
         }
         return false;
     }
-
+    
     /* (non-Javadoc)
      * @see org.onap.aaf.auth.env.test.AuthzTrans#org()
      */
@@ -213,4 +224,27 @@ public class AuthzTransImpl extends BasicTrans implements AuthzTrans {
         }
         return now;
     }
+    
+    /*
+     * (non-Javadoc)
+     * @see org.onap.aaf.auth.env.AuthzTrans#setTag(java.lang.String)
+     */
+    @Override
+    public void setTag(String tag) {
+       this.tag = tag;
+    }
+
+    @Override
+    public String getTag() {
+       return tag;
+    }
+
+       @Override
+       public void clearCache() {
+        if (lur!=null) {
+               StringBuilder report = new StringBuilder();
+            lur.clear(user, report);
+            info().log(report);
+        }
+       }
 }
index b111163..5545c7d 100644 (file)
@@ -21,8 +21,8 @@
 
 package org.onap.aaf.auth.env;
 
-import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.onap.aaf.auth.rserv.TransOnlyFilter;
 import org.onap.aaf.cadi.principal.TaggedPrincipal;
@@ -43,13 +43,14 @@ public class AuthzTransOnlyFilter extends TransOnlyFilter<AuthzTrans> {
     }
     
     @Override
-    protected AuthzTrans newTrans() {
-        return env.newTrans();
+    protected AuthzTrans newTrans(HttpServletRequest req, HttpServletResponse resp) {
+        AuthzTrans trans = env.newTrans();
+        trans.set(req, resp);
+        return trans;
     }
 
     @Override
-    protected TimeTaken start(AuthzTrans trans, ServletRequest request) {
-        trans.set((HttpServletRequest)request);
+    protected TimeTaken start(AuthzTrans trans) {
         return trans.start("Trans " + //(context==null?"n/a":context.toString()) +
         " IP: " + trans.ip() +
         " Port: " + trans.port()
index 94a6aad..f0052e5 100644 (file)
@@ -24,6 +24,7 @@ package org.onap.aaf.auth.env;
 import java.util.Date;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.onap.aaf.auth.org.Organization;
 import org.onap.aaf.cadi.Lur;
@@ -130,7 +131,7 @@ public class NullTrans implements AuthzTrans {
         return null;
     }
     @Override
-    public AuthzTrans set(HttpServletRequest req) {
+    public AuthzTrans set(HttpServletRequest req, HttpServletResponse resp) {
         return null;
     }
 
@@ -138,7 +139,13 @@ public class NullTrans implements AuthzTrans {
        public HttpServletRequest hreq() {
                return null;
        }
+
+    @Override
+       public HttpServletResponse hresp() {
+               return null;
+       }
     
+
        @Override
     public String user() {
         return null;
@@ -236,5 +243,15 @@ public class NullTrans implements AuthzTrans {
         }
         return now;
     }
+       @Override
+       public void setTag(String tag) {
+       }
+       @Override
+       public String getTag() {
+               return null;
+       }
+       @Override
+       public void clearCache() {
+       }
 }
 
index 943b92f..098fb97 100644 (file)
@@ -71,7 +71,7 @@ public class OrganizationFactory {
                                String realm = env.getProperty(Config.AAF_DEFAULT_REALM,"people.osaaf.org");
                                defaultOrg = cnst.newInstance(env,realm);
                        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) {
-                       env.warn().log("Default Organization Module not linked in",e);
+                       env.init().log("Default Organization Module not linked in",e);
                        }
         }
         if (defaultOrg == null) {
index a269f24..37f3b08 100644 (file)
@@ -131,6 +131,12 @@ public class CachingFileAccess<TRANS extends Trans> extends HttpCode<TRANS, Void
         typeMap.put("props", "text/plain");
         typeMap.put("jks", "application/octet-stream");
         
+        // Fonts
+        typeMap.put("ttf","font/ttf");
+        typeMap.put("woff","font/woff");
+        typeMap.put("woff2","font/woff2");
+
+        
         timer = new Timer("Caching Cleanup",true);
         timer.schedule(new Cleanup(content,500),60000,60000);
         
index d0fc1a3..81e2e61 100644 (file)
@@ -33,6 +33,7 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.onap.aaf.auth.env.AuthzTrans;
 import org.onap.aaf.cadi.Access;
 import org.onap.aaf.cadi.CadiException;
 import org.onap.aaf.cadi.CadiWrap;
@@ -85,19 +86,20 @@ public abstract class TransFilter<TRANS extends TransStore> implements Filter {
         return cadi.getLur();
     }
 
-    protected abstract TRANS newTrans(HttpServletRequest request);
-    protected abstract TimeTaken start(TRANS trans, ServletRequest request);
+    protected abstract TRANS newTrans(HttpServletRequest request,HttpServletResponse response);
+    protected abstract TimeTaken start(TRANS trans);
     protected abstract void authenticated(TRANS trans, Principal p);
-    protected abstract void tallyHo(TRANS trans);
+    protected abstract void tallyHo(TRANS trans, String target);
     
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
         HttpServletRequest req = (HttpServletRequest)request;
         HttpServletResponse res = (HttpServletResponse)response;
         
-        TRANS trans = newTrans(req);
+        TRANS trans = newTrans(req,res);
         
-        TimeTaken overall = start(trans,request);
+        TimeTaken overall = start(trans);
+        String target = "n/a";
         try {
             request.setAttribute(TRANS_TAG, trans);
             
@@ -116,6 +118,10 @@ public abstract class TransFilter<TRANS extends TransStore> implements Filter {
             CadiWrap cw = null;
             try {
                 resp = cadi.validate(req,res,trans);
+                Object tag = req.getAttribute("CRED_TAG");
+                if(tag!=null) {
+                       ((AuthzTrans)trans).setTag(tag.toString());
+                }
                 switch(r=resp.isAuthenticated()) {
                     case IS_AUTHENTICATED:
                         cw = new CadiWrap(req,resp,cadi.getLur());
@@ -139,7 +145,7 @@ public abstract class TransFilter<TRANS extends TransStore> implements Filter {
                 // use
                 trans.checkpoint(resp.desc(),Env.ALWAYS);
                 if (resp.isFailedAttempt()) {
-                        trans.audit().log(resp.desc());
+                       target = resp.getTarget();
                 }
             }
         } catch (Exception e) {
@@ -148,7 +154,7 @@ public abstract class TransFilter<TRANS extends TransStore> implements Filter {
             throw new ServletException(e);
         } finally {
             overall.done();
-            tallyHo(trans);
+            tallyHo(trans,target);
         }
     }
 
index c3514b6..ef91e48 100644 (file)
@@ -29,6 +29,8 @@ import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.onap.aaf.cadi.principal.TaggedPrincipal;
 import org.onap.aaf.misc.env.TimeTaken;
@@ -52,16 +54,15 @@ public abstract class TransOnlyFilter<TRANS extends TransStore> implements Filte
     
 
 
-    protected abstract TRANS newTrans();
-    protected abstract TimeTaken start(TRANS trans, ServletRequest request);
+    protected abstract TRANS newTrans(HttpServletRequest req, HttpServletResponse resp);
+    protected abstract TimeTaken start(TRANS trans);
     protected abstract void authenticated(TRANS trans, TaggedPrincipal p);
     protected abstract void tallyHo(TRANS trans);
     
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
-        TRANS trans = newTrans();
-        
-        TimeTaken overall = start(trans,request);
+        TRANS trans = newTrans((HttpServletRequest)request,(HttpServletResponse)response);
+        TimeTaken overall = start(trans);
         try {
             request.setAttribute(TransFilter.TRANS_TAG, trans);
             chain.doFilter(request, response);
index 02d9351..5fbb951 100644 (file)
@@ -76,7 +76,7 @@ public abstract class AbsService<ENV extends BasicEnv, TRANS extends Trans> exte
                str = Defaults.AAF_VERSION;
                env.setProperty(Config.AAF_LOCATOR_VERSION, str);
         }
-        app_version = str;
+        app_version = access.getProperty(Config.AAF_DEPLOYED_VERSION, str);
         
         // Print Cipher Suites Available
         if (access.willLog(Level.DEBUG)) {
index 0e8cb78..11ba656 100644 (file)
@@ -43,9 +43,11 @@ public abstract class AbsServiceStarter<ENV extends RosettaEnv, TRANS extends Tr
     private boolean do_register;
     protected AbsService<ENV,TRANS> service;
        protected String hostname;
+       protected final boolean secure;
 
 
-    public AbsServiceStarter(final AbsService<ENV,TRANS> service) {
+    public AbsServiceStarter(final AbsService<ENV,TRANS> service, boolean secure) {
+       this.secure = secure;
         this.service = service;
         try {
             OrganizationFactory.init(service.env);
@@ -56,7 +58,6 @@ public abstract class AbsServiceStarter<ENV extends RosettaEnv, TRANS extends Tr
         // do_register - this is used for specialty Debug Situations.  Developer can create an Instance for a remote system
         // for Debugging purposes without fear that real clients will start to call your debug instance
         do_register = !"TRUE".equalsIgnoreCase(access().getProperty("aaf_locate_no_register",null));
-        _propertyAdjustment();
         hostname = access().getProperty(Config.HOSTNAME, null);
         if (hostname==null) {
             try {
@@ -65,6 +66,7 @@ public abstract class AbsServiceStarter<ENV extends RosettaEnv, TRANS extends Tr
                                hostname= "cannotBeDetermined";
                        }
         }
+        _propertyAdjustment();
     }
     
     
@@ -96,12 +98,14 @@ public abstract class AbsServiceStarter<ENV extends RosettaEnv, TRANS extends Tr
        });
                if(System.getProperty("ECLIPSE", null)!=null) {
                        Thread.sleep(2000);
-               System.out.println("Service Started in Eclipse: ");
-               System.out.print("  Hit <enter> to end:");
-               try {
-                               System.in.read();
-                               System.exit(0);
-                       } catch (IOException e) {
+                       if(!app.isCancelled()) {
+                       System.out.println("Service Started in Eclipse: ");
+                       System.out.print("  Hit <enter> to end:\n");
+                       try {
+                                       System.in.read();
+                                       System.exit(0);
+                               } catch (IOException e) {
+                               }
                        }
                }
     }
@@ -124,6 +128,7 @@ public abstract class AbsServiceStarter<ENV extends RosettaEnv, TRANS extends Tr
                        _start(service);
                } catch (Exception e) {
                        e.printStackTrace();
+                       shutdown();
                }
        }
 
index bcc071a..8d49720 100644 (file)
@@ -54,23 +54,11 @@ import org.onap.aaf.misc.rosetta.env.RosettaEnv;
 
 
 public class JettyServiceStarter<ENV extends RosettaEnv, TRANS extends Trans> extends AbsServiceStarter<ENV,TRANS> {
-    private boolean secure;
 
-    public JettyServiceStarter(final AbsService<ENV,TRANS> service) throws OrganizationException {
-        super(service);
-        secure = true;
+    public JettyServiceStarter(final AbsService<ENV,TRANS> service, boolean secure) throws OrganizationException {
+        super(service, secure);
     }
     
-    /**
-     * Specifically set this Service starter to Insecure (HTTP) Mode. 
-     * @return
-     */
-    public JettyServiceStarter<ENV,TRANS> insecure() {
-        secure = false;
-        return this;
-    }
-
-
     @Override
     public void _propertyAdjustment() {
 //        System.setProperty("com.sun.management.jmxremote.port", "8081");
index 7e861ed..98c0907 100644 (file)
@@ -143,6 +143,21 @@ public class Validator {
         return this;
     }
 
+    public final Validator permTypeWithUser(String user, String type) {
+        if (type==null) {
+            msg("Perm Type is null");
+        } else if (user==null) {
+            msg("User is null");
+        } else {
+               if(!(type.startsWith(user) && type.endsWith(":id"))) {
+                 if(nob(type,NAME_CHARS)) {
+                   msg("Perm Type [" + type + "] is invalid.");
+                 }
+               }
+        }
+        return this;
+    }
+    
     public final Validator permType(String type, String ns) {
         if (type==null) {
             msg("Perm Type is null");
@@ -169,6 +184,29 @@ public class Validator {
         return this;
     }
 
+    public final Validator role(String user, String role) {
+       boolean quit = false;
+       if(role==null) {
+               msg("Role is null");
+               quit = true;
+       }
+       if(user==null) {
+               msg("User is null");
+               quit = true;
+       }
+       if(!quit) {
+               if(role.startsWith(user) && role.endsWith(":user")) {
+                       if(!(role.length() == user.length() + 5)) {
+                   msg("Role [" + role + "] is invalid.");
+                       }
+               } else if (nob(role, NAME_CHARS)) {
+                   msg("Role [" + role + "] is invalid.");
+               }
+       }
+        return this;
+    }
+
+
     public final Validator role(String role) {
         if (nob(role, NAME_CHARS)) {
             msg("Role [" + role + "] is invalid.");
index f4481ed..af92e37 100644 (file)
@@ -66,11 +66,12 @@ public class JU_AuthzTransImpl {
     public void setUp(){
         authzTransImpl = new AuthzTransImpl(authzEnvMock);
         req = mock(HttpServletRequest.class);
-        authzTransImpl.set(req);
+        res = mock(HttpServletResponse.class);
+        authzTransImpl.set(req,res);
         when(req.getParameter("request")).thenReturn("NotNull");
-        authzTransImpl.set(req);
+        authzTransImpl.set(req,res);
         when(req.getParameter("request")).thenReturn("");
-        authzTransImpl.set(req);    
+        authzTransImpl.set(req,res);    
     }
     
     @Test
index 091a3aa..346ca48 100644 (file)
@@ -76,10 +76,7 @@ public class JU_AuthzTransOnlyFilter {
     public void testStart() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
         AuthzTransOnlyFilter aTF = new AuthzTransOnlyFilter(authzEnvMock);
         Class c = aTF.getClass();
-        Class[] cArg = new Class[2];
-        cArg[0] = AuthzTrans.class;
-        cArg[1] = ServletRequest.class;        //Steps to test a protected method
-        Method startMethod = c.getDeclaredMethod("start", cArg);
+        Method startMethod = c.getDeclaredMethod("start", new Class[] {AuthzTrans.class});
         startMethod.setAccessible(true);
         //startMethod.invoke(aTF, authzTransMock, servletRequestMock);
     }
index f67716f..9c7212c 100644 (file)
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.mock;
 import java.security.Principal;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -157,7 +158,8 @@ public class JU_NullTrans {
     @Test
     public void testSet() {
         HttpServletRequest req = mock(HttpServletRequest.class);
-        AuthzTrans set = nullTrans.set(req);
+        HttpServletResponse res = mock(HttpServletResponse.class);
+        AuthzTrans set = nullTrans.set(req,res);
         Assert.assertNull(set);
     }
     
index 9b49216..4972b57 100644 (file)
@@ -49,8 +49,8 @@ public class JU_AbsServiceStarter {
     
     private class AbsServiceStarterStub extends AbsServiceStarter {
 
-        public AbsServiceStarterStub(AbsService service) {
-            super(service);
+        public AbsServiceStarterStub(AbsService service, boolean secure) {
+            super(service,secure);
             // TODO Auto-generated constructor stub
         }
 
@@ -110,7 +110,7 @@ public class JU_AbsServiceStarter {
         prop.setLogLevel(Level.DEBUG);
         absServiceStub = new AbsServiceStub(prop, bEnv);
         
-        absServiceStarterStub = new AbsServiceStarterStub(absServiceStub);
+        absServiceStarterStub = new AbsServiceStarterStub(absServiceStub,true);
     }
     
 //    @Test
index b56fc03..6795200 100644 (file)
@@ -106,10 +106,13 @@ public class AAF_FS extends AbsService<AuthzEnv, AuthzTrans>  {
         try {
             Log4JLogIt logIt = new Log4JLogIt(args, "fs");
             PropAccess propAccess = new PropAccess(logIt,args);
-
-             AAF_FS service = new AAF_FS(new AuthzEnv(propAccess));
-            JettyServiceStarter<AuthzEnv,AuthzTrans> jss = new JettyServiceStarter<AuthzEnv,AuthzTrans>(service);
-            jss.insecure().start();
+            try {
+                new JettyServiceStarter<AuthzEnv,AuthzTrans>(
+                       new AAF_FS(new AuthzEnv(propAccess)),false)
+                               .start();
+               } catch (Exception e) {
+                   propAccess.log(e);
+               }
         } catch (Exception e) {
             e.printStackTrace();
         }
index 7859b7c..f2d7522 100644 (file)
 package org.onap.aaf.auth.cui;
 
 import java.io.PrintWriter;
+import java.util.regex.Pattern;
 
 import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.onap.aaf.auth.cmd.AAFcli;
 import org.onap.aaf.auth.env.AuthzTrans;
-import org.onap.aaf.auth.env.AuthzEnv;
 import org.onap.aaf.auth.gui.AAF_GUI;
+import org.onap.aaf.auth.gui.Page;
 import org.onap.aaf.auth.rserv.HttpCode;
 import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp;
 import org.onap.aaf.cadi.http.HTransferSS;
@@ -43,6 +45,7 @@ import org.onap.aaf.misc.env.TimeTaken;
 
 public class CUI extends HttpCode<AuthzTrans, Void> {
     private final AAF_GUI gui;
+    private final static Pattern userPerm = Pattern.compile("perm (create|delete).*@.*:id.*aaf.gui.*");
 
 
     public CUI(AAF_GUI gui) {
@@ -84,6 +87,13 @@ public class CUI extends HttpCode<AuthzTrans, Void> {
             }
             try {
                 aafcli.eval(cmdStr);
+                if(userPerm.matcher(cmdStr).matches()) {
+                       trans.clearCache();
+                       Cookie cookie = new Cookie(Page.AAF_THEME,trans.getProperty(Page.AAF_THEME));
+                       cookie.setMaxAge(-1);
+                       cookie.setComment("Remove AAF GUI Theme");
+                       trans.hresp().addCookie(cookie);
+                }
                 pw.flush();
             } catch (Exception e) {
                 pw.flush();
index f8aeb11..17916c2 100644 (file)
@@ -26,6 +26,9 @@ import static org.onap.aaf.auth.rserv.HttpMethods.POST;
 import static org.onap.aaf.auth.rserv.HttpMethods.PUT;
 
 import javax.servlet.Filter;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.onap.aaf.auth.cmd.Cmd;
 import org.onap.aaf.auth.cui.CUI;
@@ -40,6 +43,7 @@ import org.onap.aaf.auth.gui.pages.CMArtiChangeAction;
 import org.onap.aaf.auth.gui.pages.CMArtiChangeForm;
 import org.onap.aaf.auth.gui.pages.CMArtifactShow;
 import org.onap.aaf.auth.gui.pages.CredDetail;
+import org.onap.aaf.auth.gui.pages.CredHistory;
 import org.onap.aaf.auth.gui.pages.Home;
 import org.onap.aaf.auth.gui.pages.LoginLanding;
 import org.onap.aaf.auth.gui.pages.LoginLandingAction;
@@ -66,6 +70,7 @@ import org.onap.aaf.auth.gui.pages.UserRoleExtend;
 import org.onap.aaf.auth.gui.pages.UserRoleRemove;
 import org.onap.aaf.auth.gui.pages.WebCommand;
 import org.onap.aaf.auth.rserv.CachingFileAccess;
+import org.onap.aaf.auth.rserv.HttpCode;
 import org.onap.aaf.auth.server.AbsService;
 import org.onap.aaf.auth.server.JettyServiceStarter;
 import org.onap.aaf.auth.server.Log4JLogIt;
@@ -114,21 +119,21 @@ public class AAF_GUI extends AbsService<AuthzEnv, AuthzTrans> implements State<E
     protected final String deployedVersion;
     private StaticSlot sThemeWebPath;
     private StaticSlot sDefaultTheme;
-//  public final String theme;
 
 
     public AAF_GUI(final AuthzEnv env) throws Exception {
         super(env.access(), env);
         sDefaultTheme = env.staticSlot(AAF_GUI_THEME);
-        env.put(sDefaultTheme, env.getProperty(AAF_GUI_THEME,"onap"));
+        String defTheme = env.getProperty(AAF_GUI_THEME,"onap");
+        env.put(sDefaultTheme, defTheme);
         
         sThemeWebPath = env.staticSlot(CachingFileAccess.CFA_WEB_PATH);
         if(env.get(sThemeWebPath)==null) {
                env.put(sThemeWebPath,"theme");
         }
-
+        
         slot_httpServletRequest = env.slot(HTTP_SERVLET_REQUEST);
-        deployedVersion = access.getProperty(Config.AAF_RELEASE, "N/A:2.x");
+        deployedVersion = app_version;
 
         // Certificate Manager
         String aaf_url_cm = env.getProperty(Config.AAF_URL_CM,Config.AAF_URL_CM_DEF);
@@ -157,8 +162,9 @@ public class AAF_GUI extends AbsService<AuthzEnv, AuthzTrans> implements State<E
         // MyNameSpace
         final Page myNamespaces = new Display(this, GET, new NssShow(this, start)).page();
         Page nsDetail  = new Display(this, GET, new NsDetail(this, start, myNamespaces)).page();
-                              new Display(this, GET, new NsHistory(this, start,myNamespaces,nsDetail));
+                         new Display(this, GET, new NsHistory(this, start,myNamespaces,nsDetail));
         Page crdDetail = new Display(this, GET, new CredDetail(this, start, myNamespaces, nsDetail)).page();
+                         new Display(this, GET, new CredHistory(this,start,myNamespaces,nsDetail,crdDetail));
         Page artiShow  = new Display(this, GET, new CMArtifactShow(this, start, myNamespaces, nsDetail, crdDetail)).page();
         Page artiCForm = new Display(this, GET, new CMArtiChangeForm(this, start, myNamespaces, nsDetail, crdDetail,artiShow)).page();
                          new Display(this, POST, new CMArtiChangeAction(this, start,artiShow,artiCForm));
@@ -204,6 +210,23 @@ public class AAF_GUI extends AbsService<AuthzEnv, AuthzTrans> implements State<E
         // Command line Mechanism
         route(env, PUT, "/gui/cui", new CUI(this),"text/plain;charset=utf-8","*/*");
         
+        route(env, GET, "/gui/clear", new HttpCode<AuthzTrans, Void>(null, "Clear"){
+                       @Override
+                       public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+                               trans.clearCache();
+                               Cookie cookies[] = req.getCookies();
+                               if(cookies!=null) {
+                               for(Cookie c : cookies) {
+                                       if(c.getName().startsWith("aaf.gui.")) {
+                                               c.setMaxAge(0);
+                                               resp.addCookie(c);
+                                       }
+                               }
+                               }
+                               resp.sendRedirect("/gui/home");
+                       }
+        }, "text/plain;charset=utf-8","*/*");
+        
         ///////////////////////  
         // WebContent Handler
         ///////////////////////
@@ -262,9 +285,13 @@ public class AAF_GUI extends AbsService<AuthzEnv, AuthzTrans> implements State<E
             Log4JLogIt logIt = new Log4JLogIt(args, "gui");
             PropAccess propAccess = new PropAccess(logIt,args);
 
-            AAF_GUI service = new AAF_GUI(new AuthzEnv(propAccess));
-            JettyServiceStarter<AuthzEnv,AuthzTrans> jss = new JettyServiceStarter<AuthzEnv,AuthzTrans>(service);
-            jss.start();
+            try {
+                new JettyServiceStarter<AuthzEnv,AuthzTrans>(
+                       new AAF_GUI(new AuthzEnv(propAccess)),true)
+                               .start();
+               } catch (Exception e) {
+                   propAccess.log(e);
+               }
         } catch (Exception e) {
             e.printStackTrace();
         }
index 5b6eb01..9abd5ee 100644 (file)
@@ -46,7 +46,6 @@ import org.onap.aaf.auth.env.AuthzTrans;
 import org.onap.aaf.auth.gui.pages.Home;
 import org.onap.aaf.cadi.Permission;
 import org.onap.aaf.cadi.aaf.AAFPermission;
-import org.onap.aaf.cadi.client.Holder;
 import org.onap.aaf.cadi.config.Config;
 import org.onap.aaf.cadi.principal.TaggedPrincipal;
 import org.onap.aaf.misc.env.APIException;
@@ -70,6 +69,7 @@ import org.onap.aaf.misc.xgen.html.Imports;
  *
  */
 public class Page extends HTMLCacheGen {
+    public static final String AAF_THEME = "aaf_theme";
     public static final String AAFURL_TOOLS = "aaf_url.tools";
     public static final String AAF_URL_TOOL_DOT = "aaf_url.tool.";
     public static final String AAF_URL_CUIGUI = "aaf_url.cuigui"; // link to help
@@ -92,6 +92,23 @@ public class Page extends HTMLCacheGen {
 
     // Note: Only access is synchronized in "getPerm"
     private final static Map<String,Map<String,Permission>> perms = new HashMap<>();
+    
+    /*
+     *      Relative path, Menu Name, Full Path
+     */
+    protected static final String[][] MENU_ITEMS = new String[][] {
+               {"myperms","My Permissions","/gui/myperms"},
+               {"myroles","My Roles","/gui/myroles"},
+               {"ns","My Namespaces","/gui/ns"},
+               {"approve","My Approvals","/gui/approve"},
+               {"myrequests","My Pending Requests","/gui/myrequests"},
+                   // Enable later
+               //  {"onboard","Onboarding"},
+               {"passwd","Password Management","/gui/passwd"},
+               {"cui","Command Prompt","/gui/cui"},
+               {"api","AAF API","/gui/api"},
+               {"clear","Clear Preferences","/gui/clear"}
+    };
 
     public String name() {
         return bcName;
@@ -151,7 +168,8 @@ public class Page extends HTMLCacheGen {
     
     
     private static class PageCode implements Code<HTMLGen> {
-            private static final String AAF_GUI_TITLE = "aaf_gui_title";
+                       private static final String AAF_GUI_THEME = "aaf.gui.theme";
+                       private static final String AAF_GUI_TITLE = "aaf_gui_title";
             
             private final ContentCode[] content;
             private final Slot browserSlot;
@@ -167,6 +185,7 @@ public class Page extends HTMLCacheGen {
                 browserSlot = env.slot(BROWSER_TYPE);
                 sTheme = env.staticSlot(AAF_GUI.AAF_GUI_THEME);
                 this.env = env;
+                       getThemeFiles(env,""); //
             }
 
             private static synchronized List<String> getThemeFiles(Env env, String theme) {
@@ -185,11 +204,11 @@ public class Page extends HTMLCacheGen {
                                                                        themeProps = new TreeMap<>();
                                                                        props = null;
                                                                } else {
-                                                                       props = themeProps.get(theme);
+                                                                       props = themeProps.get(t.getName());
                                                                }
                                                                if(props==null) {
                                                                        props = new Properties();
-                                                                       themeProps.put(theme, props);
+                                                                       themeProps.put(t.getName(), props);
                                                                }
                                                                
                                                                try {
@@ -215,13 +234,10 @@ public class Page extends HTMLCacheGen {
                return themes.get(theme);
             }
             
-            protected Imports getImports(Env env, Holder<String> theme, String defaultTheme, int backdots, BROWSER browser) {
-               List<String> ls = getThemeFiles(env,theme.get());
+            protected Imports getImports(Env env, String theme, int backdots, BROWSER browser) {
+               List<String> ls = getThemeFiles(env,theme);
                Imports imp = new Imports(backdots);
-               if(ls==null) {
-                       theme.set(defaultTheme);
-               }
-                       String prefix = "theme/" + theme.get() + '/';
+                       String prefix = "theme/" + theme + '/';
                        for(String f : ls) {
                        if(f.endsWith(".js")) {
                                imp.js(prefix + f);
@@ -262,7 +278,6 @@ public class Page extends HTMLCacheGen {
                 hgen.html();
                 final String title = env.getProperty(AAF_GUI_TITLE,"Authentication/Authorization Framework");
                 final String defaultTheme = env.get(sTheme,"onap"); 
-                final Holder<String> hTheme = new Holder<>(defaultTheme);
               
                 Mark head = hgen.head();
                     hgen.leaf(TITLE).text(title).end();
@@ -270,15 +285,37 @@ public class Page extends HTMLCacheGen {
                         @Override
                         public void code(AAF_GUI state, AuthzTrans trans, final Cache<HTMLGen> cache, final HTMLGen hgen) throws APIException, IOException {
                                BROWSER browser = browser(trans,browserSlot);  
+                               String theme = null;
                                Cookie[] cookies = trans.hreq().getCookies();
                                if(cookies!=null) {
                                        for(Cookie c : cookies) {
-                                               if("aaf_theme".equals(c.getName())) {
-                                                       hTheme.set(c.getValue());
+                                               if(AAF_GUI_THEME.equals(c.getName())) {
+                                                       theme=c.getValue();
+                                                       if(!(themes.containsKey(theme))) {
+                                                               theme = defaultTheme;
+                                                       }
+                                                       break;
                                                }
                                        }
                                }
-                            hgen.imports(getImports(env,hTheme,defaultTheme,backdots,browser));
+                               
+                               if(theme==null) {
+                                       for(String t : themes.keySet()) {
+                                               if(!t.equals(defaultTheme) && trans.fish(new AAFPermission(null,trans.user()+":id", AAF_GUI_THEME, t))) {
+                                                       theme=t;
+                                                       break;
+                                               }
+                                       }
+                                       if(theme==null) {
+                                               theme = defaultTheme;
+                                       }
+                                       Cookie cookie = new Cookie(AAF_GUI_THEME,theme);
+                                       cookie.setMaxAge(604_800); // one week
+                                       trans.hresp().addCookie(cookie);
+                               }
+                               trans.setProperty(Page.AAF_THEME, theme);
+
+                            hgen.imports(getImports(env,theme,backdots,browser));
                             switch(browser) {
                                 case ie:
                                 case ieOld:
@@ -350,7 +387,8 @@ public class Page extends HTMLCacheGen {
                     }
                     
                     hgen.end(header);
-                    
+
+                    hgen.divID("pageContent");
                     Mark inner = hgen.divID("inner");
                         // Content
                         for (int i=cIdx;i<content.length;++i) {
@@ -361,39 +399,65 @@ public class Page extends HTMLCacheGen {
                         }
 
                     hgen.end(inner);    
+
                     
+                    cache.dynamic(hgen, new DynamicCode<HTMLGen,AAF_GUI,AuthzTrans>() {
+                        @Override
+                        public void code(AAF_GUI state, AuthzTrans trans,Cache<HTMLGen> cache, HTMLGen xgen) throws APIException, IOException {
+                               String theme = trans.getProperty(Page.AAF_THEME);
+                               Properties props;
+                               if(theme==null) {
+                                       props = null;
+                               } else {
+                                       props = themeProps==null?null:themeProps.get(theme);
+                               }
+                               
+                               if(props!=null && "TRUE".equalsIgnoreCase(props.getProperty("enable_nav_btn"))) {
+                                               xgen.leaf("button", "id=navBtn").end();
+                               }
+                        }
+                    });
+                    // Adding "nav Hamburger button"
                     // Navigation - Using older Nav to work with decrepit   IE versions
-                    
                     Mark nav = hgen.divID("nav");
                     cache.dynamic(hgen, new DynamicCode<HTMLGen,AAF_GUI,AuthzTrans>() {
                         @Override
                         public void code(AAF_GUI state, AuthzTrans trans,Cache<HTMLGen> cache, HTMLGen xgen) throws APIException, IOException {
-                               Properties props = themeProps==null?null:themeProps.get(hTheme.get());
-                               if(props!=null && "TRUE".equalsIgnoreCase(props.getProperty("main_menu_in_nav"))) {
-                                xgen.incr("h2").text("Navigation").end();
-                                Mark mark = new Mark();
-                               boolean selected = isSelected(trans.path(),Home.HREF);
-                                               //trans.path().endsWith("home");
-                                xgen.incr(mark,HTMLGen.UL)
-                                       .incr(HTMLGen.LI,selected?"class=selected":"")
-                                       .incr(HTMLGen.A, "href=home")
-                                       .text("Home")
-                                       .end(2);
-                                boolean noSelection = !selected;
-                                for(String[] mi : Home.MENU_ITEMS) {
-                                       //selected = trans.path().endsWith(mi[0]);
-                                       if(noSelection) {
-                                               selected = isSelected(trans.path(),mi[2]);
-                                               noSelection = !selected;
-                                       } else {
-                                               selected = false;
-                                       }
-                                       xgen.incr(HTMLGen.LI,selected?"class=selected":"")
-                                           .incr(HTMLGen.A, "href="+mi[0])
-                                           .text(mi[1])
-                                           .end(2);
-                                }
-                                xgen.end(mark);
+                               String theme = trans.getProperty(Page.AAF_THEME);
+                               Properties props;
+                               if(theme==null) {
+                                       props = null;
+                               } else {
+                                       props = themeProps==null?null:themeProps.get(theme);
+                               }
+                               
+                               if(props!=null) {
+                                       if("TRUE".equalsIgnoreCase(props.getProperty("main_menu_in_nav"))) {
+                                       xgen.incr("h2").text("Navigation").end();
+                                       Mark mark = new Mark();
+                                       boolean selected = isSelected(trans.path(),Home.HREF);
+                                                       //trans.path().endsWith("home");
+                                       xgen.incr(mark,HTMLGen.UL)
+                                               .incr(HTMLGen.LI,selected?"class=selected":"")
+                                               .incr(HTMLGen.A, "href=home")
+                                               .text("Home")
+                                               .end(2);
+                                       boolean noSelection = !selected;
+                                       for(String[] mi : MENU_ITEMS) {
+                                               //selected = trans.path().endsWith(mi[0]);
+                                               if(noSelection) {
+                                                       selected = isSelected(trans.path(),mi[2]);
+                                                       noSelection = !selected;
+                                               } else {
+                                                       selected = false;
+                                               }
+                                               xgen.incr(HTMLGen.LI,selected?"class=selected":"")
+                                                   .incr(HTMLGen.A, "href="+mi[2])
+                                                   .text(mi[1])
+                                                   .end(2);
+                                       }
+                                       xgen.end(mark);
+                                       }
                                }
                         }
 
index 969505b..106c388 100644 (file)
@@ -43,6 +43,7 @@ import org.onap.aaf.cadi.Symm;
 import org.onap.aaf.cadi.client.Future;
 import org.onap.aaf.cadi.client.Rcli;
 import org.onap.aaf.cadi.client.Retryable;
+import org.onap.aaf.cadi.config.Config;
 import org.onap.aaf.misc.env.APIException;
 import org.onap.aaf.misc.env.Env;
 import org.onap.aaf.misc.env.TimeTaken;
@@ -82,7 +83,7 @@ public class ApiDocs extends Page {
 
         public Preamble(AAF_GUI gui) {
             super(false, "preamble");
-            fsUrl = gui.access.getProperty("fs_url", "");
+            fsUrl = gui.access.getProperty(Config.AAF_URL_FS, "/theme");
         }
 
         @Override
index d32c7dc..1e06b10 100644 (file)
@@ -82,32 +82,36 @@ trans.info().log("Step 1");
                                     arti.getSans().add(s);
                                 }
                             }
-                            // Disallow IP entries, except by special Permission
-                            if (!trans.fish(getPerm(ca,"ip"))) {
-                                boolean ok=true;
-                                if (IPValidator.ip(machine)) {
-                                    ok=false;
-                                }
-                                if (ok) {
-                                    for (String s: arti.getSans()) {
-                                        if (IPValidator.ip(s)) {
-                                            ok=false;
-                                            break;
-                                        }
-                                    }
-                                }
-                                if (!ok) {
-                                    hgen.p("Policy Failure: IPs in certificates are only allowed by Exception.");
-                                    return;
-                                }
-                            }
                             
-                            // Disallow Domain based Definitions without exception
-                            if (machine.startsWith("*")) { // Domain set
-                                if (!trans.fish(getPerm(ca, "domain"))) {
-                                    hgen.p("Policy Failure: Domain Artifact Declarations are only allowed by Exception.");
-                                    return;
-                                }
+                            // These checks to not apply to deletions
+                            if(!CMArtiChangeForm.DELETE.equals(trans.get(sCmd, ""))) {
+                                   // Disallow IP entries, except by special Permission
+                                   if (!trans.fish(getPerm(ca,"ip"))) {
+                                       boolean ok=true;
+                                       if (IPValidator.ip(machine)) {
+                                           ok=false;
+                                       }
+                                       if (ok) {
+                                           for (String s: arti.getSans()) {
+                                               if (IPValidator.ip(s)) {
+                                                   ok=false;
+                                                   break;
+                                               }
+                                           }
+                                       }
+                                       if (!ok) {
+                                           hgen.p("Policy Failure: IPs in certificates are only allowed by Exception.");
+                                           return;
+                                       }
+                                   }
+                                   
+                                   // Disallow Domain based Definitions without exception
+                                   if (machine.startsWith("*")) { // Domain set
+                                       if (!trans.fish(getPerm(ca, "domain"))) {
+                                           hgen.p("Policy Failure: Domain Artifact Declarations are only allowed by Exception.");
+                                           return;
+                                       }
+                                   }
                             }
                             
                             arti.setMechid((String)trans.get(sID,null));
index 00e58c8..70d8693 100644 (file)
@@ -214,6 +214,7 @@ public class CredDetail extends Page {
                                 StringWriter buttons = new StringWriter();
                                 HTMLGen hgen = cd.clone(buttons);
                                 hgen.leaf("button","onclick=divVisibility('"+key+"');","class=button").text("Expand").end();
+                                hgen.leaf(HTMLGen.A,"class=button","class=greenbutton","href="+CredHistory.HREF+"?user="+ulm.getKey()).text("History").end();
                                 
                                 StringWriter creds = new StringWriter();
                                 hgen = cd.clone(creds);
@@ -302,8 +303,9 @@ public class CredDetail extends Page {
                                                             Chrono.niceDateStamp(oldest),
                                                             Chrono.niceDateStamp(newest)))
                                                     .end(uRow);
-                                                    
+
                                             }
+                                         
                                         }
                                         hgen.end(utable);
                                     }
@@ -316,6 +318,7 @@ public class CredDetail extends Page {
                                         new TextCell(creds.toString(),STYLE_WIDTH_70)
                                     });
                             }
+
                             for (String missing : lns) {
                                 StringWriter buttons = new StringWriter();
                                 HTMLGen hgen = cd.clone(buttons);
diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CredHistory.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CredHistory.java
new file mode 100644 (file)
index 0000000..7e3962e
--- /dev/null
@@ -0,0 +1,224 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * 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====================================================
+ *
+ */
+
+package org.onap.aaf.auth.gui.pages;
+
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.List;
+
+import org.onap.aaf.auth.env.AuthzEnv;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.gui.AAF_GUI;
+import org.onap.aaf.auth.gui.BreadCrumbs;
+import org.onap.aaf.auth.gui.NamedCode;
+import org.onap.aaf.auth.gui.Page;
+import org.onap.aaf.auth.gui.Table;
+import org.onap.aaf.auth.gui.Table.Cells;
+import org.onap.aaf.auth.gui.table.AbsCell;
+import org.onap.aaf.auth.gui.table.TableData;
+import org.onap.aaf.auth.gui.table.TextCell;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.client.Future;
+import org.onap.aaf.cadi.client.Rcli;
+import org.onap.aaf.cadi.client.Retryable;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Env;
+import org.onap.aaf.misc.env.Slot;
+import org.onap.aaf.misc.env.TimeTaken;
+import org.onap.aaf.misc.xgen.Cache;
+import org.onap.aaf.misc.xgen.DynamicCode;
+import org.onap.aaf.misc.xgen.html.HTMLGen;
+
+import aaf.v2_0.History;
+import aaf.v2_0.History.Item;
+
+
+public class CredHistory extends Page {
+    static final String NAME="CredHistory";
+    static final String HREF = "/gui/credHistory";
+    static final String FIELDS[] = {"user","dates"};
+
+    
+    public CredHistory(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException {
+        super(gui.env,NAME,HREF, FIELDS,
+            new BreadCrumbs(breadcrumbs),
+            new Table<AAF_GUI,AuthzTrans>("History", gui.env.newTransNoAvg(),new Model(gui.env),"class=std"),
+            new NamedCode(true, "content") {
+                @Override
+                public void code(final Cache<HTMLGen> cache, final HTMLGen hgen) throws APIException, IOException {
+                    final Slot user = gui.env.slot(NAME+".user");
+                    cache.dynamic(hgen, new DynamicCode<HTMLGen, AAF_GUI, AuthzTrans>() {
+                        @Override
+                        public void code(final AAF_GUI gui, final AuthzTrans trans,    final Cache<HTMLGen> cache, final HTMLGen hgen)    throws APIException, IOException {
+                            String obUser = trans.get(user, null);
+                            
+                            // Use Javascript to make the table title more descriptive
+                            hgen.js()
+                            .text("var caption = document.querySelector(\".title\");")
+                            .text("caption.innerHTML='History for User [ " + obUser + " ]';")                        
+                            .done();
+                            
+                            // Use Javascript to change Link Target to our last visited Detail page
+                            String lastPage = CredDetail.HREF + "?role=" + obUser;
+                            hgen.js()
+                                .text("alterLink('roledetail', '"+lastPage + "');")                            
+                                .done();
+                            
+                            hgen.br();
+                            hgen.leaf("a", "href=#advanced_search","onclick=divVisibility('advanced_search');","class=greenbutton").text("Advanced Search").end()
+                                .divID("advanced_search", "style=display:none");
+                            hgen.incr("table");
+                                
+                            addDateRow(hgen,"Start Date");
+                            addDateRow(hgen,"End Date");
+                            hgen.incr("tr").incr("td");
+                            hgen.tagOnly("input", "type=button","value=Get History",
+                                    "onclick=datesURL('"+HREF+"?user=" + obUser+"');","class=greenbutton");
+                            hgen.end().end();
+                            hgen.end();
+                            hgen.end();
+                        }
+                    });
+                }
+            }
+
+            );
+        
+    }
+    
+    private static void addDateRow(HTMLGen hgen, String s) {
+        hgen
+            .incr("tr")
+            .incr("td")
+            .incr("label", "for=month", "required").text(s+"*").end()
+            .end()
+            .incr("td")
+            .incr("select", "name=month"+s.substring(0, s.indexOf(' ')), "id=month"+s.substring(0, s.indexOf(' ')), "required")
+            .incr("option", "value=").text("Month").end();
+        for(NsHistory.Month m : NsHistory.Month.values()) {
+            if (Calendar.getInstance().get(Calendar.MONTH) == m.ordinal()) {
+                hgen.incr("option", "selected", "value="+(m.ordinal()+1)).text(m.name()).end();
+            } else {
+                hgen.incr("option", "value="+(m.ordinal()+1)).text(m.name()).end();
+            }
+        }
+        hgen.end()
+            .end()
+            .incr("td")
+            .tagOnly("input","type=number","id=year"+s.substring(0, s.indexOf(' ')),"required",
+                    "value="+Calendar.getInstance().get(Calendar.YEAR), "min=1900", 
+                    "max="+Calendar.getInstance().get(Calendar.YEAR),
+                    "placeholder=Year").end()
+            .end();
+    }
+    
+    
+    /**
+     * Implement the Table Content for History
+     * 
+     * @author Jonathan
+     *
+     */
+    private static class Model extends TableData<AAF_GUI,AuthzTrans> {
+        private static final String[] headers = new String[] {"Date","User","Memo"};
+        private Slot user;
+        private Slot dates;
+        
+        public Model(AuthzEnv env) {
+            user = env.slot(NAME+".user");
+            dates = env.slot(NAME+".dates");
+        }
+        
+        @Override
+        public String[] headers() {
+            return headers;
+        }
+        
+        @Override
+        public Cells get(final AuthzTrans trans, final AAF_GUI gui) {
+            final String oName = trans.get(user,null);
+            final String oDates = trans.get(dates,null);
+            
+            Cells rv = Cells.EMPTY;
+            if (oName!=null) {
+                
+                try {
+                    rv = gui.clientAsUser(trans.getUserPrincipal(), new Retryable<Cells>() {
+                        @Override
+                        public Cells code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+                            ArrayList<AbsCell[]> rv = new ArrayList<>();
+                            TimeTaken tt = trans.start("AAF Get History for credential ["+oName+"]",Env.REMOTE);
+                            String msg = null;
+                            try {
+                                if (oDates != null) {
+                                    client.setQueryParams("yyyymm="+oDates);
+                                }
+                                Future<History> fh = client.read("/authz/hist/subject/"+oName + "/cred",gui.getDF(History.class));
+                                if (fh.get(AAF_GUI.TIMEOUT)) {
+                                    tt.done();
+                                    tt = trans.start("Load History Data", Env.SUB);
+                                    List<Item> histItems = fh.value.getItem();
+                                    
+                                    java.util.Collections.sort(histItems, new Comparator<Item>() {
+                                        @Override
+                                        public int compare(Item o1, Item o2) {
+                                            return o2.getTimestamp().compare(o1.getTimestamp());
+                                        }
+                                    });
+                                    
+                                    for (Item i : histItems) {
+                                        String user = i.getUser();
+                                        AbsCell userCell = new TextCell(user);
+
+                                        String memo = i.getMemo().replace("<script>", "&lt;script&gt;").replace("</script>", "&lt;/script&gt;");
+                                        rv.add(new AbsCell[] {
+                                                new TextCell(i.getTimestamp().toGregorianCalendar().getTime().toString()),
+                                                userCell,
+                                                new TextCell(memo)
+                                        });
+                                    }
+                                } else {
+                                    if (fh.code()==403) {
+                                        rv.add(new AbsCell[] {new TextCell("You may not view History of Credentiol[" + oName + "]", "colspan = 3", "class=center")});
+                                    } else {
+                                        rv.add(new AbsCell[] {new TextCell("*** Data Unavailable ***", "colspan = 3", "class=center")});
+                                    }
+                                }
+                            } finally {
+                                tt.done();
+                            }    
+                            return new Cells(rv,msg);
+                        }
+                    });
+                } catch (Exception e) {
+                    trans.error().log(e);
+                }
+            }
+            return rv;
+        }
+    }
+
+}
index 6fc4b5c..73e118a 100644 (file)
@@ -37,21 +37,6 @@ import org.onap.aaf.misc.xgen.html.HTMLGen;
 
 public class Home extends Page {
     public static final String HREF = "/gui/home";
-    /*
-     *      Relative path, Menu Name, Full Path
-     */
-    public static final String[][] MENU_ITEMS = new String[][] {
-               {"myperms","My Permissions","/gui/myperms"},
-               {"myroles","My Roles","/gui/myroles"},
-               {"ns","My Namespaces","/gui/ns"},
-               {"approve","My Approvals","/gui/approve"},
-               {"myrequests","My Pending Requests","/gui/myrequests"},
-                   // Enable later
-               //  {"onboard","Onboarding"},
-               {"passwd","Password Management","/gui/passwd"},
-               {"cui","Command Prompt","/gui/cui"},
-               {"api","AAF API","/gui/api"}
-    };
     
        public Home(final AAF_GUI gui) throws APIException, IOException {
         super(gui.env,"Home",HREF, NO_FIELDS, new NamedCode(false,"content") {
index 16a6c94..6b1c612 100644 (file)
@@ -168,7 +168,7 @@ public class NsDetail extends Page {
                                 }
                                 String historyLink = NsHistory.HREF 
                                         + "?name=" + nsName;
-                                rv.add(new AbsCell[] {new RefCell("See History",historyLink,false)});
+                                rv.add(new AbsCell[] {new RefCell("See History",historyLink,false,"class=greenbutton")});
                             } finally {
                                 tt.done();
                             }
index bca6c92..dc9119b 100644 (file)
@@ -58,7 +58,6 @@ public class NsHistory extends Page {
     static final String NAME="NsHistory";
     static final String HREF = "/gui/nsHistory";
     static final String FIELDS[] = {"name","dates"};
-    static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id=";
     static enum Month { JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, 
                             AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER };
     
@@ -88,7 +87,7 @@ public class NsHistory extends Page {
                                 .done();
                             
                             hgen.br();
-                            hgen.leaf("a","href=#advanced_search","onclick=divVisibility('advanced_search');").text("Advanced Search").end()
+                            hgen.leaf("a","href=#advanced_search","onclick=divVisibility('advanced_search');","class=greenbutton").text("Advanced Search").end()
                                 .divID("advanced_search", "style=display:none");
                             hgen.incr("table");
                                 
@@ -96,7 +95,7 @@ public class NsHistory extends Page {
                             addDateRow(hgen,"End Date");
                             hgen.incr("tr").incr("td");
                             hgen.tagOnly("input", "type=button","value=Get History",
-                                    "onclick=datesURL('"+HREF+"?name=" + obName+"');");
+                                    "onclick=datesURL('"+HREF+"?name=" + obName+"');","class=greenbutton");
                             hgen.end().end();
                             hgen.end();
                             hgen.end();
index 41711db..ae5fe37 100644 (file)
@@ -60,8 +60,7 @@ import aaf.v2_0.Approvals;
 public class PendingRequestsShow extends Page {
     public static final String HREF = "/gui/myrequests";
     public static final String NAME = "MyRequests";
-    static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id=";
-    static final String[] FIELDS = new String[] {"as_user"}; // as_user Checked in Display
+    private static final String[] FIELDS = new String[] {"as_user"}; // as_user Checked in Display
     private static final String AS_USER=NAME+".as_user";
     
     public PendingRequestsShow(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException {
index 7d31d0e..4a5a940 100644 (file)
@@ -88,7 +88,7 @@ public class PermDetail extends Page {
             final String pInstance = trans.get(instance, null);
             final String pAction = trans.get(action, null);
             Validator v = new Validator();
-            v.permType(pType)
+            v.permTypeWithUser(trans.user(),pType)
              .permInstance(pInstance)
              .permAction(pAction);
             
@@ -135,7 +135,7 @@ public class PermDetail extends Page {
                                 String historyLink = PermHistory.HREF 
                                         + "?type=" + pType + "&instance=" + pInstance + "&action=" + pAction;
                                 
-                                rv.add(new AbsCell[] {new RefCell("See History",historyLink,false)});
+                                rv.add(new AbsCell[] {new RefCell("See History",historyLink,false,"class=greenbutton")});
                             } else {
                                 rv.add(new AbsCell[] {new TextCell(
                                     fp.code()==HttpStatus.NOT_FOUND_404?
index bbaf419..4c3bd32 100644 (file)
@@ -60,9 +60,6 @@ public class PermHistory extends Page {
     static final String NAME="PermHistory";
     static final String HREF = "/gui/permHistory";
     static final String FIELDS[] = {"type","instance","action","dates"};
-    static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id=";
-    static enum Month { JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, 
-        AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER };
     
     public PermHistory(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException {
         super(gui.env,NAME,HREF, FIELDS,
@@ -96,7 +93,7 @@ public class PermHistory extends Page {
                                 .done();
                             
                             hgen.br();
-                            hgen.leaf("a", "href=#advanced_search", "onclick=divVisibility('advanced_search');").text("Advanced Search").end()
+                            hgen.leaf("a", "href=#advanced_search", "onclick=divVisibility('advanced_search');","class=greenbutton").text("Advanced Search").end()
                                 .divID("advanced_search", "style=display:none");
                             hgen.incr("table");
                                 
@@ -106,7 +103,7 @@ public class PermHistory extends Page {
                             hgen.tagOnly("input", "type=button","value=Get History",
                                     "onclick=datesURL('"+HREF+"?type=" + type
                                     + "&instance=" + instance
-                                    + "&action=" + action+"');");
+                                    + "&action=" + action+"');","class=greenbutton");
                             hgen.end().end();
                             hgen.end();
                             hgen.end();
@@ -128,7 +125,7 @@ public class PermHistory extends Page {
             .incr("td")
             .incr("select", "name=month"+s.substring(0, s.indexOf(' ')), "id=month"+s.substring(0, s.indexOf(' ')), "required")
             .incr("option", "value=").text("Month").end();
-        for (Month m : Month.values()) {
+        for (NsHistory.Month m : NsHistory.Month.values()) {
             if (Calendar.getInstance().get(Calendar.MONTH) == m.ordinal()) {
                 hgen.incr("option", "selected", "value="+(m.ordinal()+1)).text(m.name()).end();
             } else {
index bfc258b..6588de5 100644 (file)
@@ -106,7 +106,11 @@ public class RoleDetail extends Page {
         public void prefix(final AAF_GUI gui, final AuthzTrans trans, final Cache<HTMLGen> cache, final HTMLGen hgen) {
             final String pRole = trans.get(sRoleName, null);
             Validator v = new Validator();
-            v.role(pRole);
+            if(!v.isNull("Role",pRole).err()) {
+               if(!pRole.startsWith(trans.user())) {
+                       v.role(pRole);
+               }
+            }
             if (v.err()) {
                 trans.warn().printf("Error in PermDetail Request: %s", v.errs());
                 return;
@@ -266,7 +270,7 @@ public class RoleDetail extends Page {
                         
                 // History 
                 rv.add(new AbsCell[] {
-                        new RefCell("See History",RoleHistory.HREF + "?role=" + pRole,false)
+                        new RefCell("See History",RoleHistory.HREF + "?role=" + pRole,false,"class=greenbutton")
                     });
             } else {
                 rv.add(new AbsCell[]{
index fdf6f9e..a9f0eeb 100644 (file)
@@ -60,9 +60,7 @@ public class RoleHistory extends Page {
     static final String NAME="RoleHistory";
     static final String HREF = "/gui/roleHistory";
     static final String FIELDS[] = {"role","dates"};
-    static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id=";
-    static enum Month { JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, 
-        AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER };
+
     
     public RoleHistory(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException {
         super(gui.env,NAME,HREF, FIELDS,
@@ -90,7 +88,7 @@ public class RoleHistory extends Page {
                                 .done();
                             
                             hgen.br();
-                            hgen.leaf("a", "href=#advanced_search","onclick=divVisibility('advanced_search');").text("Advanced Search").end()
+                            hgen.leaf("a", "href=#advanced_search","onclick=divVisibility('advanced_search');","class=greenbutton").text("Advanced Search").end()
                                 .divID("advanced_search", "style=display:none");
                             hgen.incr("table");
                                 
@@ -98,7 +96,7 @@ public class RoleHistory extends Page {
                             addDateRow(hgen,"End Date");
                             hgen.incr("tr").incr("td");
                             hgen.tagOnly("input", "type=button","value=Get History",
-                                    "onclick=datesURL('"+HREF+"?role=" + obRole+"');");
+                                    "onclick=datesURL('"+HREF+"?role=" + obRole+"');","class=greenbutton");
                             hgen.end().end();
                             hgen.end();
                             hgen.end();
@@ -120,7 +118,7 @@ public class RoleHistory extends Page {
             .incr("td")
             .incr("select", "name=month"+s.substring(0, s.indexOf(' ')), "id=month"+s.substring(0, s.indexOf(' ')), "required")
             .incr("option", "value=").text("Month").end();
-        for (Month m : Month.values()) {
+        for (NsHistory.Month m : NsHistory.Month.values()) {
             if (Calendar.getInstance().get(Calendar.MONTH) == m.ordinal()) {
                 hgen.incr("option", "selected", "value="+(m.ordinal()+1)).text(m.name()).end();
             } else {
index 67f03b2..ca9b3a7 100644 (file)
@@ -350,7 +350,7 @@ div.detail caption {
        color: white;
        font-family: "Lucida Console", Monaco, monospace;
        overflow-y: scroll;
-       height: 300px;
+       height: 600px;
        min-width: 600px;
        padding: 5px;   
        resize: vertical;
index f65c17b..fe4f649 100644 (file)
@@ -29,7 +29,7 @@ function getCommand() {
        cmds = document.querySelector("#command_field").value.split(" ");
        var cleanCmd = "";
        if (document.querySelector("#details_img").getAttribute("class") == "selected") 
-               cleanCmd += "set details=true ";
+               cleanCmd += "details ";
        for (var i = 0; i < cmds.length;i++) {
                var trimmed = cmds[i].trim();
                if (trimmed != "")
@@ -286,7 +286,7 @@ function maximizeConsole(img) {
                content.removeAttribute("class");
                footer.style.display="";
                console_area.style.resize="vertical";
-               console_area.style.height="300px";
+               console_area.style.height="600px";
        }
        selectOption(img,0);
 }
index 6aee85d..d88ed09 100644 (file)
@@ -122,9 +122,13 @@ public class AAF_Hello extends AbsService<AuthzEnv,AuthzTrans> {
             Log4JLogIt logIt = new Log4JLogIt(args, "hello");
             PropAccess propAccess = new PropAccess(logIt,args);
 
-             AAF_Hello service = new AAF_Hello(new AuthzEnv(propAccess));
-            JettyServiceStarter<AuthzEnv,AuthzTrans> jss = new JettyServiceStarter<AuthzEnv,AuthzTrans>(service);
-            jss.start();
+            try {
+                new JettyServiceStarter<AuthzEnv,AuthzTrans>(
+                       new AAF_Hello(new AuthzEnv(propAccess)),true)
+                               .start();
+               } catch (Exception e) {
+                   propAccess.log(e);
+               }
         } catch (Exception e) {
             e.printStackTrace();
         }
index 26bdb69..5ebabed 100644 (file)
@@ -199,8 +199,8 @@ public class AAF_Locate extends AbsService<AuthzEnv, AuthzTrans> {
                        } catch (UnknownHostException | CadiException e) {
                                throw new LocatorException(e);
                        }
-            gui_locator = AbsAAFLocator.create(rph.getPublicEntryName("gui", rph.default_container),
-               Config.AAF_DEFAULT_API_VERSION);
+               String url = rph.getPublicEntryName("gui", rph.default_container);
+            gui_locator = AbsAAFLocator.create(url,Config.AAF_DEFAULT_API_VERSION);
         }
         return gui_locator;
     }
@@ -241,9 +241,13 @@ public class AAF_Locate extends AbsService<AuthzEnv, AuthzTrans> {
             Log4JLogIt logIt = new Log4JLogIt(args, "locate");
             PropAccess propAccess = new PropAccess(logIt,args);
 
-             AAF_Locate service = new AAF_Locate(new AuthzEnv(propAccess));
-            JettyServiceStarter<AuthzEnv,AuthzTrans> jss = new JettyServiceStarter<AuthzEnv,AuthzTrans>(service);
-            jss.start();
+            try {
+                new JettyServiceStarter<AuthzEnv,AuthzTrans>(
+                       new AAF_Locate(new AuthzEnv(propAccess)),true)
+                               .start();
+               } catch (Exception e) {
+                   propAccess.log(e);
+               }
         } catch (Exception e) {
             e.printStackTrace();
         }
index 6d96ded..829335c 100644 (file)
@@ -22,7 +22,6 @@
 package org.onap.aaf.auth.locate.service;
 
 import java.util.List;
-import java.util.UUID;
 
 import org.onap.aaf.auth.dao.cass.ConfigDAO;
 import org.onap.aaf.auth.dao.cass.ConfigDAO.Data;
@@ -72,27 +71,31 @@ public class LocateServiceImpl<IN,OUT,ERROR>
                 return Result.err(Result.ERR_BadData,v.errs());
             }
             int count = 0;
+            StringBuilder denied = null;
             for (MgmtEndpoint me : meps.getMgmtEndpoint()) {
                 if (permToRegister) { 
                     int dot = me.getName().lastIndexOf('.'); // Note: Validator checks for NS for getName()
-                    AAFPermission p = new AAFPermission(me.getName().substring(0,dot),"locator",me.getName(),"write"); 
-                    if (trans.fish(p)) {
-                        LocateDAO.Data data = mapper.locateData(me);
-                        locateDAO.update(trans, data, true);
-                        ++count;
-                    } else {
-                        return Result.err(Result.ERR_Denied,"May not register service (needs " + p.getKey() + ')');
+                    AAFPermission p = new AAFPermission(me.getName().substring(0,dot),"locator",me.getHostname(),"write"); 
+                    if (!trans.fish(p)) {
+                       if(denied==null) {
+                               denied = new StringBuilder("May not register service(s):");
+                       }
+                       
+                        denied.append("\n\t");
+                        denied.append(p.getKey());
+                        denied.append(')');
+                        continue;
                     }
-                } else { //TODO if (MechID is part of Namespace) { 
-                    LocateDAO.Data data = mapper.locateData(me);
-                    locateDAO.update(trans, data, true);
-                    ++count;
                 }
+                LocateDAO.Data data = mapper.locateData(me);
+                locateDAO.update(trans, data, true);
+                ++count;
             }
             if (count>0) {
                 return Result.ok();
             } else {
-                return Result.err(Result.ERR_NotFound, "No endpoints found");
+                return denied==null?Result.err(Result.ERR_NotFound, "No endpoints found")
+                               :Result.err(Result.ERR_Security,denied.toString());
             }
         }
 
@@ -106,28 +109,39 @@ public class LocateServiceImpl<IN,OUT,ERROR>
                 return Result.err(Result.ERR_BadData,v.errs());
             }
             int count = 0;
+            StringBuilder denied = null;
             for (MgmtEndpoint me : meps.getMgmtEndpoint()) {
-                int dot = me.getName().lastIndexOf('.'); // Note: Validator checks for NS for getName()
-                AAFPermission p = new AAFPermission(me.getName().substring(0,dot),"locator",me.getHostname(),"write"); 
-                if (trans.fish(p)) {
-                    LocateDAO.Data data = mapper.locateData(me);
-                    data.port_key = UUID.randomUUID();
-                    locateDAO.delete(trans, data, false);
-                    ++count;
-                } else {
-                    return Result.err(Result.ERR_Denied,"May not register service (needs " + p.getKey() + ')');
-                }
+                if (permToRegister) { 
+                     int dot = me.getName().lastIndexOf('.'); // Note: Validator checks for NS for getName()
+                     AAFPermission p = new AAFPermission(me.getName().substring(0,dot),"locator",me.getHostname(),"write"); 
+                     if (!trans.fish(p)) {
+                       if(denied==null) {
+                               denied = new StringBuilder("May not deregister service(s):");
+                       }
+                       
+                         denied.append("\n\t");
+                         denied.append(p.getKey());
+                         denied.append(')');
+                         continue;
+                     }
+                 }
+                 LocateDAO.Data data = mapper.locateData(me);
+                 locateDAO.delete(trans, data, true);
+                 ++count;
             }
             if (count>0) {
                 return Result.ok();
             } else {
-                return Result.err(Result.ERR_NotFound, "No endpoints found");
+                return denied==null?Result.err(Result.ERR_NotFound, "No endpoints found")
+                               :Result.err(Result.ERR_Security,denied.toString());
             }
         }
 
         /////   ADDED v1_1
         /* (non-Javadoc)
          * @see org.onap.aaf.auth.locate.service.LocateService#getConfig(org.onap.aaf.auth.env.AuthzTrans, java.lang.String, java.lang.String)
+         * 
+         * Note: "id" is put in, in case we need to filter, or direct data change in the future by Permission
          */
         @Override
         public Result<Configuration> getConfig(AuthzTrans trans, String id, String type) {
@@ -145,7 +159,6 @@ public class LocateServiceImpl<IN,OUT,ERROR>
                 }
             }
             return Result.ok(c);
-            //return Result.err(Result.ERR_NotImplemented,"not done yet");
         }
 
 
index d5a6615..7f38b65 100644 (file)
@@ -192,9 +192,13 @@ public class AAF_OAuth extends AbsService<AuthzEnv,AuthzTrans> {
             Log4JLogIt logIt = new Log4JLogIt(args, "oauth");
             PropAccess propAccess = new PropAccess(logIt,args);
 
-             AAF_OAuth service = new AAF_OAuth(new AuthzEnv(propAccess));
-            JettyServiceStarter<AuthzEnv,AuthzTrans> jss = new JettyServiceStarter<AuthzEnv,AuthzTrans>(service);
-            jss.start();
+            try {
+                new JettyServiceStarter<AuthzEnv,AuthzTrans>(
+                       new AAF_OAuth(new AuthzEnv(propAccess)),true)
+                               .start();
+               } catch (Exception e) {
+                   propAccess.log(e);
+               }
         } catch (Exception e) {
             e.printStackTrace();
         }
index 6a63907..333c0fc 100644 (file)
@@ -239,9 +239,13 @@ public class AAF_Service extends AbsService<AuthzEnv,AuthzTrans> {
             Log4JLogIt logIt = new Log4JLogIt(args, "authz");
             PropAccess propAccess = new PropAccess(logIt,args);
             
-            AbsService<AuthzEnv, AuthzTrans> service = new AAF_Service(new AuthzEnv(propAccess));
-            JettyServiceStarter<AuthzEnv,AuthzTrans> jss = new JettyServiceStarter<AuthzEnv,AuthzTrans>(service);
-            jss.start();
+            try {
+                new JettyServiceStarter<AuthzEnv,AuthzTrans>(
+                       new AAF_Service(new AuthzEnv(propAccess)),true)
+                               .start();
+               } catch (Exception e) {
+                   propAccess.log(e);
+               }
         } catch (Exception e) {
             e.printStackTrace();
         }
index e311513..37ca509 100644 (file)
@@ -47,6 +47,9 @@ import javax.servlet.http.HttpServletRequest;
 
 import org.onap.aaf.auth.common.Define;
 import org.onap.aaf.auth.dao.DAOException;
+import org.onap.aaf.auth.dao.cached.CachedPermDAO;
+import org.onap.aaf.auth.dao.cached.CachedRoleDAO;
+import org.onap.aaf.auth.dao.cached.CachedUserRoleDAO;
 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
 import org.onap.aaf.auth.dao.cass.CertDAO;
 import org.onap.aaf.auth.dao.cass.CredDAO;
@@ -70,6 +73,7 @@ import org.onap.aaf.auth.dao.hl.Function.OP_STATUS;
 import org.onap.aaf.auth.dao.hl.Question;
 import org.onap.aaf.auth.dao.hl.Question.Access;
 import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE;
 import org.onap.aaf.auth.layer.Result;
 import org.onap.aaf.auth.org.Executor;
 import org.onap.aaf.auth.org.Organization;
@@ -82,7 +86,9 @@ import org.onap.aaf.auth.service.mapper.Mapper;
 import org.onap.aaf.auth.service.mapper.Mapper.API;
 import org.onap.aaf.auth.service.validation.ServiceValidator;
 import org.onap.aaf.auth.validation.Validator;
+import org.onap.aaf.cadi.aaf.Defaults;
 import org.onap.aaf.cadi.principal.BasicPrincipal;
+import org.onap.aaf.cadi.util.FQI;
 import org.onap.aaf.misc.env.Env;
 import org.onap.aaf.misc.env.TimeTaken;
 import org.onap.aaf.misc.env.util.Chrono;
@@ -109,7 +115,8 @@ import aaf.v2_0.CredRequest;
 public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS>
     implements AuthzService            <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> {
     
-    private Mapper                    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
+    private static final String TWO_SPACE = "  ";
+       private Mapper                    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
     @Override
     public Mapper                    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper() {return mapper;}
     
@@ -799,62 +806,129 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
     @Override
     public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {        
         final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
-        // Does Perm Type exist as a Namespace?
-        if(newPd.value.type.isEmpty() || ques.nsDAO().read(trans, newPd.value.fullType()).isOKhasData()) {
-            return Result.err(Status.ERR_ConflictAlreadyExists,
-                    "Permission Type exists as a Namespace");
-        }
-        
+
         final ServiceValidator v = new ServiceValidator();
         if (v.perm(newPd).err()) {
             return Result.err(Status.ERR_BadData,v.errs());
         }
-        
-        Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
-            new Mapper.Memo() {
-                @Override
-                public String get() {
-                    return "Create Permission [" + 
-                        newPd.value.fullType() + '|' + 
-                        newPd.value.instance + '|' + 
-                        newPd.value.action + ']';
-                }
-            },
-            new MayChange() {
-                private Result<NsDAO.Data> nsd;
-                @Override
-                public Result<?> mayChange() {
-                    if (nsd==null) {
-                        nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
-                    }
-                    return nsd;
-                }
-            });
-        Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, newPd.value.ns);
-        if (nsr.notOKorIsEmpty()) {
-            return Result.err(nsr);
+
+        // User Permission mechanism
+        if(newPd.value.ns.indexOf('@')>0) {
+               PermDAO.Data pdd = newPd.value;
+               if(trans.user().equals(newPd.value.ns)) {
+                       CachedPermDAO permDAO = ques.permDAO();
+                       Result<List<PermDAO.Data>> rlpdd = permDAO.read(trans, pdd);
+                       if(rlpdd.notOK()) {
+                               return Result.err(rlpdd);
+                       }
+                       if(!rlpdd.isEmpty()) {
+                               return Result.err(Result.ERR_ConflictAlreadyExists,"Permission already exists"); 
+                       }
+
+                               RoleDAO.Data rdd = new RoleDAO.Data();
+                               rdd.ns = pdd.ns;
+                               rdd.name = "user";
+
+                               pdd.roles(true).add(rdd.fullName());
+                               Result<PermDAO.Data> rpdd = permDAO.create(trans, pdd);
+                               if(rpdd.notOK()) {
+                                       return Result.err(rpdd);
+                               }
+                               
+                       CachedRoleDAO roleDAO = ques.roleDAO();
+                       Result<List<RoleDAO.Data>> rlrdd = roleDAO.read(trans, rdd);
+                       if(rlrdd.notOK()) {
+                               return Result.err(rlrdd);
+                       } else {
+                               if(!rlrdd.isEmpty()) {
+                                       rdd = rlrdd.value.get(0);
+                               }
+                       }
+                       
+                       String eperm = pdd.encode();
+                       rdd.perms(true).add(eperm);
+                       Result<Void> rv = roleDAO.update(trans, rdd);
+                       if(rv.notOK()) {
+                               return rv;
+                       }
+                        
+                       CachedUserRoleDAO urDAO = ques.userRoleDAO();
+                       UserRoleDAO.Data urdd = new UserRoleDAO.Data();
+                       urdd.user = trans.user();
+                       urdd.ns = rdd.ns;
+                       urdd.rname = rdd.name;
+                       urdd.role = rdd.fullName();
+                       Result<List<UserRoleDAO.Data>> rlurdd = urDAO.read(trans, urdd);
+                       if(rlurdd.notOK()) {
+                               return Result.err(rlrdd);
+                       } else if(rlurdd.isEmpty()) {
+                               GregorianCalendar gc = trans.org().expiration(null, Expiration.UserInRole);
+                               if(gc==null) {
+                                       return Result.err(Result.ERR_Policy,"Organzation does not grant Expiration for UserRole");
+                               } else {
+                                       urdd.expires = gc.getTime();
+                               }
+                               Result<UserRoleDAO.Data> rurdd = urDAO.create(trans, urdd);
+                               return Result.err(rurdd);
+                       }
+                       return rv;
+               } else {
+                       return Result.err(Result.ERR_Security,"Only the User can create User Permissions");
+               }
+        } else {
+               // Does Perm Type exist as a Namespace?
+               if(newPd.value.type.isEmpty() || ques.nsDAO().read(trans, newPd.value.fullType()).isOKhasData()) {
+                   return Result.err(Status.ERR_ConflictAlreadyExists,
+                           "Permission Type exists as a Namespace");
+               }
+               
+               Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
+                   new Mapper.Memo() {
+                       @Override
+                       public String get() {
+                           return "Create Permission [" + 
+                               newPd.value.fullType() + '|' + 
+                               newPd.value.instance + '|' + 
+                               newPd.value.action + ']';
+                       }
+                   },
+                   new MayChange() {
+                       private Result<NsDAO.Data> nsd;
+                       @Override
+                       public Result<?> mayChange() {
+                           if (nsd==null) {
+                               nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
+                           }
+                           return nsd;
+                       }
+                   });
+               
+               Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, newPd.value.ns);
+               if (nsr.notOKorIsEmpty()) {
+                   return Result.err(nsr);
+               }
+               switch(fd.status) {
+                   case OK:
+                       Result<String> rfc = func.createFuture(trans,fd.value, 
+                               newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
+                               trans.user(),
+                               nsr.value.get(0),
+                               FUTURE_OP.C);
+                       if (rfc.isOK()) {
+                           return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
+                                   newPd.value.ns,
+                                   newPd.value.type,
+                                   newPd.value.instance,
+                                   newPd.value.action);
+                       } else {
+                           return Result.err(rfc);
+                       }
+                   case Status.ACC_Now:
+                       return func.createPerm(trans, newPd.value, true);
+                   default:
+                       return Result.err(fd);
+               }
         }
-        switch(fd.status) {
-            case OK:
-                Result<String> rfc = func.createFuture(trans,fd.value, 
-                        newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
-                        trans.user(),
-                        nsr.value.get(0),
-                        FUTURE_OP.C);
-                if (rfc.isOK()) {
-                    return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
-                            newPd.value.ns,
-                            newPd.value.type,
-                            newPd.value.instance,
-                            newPd.value.action);
-                } else {
-                    return Result.err(rfc);
-                }
-            case Status.ACC_Now:
-                return func.createPerm(trans, newPd.value, true);
-            default:
-                return Result.err(fd);
-        }    
     }
 
     @ApiDoc( 
@@ -1392,7 +1466,7 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
             return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
                     perm.ns,perm.type,perm.instance,perm.action    );
         }
-
+        
         Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
                 new Mapper.Memo() {
                     @Override
@@ -1917,6 +1991,9 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
                     public Result<?> mayChange() {
                         if (nsd==null) {
                             nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
+                            if(nsd.notOK()) {
+                               trans.requested(REQD_TYPE.future,true);
+                            }
                         }
                         return nsd;
                     }
@@ -1926,32 +2003,32 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
             return Result.err(nsr);
         }
         switch(fd.status) {
-        case OK:
-            Result<String> rfc = func.createFuture(trans,fd.value, 
-                    rpd.value.fullPerm(),
-                    trans.user(),
-                    nsr.value.get(0),
-                    FUTURE_OP.G);
-            if (rfc.isOK()) {
-                return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
-                        rpd.value.ns,
-                        rpd.value.type,
-                        rpd.value.instance,
-                        rpd.value.action);
-            } else { 
-                return Result.err(rfc);
-            }
-        case Status.ACC_Now:
-            Result<Void> rv = null;
-            if (createPerm!=null) {// has been validated for creating
-                rv = func.createPerm(trans, createPerm, false);
-            }
-            if (rv==null || rv.isOK()) {
-                rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
-            }
-            return rv;
-        default:
-            return Result.err(fd);
+               case OK:
+                   Result<String> rfc = func.createFuture(trans,fd.value, 
+                           rpd.value.fullPerm(),
+                           trans.user(),
+                           nsr.value.get(0),
+                           FUTURE_OP.G);
+                   if (rfc.isOK()) {
+                       return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
+                               rpd.value.ns,
+                               rpd.value.type,
+                               rpd.value.instance,
+                               rpd.value.action);
+                   } else { 
+                       return Result.err(rfc);
+                   }
+               case Status.ACC_Now:
+                   Result<Void> rv = null;
+                   if (createPerm!=null) {// has been validated for creating
+                       rv = func.createPerm(trans, createPerm, false);
+                   }
+                   if (rv==null || rv.isOK()) {
+                       rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
+                   }
+                   return rv;
+               default:
+                   return Result.err(fd);
         }
         
     }
@@ -2229,40 +2306,59 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
     }
 
     private class MayChangeCred implements MayChange {
-        
-        private Result<NsDAO.Data> nsd;
+        private static final String EXTEND = "extend";
+               private static final String RESET = "reset";
+               private static final String DELETE = "delete";
+               private Result<NsDAO.Data> nsd;
         private AuthzTrans trans;
         private CredDAO.Data cred;
-        public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) {
+               private String action;
+        public MayChangeCred(AuthzTrans trans, CredDAO.Data cred, String action) {
             this.trans = trans;
             this.cred = cred;
+            this.action = action;
         }
 
         @Override
         public Result<?> mayChange() {
             // User can change himself (but not create)
-            if (trans.user().equals(cred.id)) {
-                return Result.ok();
-            }
             if (nsd==null) {
                 nsd = ques.validNSOfDomain(trans, cred.id);
             }
             // Get the Namespace
             if (nsd.isOK()) {
-                if (ques.mayUser(trans, trans.user(), nsd.value,Access.write).isOK()) {
-                    return Result.ok();
-                }
-                String user[] = Split.split('.',trans.user());
-                if (user.length>2) {
-                    String company = user[user.length-1] + '.' + user[user.length-2];
-                    if (ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,"reset")) {
-                        return Result.ok();
-                    }
-                }
+                       String ns = nsd.value.name;
+                       String user = trans.user();
+               String company;
+               String temp[] = Split.split('.',ns);
+               switch(temp.length) {
+                       case 0:
+                               company = Defaults.AAF_NS;
+                               break;
+                       case 1:
+                               company = temp[0];
+                               break;
+                       default:
+                               company = temp[0] + '.' + temp[1];
+               }
+               switch(action) {
+                       case DELETE:
+                               if(ques.isOwner(trans, user,ns) ||
+                                  ques.isAdmin(trans, user,ns) ||
+                                                  ques.isGranted(trans, user, ROOT_NS,"password",company,DELETE)) {
+                                               return Result.ok();
+                               }
+                               break;
+                       case RESET:
+                       case EXTEND:
+                        if (ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,action)) {
+                            return Result.ok();
+                        }
+                        break;
+               }
             }
-            return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns);
+            return Result.err(Status.ERR_Denied,"%s is not allowed to %s %s in %s",trans.user(),action,cred.id,cred.ns);
         }
-
     }
 
     private final long DAY_IN_MILLIS = 24*3600*1000L;
@@ -2561,7 +2657,7 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
                      }
             )
     @Override
-    public Result<Void> changeUserCred(final AuthzTrans trans, REQUEST from) {
+    public Result<Void> resetUserCred(final AuthzTrans trans, REQUEST from) {
         final String cmdDescription = "Update User Credential";
         TimeTaken tt = trans.start(cmdDescription, Env.SUB);
         try {
@@ -2579,13 +2675,15 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
                     return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
                 } 
                 
-                MayChange mc = new MayChangeCred(trans, rcred.value);
+                MayChange mc = new MayChangeCred(trans, rcred.value,MayChangeCred.RESET);
                 Result<?> rmc = mc.mayChange(); 
                 if (rmc.notOK()) {
                     return Result.err(rmc);
                 }
                 
-                 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
+                List<CredDAO.Data> lcdd = filterList(rlcd.value,CredDAO.BASIC_AUTH, CredDAO.BASIC_AUTH_SHA256);
+                
+                Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, lcdd, MayChangeCred.RESET);
                 if (ri.notOK()) {
                     return Result.err(ri);
                 }
@@ -2668,27 +2766,6 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         }
     }
 
-    /*
-     * Codify the way to get Either Choice Needed or actual Integer from Credit Request
-     */
-    private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd) {
-        int entry = 0;
-        if (lcd.size() > 1) {
-            String inputOption = cr.getEntry();
-            if (inputOption == null) {
-                String message = selectCredFromList(lcd, false);
-                Object[] variables = buildVariables(lcd);
-                return Result.err(Status.ERR_ChoiceNeeded, message, variables);
-            } else {
-                entry = Integer.parseInt(inputOption) - 1;
-            }
-            if (entry < 0 || entry >= lcd.size()) {
-                return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
-            }
-        }
-        return Result.ok(entry);
-    }
-    
     @ApiDoc( 
             method = PUT,  
             path = "/authn/cred/:days",
@@ -2730,14 +2807,18 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
             if (rlcd.notOKorIsEmpty()) {
                 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
             }
+            
+            // Only Passwords can be extended
+            List<CredDAO.Data> lcdd = filterList(rlcd.value,CredDAO.BASIC_AUTH, CredDAO.BASIC_AUTH_SHA256);
 
             //Need to do the "Pick Entry" mechanism
-            Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
+            // Note, this sorts
+            Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, lcdd, "extend");
             if (ri.notOK()) {
                 return Result.err(ri);
             }
 
-            CredDAO.Data found = rlcd.value.get(ri.value);
+            CredDAO.Data found = lcdd.get(ri.value);
             CredDAO.Data cd = cred.value;
             // Copy over the cred
             cd.id = found.id;
@@ -2759,29 +2840,204 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         }
     }    
 
-    private String[] buildVariables(List<CredDAO.Data> value) {
+    @ApiDoc( 
+               method = DELETE,  
+               path = "/authn/cred",
+               params = {},
+               expectedCode = 200,
+               errorCodes = {300,403,404,406}, 
+               text = { "Delete a Credential. If multiple credentials exist for this",
+                       "ID, you will need to specify which entry you are deleting in the",
+                       "CredRequest object."
+                        }
+               )
+       @Override
+       public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from)  {
+           final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
+           final Validator v = new ServiceValidator();
+           if (v.nullOrBlank("cred", cred.value.id).err()) {
+               return Result.err(Status.ERR_BadData,v.errs());
+           }
+
+           MayChange mc = new MayChangeCred(trans,cred.value,MayChangeCred.DELETE);
+           Result<?> rmc = mc.mayChange(); 
+           if (rmc.notOK()) {
+               return Result.err(rmc);
+           }
+
+           Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
+           if (rlcd.notOKorIsEmpty()) {
+               // Empty Creds should have no user_roles.
+               Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
+               if (rlurd.isOK()) {
+                   for (UserRoleDAO.Data data : rlurd.value) {
+                       ques.userRoleDAO().delete(trans, data, false);
+                   }
+               }
+               return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
+           }
+           boolean isLastCred = rlcd.value.size()==1;
+           
+           
+           int entry = 0;
+           if (!trans.requested(force)) {
+               if (rlcd.value.size() > 1) {
+                   CredRequest cr = (CredRequest)from;
+                   String inputOption = cr.getEntry();
+                   if (inputOption == null) {
+                       List<CredDAO.Data> list = filterList(rlcd.value,CredDAO.BASIC_AUTH,CredDAO.BASIC_AUTH_SHA256,CredDAO.CERT_SHA256_RSA);
+                       String message = selectCredFromList(list, MayChangeCred.DELETE);
+                       Object[] variables = buildVariables(list);
+                       return Result.err(Status.ERR_ChoiceNeeded, message, variables);
+                   } else {
+                       try {
+                           if (inputOption.length()>5) { // should be a date
+                               Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime();
+                               entry = 0;
+                               for (CredDAO.Data cd : rlcd.value) {
+                                   if (cd.type.equals(cr.getType()) && cd.expires.equals(d)) {
+                                       break;
+                                   }
+                                   ++entry;
+                               }
+                           } else {
+                               entry = Integer.parseInt(inputOption) - 1;
+                           }
+                       } catch (NullPointerException e) {
+                           return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry");
+                       } catch (NumberFormatException e) {
+                           return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
+                       }
+                   }
+                   isLastCred = (entry==-1)?true:false;
+               } else {
+                   isLastCred = true;
+               }
+               if (entry < -1 || entry >= rlcd.value.size()) {
+                   return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
+               }
+           }
+           
+           Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
+               () -> "Delete Credential [" +
+                   cred.value.id +
+                   ']',
+               mc);
+       
+           Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, cred.value.ns);
+           if (nsr.notOKorIsEmpty()) {
+               return Result.err(nsr);
+           }
+       
+           switch(fd.status) {
+               case OK:
+                   Result<String> rfc = func.createFuture(trans, fd.value, cred.value.id,
+                           trans.user(), nsr.value.get(0), FUTURE_OP.D);
+       
+                   if (rfc.isOK()) {
+                       return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
+                   } else { 
+                       return Result.err(rfc);
+                   }
+               case Status.ACC_Now:
+                   Result<?>udr = null;
+                   if (!trans.requested(force)) {
+                       if (entry<0 || entry >= rlcd.value.size()) {
+                           return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
+                       }
+                       udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
+                   } else {
+                       for (CredDAO.Data curr : rlcd.value) {
+                           udr = ques.credDAO().delete(trans, curr, false);
+                           if (udr.notOK()) {
+                               return Result.err(udr);
+                           }
+                       }
+                   }
+                   if (isLastCred) {
+                       Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
+                       if (rlurd.isOK()) {
+                           for (UserRoleDAO.Data data : rlurd.value) {
+                               ques.userRoleDAO().delete(trans, data, false);
+                           }
+                       }
+                   }
+                   if (udr==null) {
+                       return Result.err(Result.ERR_NotFound,"No User Data found");
+                   }
+                   if (udr.isOK()) {
+                       return Result.ok();
+                   }
+                   return Result.err(udr);
+               default:
+                   return Result.err(fd);
+           }
+       
+       }
+
+       /*
+        * Codify the way to get Either Choice Needed or actual Integer from Credit Request
+        */
+       private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd, String action) {
+           int entry = 0;
+           if (lcd.size() > 1) {
+               String inputOption = cr.getEntry();
+               if (inputOption == null) {
+                   String message = selectCredFromList(lcd, action);
+                   Object[] variables = buildVariables(lcd);
+                   return Result.err(Status.ERR_ChoiceNeeded, message, variables);
+               } else {
+                   entry = Integer.parseInt(inputOption) - 1;
+               }
+               if (entry < 0 || entry >= lcd.size()) {
+                   return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
+               }
+           }
+           return Result.ok(entry);
+       }
+
+       private List<CredDAO.Data> filterList(List<CredDAO.Data> orig, Integer ... types) {
+       List<CredDAO.Data> rv = new ArrayList<>();
+        for(CredDAO.Data cdd : orig) {
+               if(cdd!=null) {
+                       for(int t : types) {
+                               if(t==cdd.type) {
+                                       rv.add(cdd);
+                               }
+                       }
+               }
+        }
+               return rv;
+       }
+
+       private String[] buildVariables(List<CredDAO.Data> value) {
         // ensure credentials are sorted so we can fully automate Cred regression test
-        Collections.sort(value, (cred1, cred2) -> cred1.expires.compareTo(cred2.expires));
+        Collections.sort(value, (cred1, cred2) -> 
+               cred1.type==cred2.type?cred2.expires.compareTo(cred1.expires):
+                       cred1.type<cred2.type?-1:1);
         String [] vars = new String[value.size()+1];
         vars[0]="Choice";
+        CredDAO.Data cdd;
         for (int i = 0; i < value.size(); i++) {
-        vars[i+1] = value.get(i).id + "    " + value.get(i).type 
-                + "    |" + value.get(i).expires;
+               cdd = value.get(i);
+               vars[i+1] = cdd.id + TWO_SPACE + cdd.type + TWO_SPACE + (cdd.type<10?TWO_SPACE:"")+ cdd.expires + TWO_SPACE + cdd.tag;
         }
         return vars;
     }
     
-    private String selectCredFromList(List<CredDAO.Data> value, boolean isDelete) {
+    private String selectCredFromList(List<CredDAO.Data> value, String action) {
         StringBuilder errMessage = new StringBuilder();
-        String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:";
+        String userPrompt = MayChangeCred.DELETE.equals(action)?
+                       "Select which cred to delete (set force=true to delete all):":
+                       "Select which cred to " + action + ':';
         int numSpaces = value.get(0).id.length() - "Id".length();
         
         errMessage.append(userPrompt + '\n');
-        errMessage.append("       Id");
+        errMessage.append("        ID");
         for (int i = 0; i < numSpaces; i++) {
             errMessage.append(' ');
         }
-        errMessage.append("   Type  Expires" + '\n');
+        errMessage.append(" Type  Expires                       Tag " + '\n');
         for (int i=0;i<value.size();++i) {
             errMessage.append("    %s\n");
         }
@@ -2791,140 +3047,6 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         
     }
 
-    @ApiDoc( 
-            method = DELETE,  
-            path = "/authn/cred",
-            params = {},
-            expectedCode = 200,
-            errorCodes = {300,403,404,406}, 
-            text = { "Delete a Credential. If multiple credentials exist for this",
-                    "ID, you will need to specify which entry you are deleting in the",
-                    "CredRequest object."
-                     }
-            )
-    @Override
-    public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from)  {
-        final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
-        final Validator v = new ServiceValidator();
-        if (v.nullOrBlank("cred", cred.value.id).err()) {
-            return Result.err(Status.ERR_BadData,v.errs());
-        }
-    
-        Result<List<CredDAO.Data>> rlcd = ques.credDAO().readID(trans, cred.value.id);
-        if (rlcd.notOKorIsEmpty()) {
-            // Empty Creds should have no user_roles.
-            Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
-            if (rlurd.isOK()) {
-                for (UserRoleDAO.Data data : rlurd.value) {
-                    ques.userRoleDAO().delete(trans, data, false);
-                }
-            }
-            return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
-        }
-        boolean isLastCred = rlcd.value.size()==1;
-        
-        MayChange mc = new MayChangeCred(trans,cred.value);
-        Result<?> rmc = mc.mayChange(); 
-        if (rmc.notOK()) {
-            return Result.err(rmc);
-        }
-        
-        int entry = 0;
-        if (!trans.requested(force)) {
-            if (rlcd.value.size() > 1) {
-                CredRequest cr = (CredRequest)from;
-                String inputOption = cr.getEntry();
-                if (inputOption == null) {
-                    String message = selectCredFromList(rlcd.value, true);
-                    Object[] variables = buildVariables(rlcd.value);
-                    return Result.err(Status.ERR_ChoiceNeeded, message, variables);
-                } else {
-                    try {
-                        if (inputOption.length()>5) { // should be a date
-                            Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime();
-                            entry = 0;
-                            for (CredDAO.Data cd : rlcd.value) {
-                                if (cd.type.equals(cr.getType()) && cd.expires.equals(d)) {
-                                    break;
-                                }
-                                ++entry;
-                            }
-                        } else {
-                            entry = Integer.parseInt(inputOption) - 1;
-                        }
-                    } catch (NullPointerException e) {
-                        return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry");
-                    } catch (NumberFormatException e) {
-                        return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
-                    }
-                }
-                isLastCred = (entry==-1)?true:false;
-            } else {
-                isLastCred = true;
-            }
-            if (entry < -1 || entry >= rlcd.value.size()) {
-                return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
-            }
-        }
-        
-        Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
-            () -> "Delete Credential [" +
-                cred.value.id +
-                ']',
-            mc);
-    
-        Result<List<NsDAO.Data>> nsr = ques.nsDAO().read(trans, cred.value.ns);
-        if (nsr.notOKorIsEmpty()) {
-            return Result.err(nsr);
-        }
-    
-        switch(fd.status) {
-            case OK:
-                Result<String> rfc = func.createFuture(trans, fd.value, cred.value.id,
-                        trans.user(), nsr.value.get(0), FUTURE_OP.D);
-    
-                if (rfc.isOK()) {
-                    return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
-                } else { 
-                    return Result.err(rfc);
-                }
-            case Status.ACC_Now:
-                Result<?>udr = null;
-                if (!trans.requested(force)) {
-                    if (entry<0 || entry >= rlcd.value.size()) {
-                        return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
-                    }
-                    udr = ques.credDAO().delete(trans, rlcd.value.get(entry),false);
-                } else {
-                    for (CredDAO.Data curr : rlcd.value) {
-                        udr = ques.credDAO().delete(trans, curr, false);
-                        if (udr.notOK()) {
-                            return Result.err(udr);
-                        }
-                    }
-                }
-                if (isLastCred) {
-                    Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO().readByUser(trans, cred.value.id);
-                    if (rlurd.isOK()) {
-                        for (UserRoleDAO.Data data : rlurd.value) {
-                            ques.userRoleDAO().delete(trans, data, false);
-                        }
-                    }
-                }
-                if (udr==null) {
-                    return Result.err(Result.ERR_NotFound,"No User Data found");
-                }
-                if (udr.isOK()) {
-                    return Result.ok();
-                }
-                return Result.err(udr);
-            default:
-                return Result.err(fd);
-        }
-    
-    }
-
-
     @Override
     public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
         TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
@@ -2949,22 +3071,6 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         }
     }
 
-    @ApiDoc( 
-            method = GET,  
-            path = "/authn/basicAuth",
-            params = {},
-            expectedCode = 200,
-            errorCodes = { 403 }, 
-            text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n" 
-                    + "Use /authn/validate instead\n"
-                    + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
-                    + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
-                + "security, and 403 if it does not." }
-            )
-    private void basicAuth() {
-        // This is a place holder for Documentation.  The real BasicAuth API does not call Service.
-    }
-    
     @ApiDoc( 
             method = POST,  
             path = "/authn/validate",
@@ -2995,6 +3101,22 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         return Result.err(Status.ERR_Denied,"Bad Basic Auth");
     }
 
+@ApiDoc( 
+               method = GET,  
+               path = "/authn/basicAuth",
+               params = {},
+               expectedCode = 200,
+               errorCodes = { 403 }, 
+               text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n" 
+                       + "Use /authn/validate instead\n"
+                       + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
+                       + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
+                   + "security, and 403 if it does not." }
+               )
+       private void basicAuth() {
+           // This is a place holder for Documentation.  The real BasicAuth API does not call Service.
+       }
+
 /***********************************
  * USER-ROLE 
  ***********************************/
@@ -3022,7 +3144,7 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
             final UserRoleDAO.Data userRole = urr.value;
             
             final ServiceValidator v = new ServiceValidator();
-            if (v.user_role(userRole).err() ||
+            if (v.user_role(trans.user(),userRole).err() ||
                v.user(trans.org(), userRole.user).err()) {
                 return Result.err(Status.ERR_BadData,v.errs());
             }
@@ -3038,6 +3160,9 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
                     private Result<NsDAO.Data> nsd;
                     @Override
                     public Result<?> mayChange() {
+                       if(urr.value.role.startsWith(urr.value.user)) {
+                               return Result.ok((NsDAO.Data)null);
+                       }
                         if (nsd==null) {
                             RoleDAO.Data r = RoleDAO.Data.decode(userRole);
                             nsd = ques.mayUser(trans, trans.user(), r, Access.write);
@@ -3045,15 +3170,24 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
                         return nsd;
                     }
                 });
-            Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
-            if (nsr.notOKorIsEmpty()) {
-                return Result.err(nsr);
+            
+            NsDAO.Data ndd;
+            if(userRole.role.startsWith(userRole.user)) {
+               userRole.ns=userRole.user;
+               userRole.rname="user";
+               ndd = null;
+            } else {
+                   Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
+                   if (nsr.notOK()) {
+                       return Result.err(nsr);
+                   }
+                   ndd = nsr.value;
             }
 
             switch(fd.status) {
                 case OK:
                     Result<String> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname, 
-                            userRole.user, nsr.value, FUTURE_OP.C);
+                            userRole.user, ndd, FUTURE_OP.C);
                     if (rfc.isOK()) {
                         return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
                                 userRole.user,
@@ -3519,7 +3653,7 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         return Result.ok(users);
     }
 
-    /***********************************
+/***********************************
  * HISTORY 
  ***********************************/    
     @Override
@@ -3593,16 +3727,21 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         }
 
         // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
-        Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
-        if (rnd.notOK()) {
-            return Result.err(rnd);
+        Result<List<HistoryDAO.Data>> resp;
+        if(type.startsWith(trans.user())) {
+               resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
+        } else {
+            Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
+               if (rnd.notOK()) {
+                   return Result.err(rnd);
+               }
+               rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
+               if (rnd.notOK()) {
+                   return Result.err(rnd);    
+               }
+               resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
         }
         
-        rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
-        if (rnd.notOK()) {
-            return Result.err(rnd);    
-        }
-        Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, type, "perm", yyyymm);
         if (resp.notOK()) {
             return Result.err(resp);
         }
@@ -3612,8 +3751,7 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
     @Override
     public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
         final Validator v = new ServiceValidator();
-        if (v.nullOrBlank("NS",ns)
-            .err()) { 
+        if (v.nullOrBlank("NS",ns).err()) { 
             return Result.err(Status.ERR_BadData,v.errs());
         }
 
@@ -3633,6 +3771,22 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         return mapper.history(trans, resp.value,sort);
     }
 
+    @Override
+    public Result<HISTORY> getHistoryBySubject(AuthzTrans trans, String subject, String target, int[] yyyymm, final int sort) {
+       NsDAO.Data ndd = new NsDAO.Data();
+       ndd.name = FQI.reverseDomain(subject);
+        Result<Data> rnd = ques.mayUser(trans, trans.user(), ndd, Access.read);
+        if (rnd.notOK()) {
+            return Result.err(rnd);    
+        }
+
+        Result<List<HistoryDAO.Data>> resp = ques.historyDAO().readBySubject(trans, subject, target, yyyymm);
+        if (resp.notOK()) {
+            return Result.err(resp);
+        }
+        return mapper.history(trans, resp.value,sort);
+    }
+
 /***********************************
  * DELEGATE 
  ***********************************/
index a89f64e..80d317f 100644 (file)
@@ -447,7 +447,7 @@ public interface AuthzService<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERT
      * @param from
      * @return
      */
-    Result<Void> changeUserCred(AuthzTrans trans, REQUEST from);
+    Result<Void> resetUserCred(AuthzTrans trans, REQUEST from);
 
     /**
      * 
@@ -636,6 +636,16 @@ public interface AuthzService<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERT
      */
     public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String subj, int[] yyyymm, int sort);
 
+    /**
+     * 
+     * @param trans
+     * @param target
+     * @param yyyymm
+     * @param sort
+     * @return
+     */
+       public Result<HISTORY> getHistoryBySubject(AuthzTrans trans, String subject, String target, int[] yyyymm, int sort);
+
 /***********************************
  * DELEGATE 
  ***********************************/
@@ -753,7 +763,4 @@ public interface AuthzService<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERT
      */
     public void dbReset(AuthzTrans trans);
 
-
-
-
 }
index 2c868d3..ce730ce 100644 (file)
@@ -170,6 +170,33 @@ public class API_History {
                 }
             }
         });
+        
+        /**
+         * Get History by Subject 
+         */
+        authzAPI.route(GET,"/authz/hist/subject/:type/:subject",API.HISTORY,new Code(facade,"Get History by Perm Type", true) {
+            @Override
+            public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+                int[] years;
+                int descend;
+                try {
+                    years = getYears(req);
+                    descend = decending(req);
+                } catch (Exception e) {
+                    context.error(trans, resp, Result.err(Status.ERR_BadData, e.getMessage()));
+                    return;
+                }
+                
+                Result<Void> r = context.getHistoryBySubject(trans, resp, pathParam(req,":type"), pathParam(req,":subject"),years,descend);
+                switch(r.status) {
+                    case OK:
+                        resp.setStatus(HttpStatus.OK_200); 
+                        break;
+                    default:
+                        context.error(trans,resp,r);
+                }
+            }
+        });
     }
 
     // Check if Ascending
index 463de35..80e0226 100644 (file)
@@ -235,13 +235,15 @@ public interface AuthzFacade {
      */
     public abstract Result<Void> getHistoryByUser(AuthzTrans trans,    HttpServletResponse resp, String user, int[] yyyymm, final int sort);
     
-    public abstract Result<Void> getHistoryByRole(AuthzTrans trans,    HttpServletResponse resp, String subject, int[] yyyymm, final int sort);
+    public abstract Result<Void> getHistoryByRole(AuthzTrans trans,    HttpServletResponse resp, String role, int[] yyyymm, final int sort);
 
-    public abstract Result<Void> getHistoryByPerm(AuthzTrans trans,    HttpServletResponse resp, String subject, int[] yyyymm, final int sort);
+    public abstract Result<Void> getHistoryByPerm(AuthzTrans trans,    HttpServletResponse resp, String perm, int[] yyyymm, final int sort);
 
-    public abstract Result<Void> getHistoryByNS(AuthzTrans trans,    HttpServletResponse resp, String subject, int[] yyyymm, final int sort);
+    public abstract Result<Void> getHistoryByNS(AuthzTrans trans,    HttpServletResponse resp, String ns, int[] yyyymm, final int sort);
 
-    /*
+    public abstract Result<Void> getHistoryBySubject(AuthzTrans trans, HttpServletResponse resp, String type, String subject, int[] yyyymm, int sort);
+
+       /*
      * Cache 
      */
     public abstract Result<Void> cacheClear(AuthzTrans trans, String pathParam);
index 02fa842..e85e52e 100644 (file)
@@ -44,7 +44,9 @@ import static org.onap.aaf.auth.layer.Result.OK;
 
 import java.io.IOException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -172,9 +174,15 @@ public abstract class AuthzFacadeImpl<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         if (result.variables==null) {
             detail = new String[1];
         } else {
-            int l = result.variables.length;
-            detail=new String[l+1];
-            System.arraycopy(result.variables, 0, detail, 1, l);
+               List<String> dlist = new ArrayList<String>();
+               String os;
+               for(Object s : result.variables) {
+                       if(s!=null && (os=s.toString()).length()>0) {
+                               dlist.add(os);
+                       }
+               }
+               detail = new String[dlist.size()];
+               dlist.toArray(detail);
         }
         //int httpstatus;
         
@@ -280,10 +288,6 @@ public abstract class AuthzFacadeImpl<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
                 break;
             case ERR_ChoiceNeeded:
                 msgId = "SVC1300";
-                detail = new String[result.variables.length];
-                for(int i=0; i<result.variables.length;++i) {
-                       detail[i]=result.variables[i].toString();
-                }
                 response.setStatus(/*httpstatus=*/300);
                 break;
             case ERR_Backend: 
@@ -1623,7 +1627,7 @@ public abstract class AuthzFacadeImpl<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
                 Question.logEncryptTrace(trans,data.asString());
             }
 
-            return service.changeUserCred(trans, data.asObject());
+            return service.resetUserCred(trans, data.asObject());
         } catch (APIException e) {
             trans.error().log(e,"Bad Input data");
             return Result.err(Status.ERR_BadData, e.getLocalizedMessage());
@@ -2274,6 +2278,7 @@ public abstract class AuthzFacadeImpl<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
     public static final String GET_HISTORY_ROLE = "getHistoryByRole";
     public static final String GET_HISTORY_PERM = "getHistoryByPerm";
     public static final String GET_HISTORY_NS = "getHistoryByNS";
+    public static final String GET_HISTORY_SUBJECT = "getHistoryBySubject";
     /* (non-Javadoc)
      * @see com.att.authz.facade.AuthzFacade#getHistoryByUser(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
      */
@@ -2447,6 +2452,50 @@ public abstract class AuthzFacadeImpl<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
         }
     }
 
+    /* (non-Javadoc)
+     * @see com.att.authz.facade.AuthzFacade#getHistoryByUser(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+     */
+    @Override
+    public Result<Void> getHistoryBySubject(AuthzTrans trans, HttpServletResponse resp, String subject, String target, int[] yyyymm, final int sort) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(GET_HISTORY_SUBJECT);
+        sb.append(' ');
+        sb.append(subject);
+        sb.append(" for ");
+        boolean first = true;
+        for (int i : yyyymm) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(',');
+            }
+            sb.append(i);
+        }
+        TimeTaken tt = trans.start(sb.toString(), Env.SUB|Env.ALWAYS);
+
+        try {
+            Result<HISTORY> rh = service.getHistoryBySubject(trans,subject,target,yyyymm,sort);
+            switch(rh.status) {
+                case OK: 
+                    RosettaData<HISTORY> data = historyDF.newData(trans).load(rh.value);
+                    if (Question.willSpecialLog(trans, trans.user())) {
+                        Question.logEncryptTrace(trans,data.asString());
+                    }
+
+                    data.to(resp.getOutputStream());
+                    setContentType(resp,historyDF.getOutType());
+                    return Result.ok();
+                default:
+                    return Result.err(rh);
+            }
+        } catch (Exception e) {
+            trans.error().log(e,IN,GET_HISTORY_USER);
+            return Result.err(e);
+        } finally {
+            tt.done();
+        }
+    }
+
     public final static String CACHE_CLEAR = "cacheClear "; 
 //    public final static String CACHE_VALIDATE = "validateCache";
     
index 187f4e3..44ad7fc 100644 (file)
@@ -38,6 +38,7 @@ import org.onap.aaf.auth.dao.cass.ApprovalDAO;
 import org.onap.aaf.auth.dao.cass.CertDAO;
 import org.onap.aaf.auth.dao.cass.CredDAO;
 import org.onap.aaf.auth.dao.cass.DelegateDAO;
+import org.onap.aaf.auth.dao.cass.DelegateDAO.Data;
 import org.onap.aaf.auth.dao.cass.FutureDAO;
 import org.onap.aaf.auth.dao.cass.HistoryDAO;
 import org.onap.aaf.auth.dao.cass.Namespace;
@@ -47,7 +48,6 @@ import org.onap.aaf.auth.dao.cass.PermDAO;
 import org.onap.aaf.auth.dao.cass.RoleDAO;
 import org.onap.aaf.auth.dao.cass.Status;
 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
-import org.onap.aaf.auth.dao.cass.DelegateDAO.Data;
 import org.onap.aaf.auth.dao.hl.Question;
 import org.onap.aaf.auth.dao.hl.Question.Access;
 import org.onap.aaf.auth.env.AuthzTrans;
@@ -58,6 +58,7 @@ import org.onap.aaf.auth.org.Organization.Expiration;
 import org.onap.aaf.auth.rserv.Pair;
 import org.onap.aaf.auth.service.MayChange;
 import org.onap.aaf.cadi.aaf.marshal.CertsMarshal;
+import org.onap.aaf.cadi.util.Split;
 import org.onap.aaf.cadi.util.Vars;
 import org.onap.aaf.misc.env.Env;
 import org.onap.aaf.misc.env.TimeTaken;
@@ -364,18 +365,32 @@ public class Mapper_2_0 implements Mapper<Nss, Perms, Pkey, Roles, Users, UserRo
     @Override
     public Result<PermDAO.Data> perm(AuthzTrans trans, Request req) {
         PermRequest from = (PermRequest)req;
-        Result<NsSplit> nss = q.deriveNsSplit(trans, from.getType());
+        String type = from.getType();
+        if(type==null) {
+               return Result.err(Result.ERR_BadData, "Invalid Perm Type");
+        }
         PermDAO.Data pd = new PermDAO.Data();
-        if (nss.isOK()) { 
-            pd.ns=nss.value.ns;
-            pd.type = nss.value.name;
-            pd.instance = from.getInstance();
-            pd.action = from.getAction();
-            pd.description = from.getDescription();
-            trans.checkpoint(pd.fullPerm(), Env.ALWAYS);
-            return Result.ok(pd);
-        } else {
-            return Result.err(nss);
+        if(type.contains("@")) {
+               String[] split = Split.splitTrim(':', type);
+               pd.ns = split[0];
+               pd.type=split.length>1?split[1]:"";
+               pd.instance = from.getInstance();
+               pd.action = from.getAction();
+               pd.description = from.getDescription();
+               return Result.ok(pd);
+        }  else {
+               Result<NsSplit> nss = q.deriveNsSplit(trans, from.getType());
+               if (nss.isOK()) { 
+                   pd.ns=nss.value.ns;
+                   pd.type = nss.value.name;
+                   pd.instance = from.getInstance();
+                   pd.action = from.getAction();
+                   pd.description = from.getDescription();
+                   trans.checkpoint(pd.fullPerm(), Env.ALWAYS);
+                   return Result.ok(pd);
+               } else {
+                   return Result.err(nss);
+               }
         }
     }
     
index adff461..df8bde8 100644 (file)
@@ -57,7 +57,9 @@ public class ServiceValidator extends Validator {
         if (pd==null) {
             msg("Perm Data is null.");
         } else {
-            ns(pd.ns);
+               if(!pd.ns.contains("@")) { 
+                       ns(pd.ns);
+               }
             permType(pd.type,pd.ns);
             permInstance(pd.instance);
             permAction(pd.action);
@@ -84,7 +86,7 @@ public class ServiceValidator extends Validator {
         }
         return this;
     }
-
+    
     public ServiceValidator role(RoleDAO.Data pd) {
         if (pd==null) {
             msg("Role Data is null.");
@@ -217,6 +219,16 @@ public class ServiceValidator extends Validator {
         return this;
     }
 
+    public ServiceValidator user_role(String user, UserRoleDAO.Data urdd) {
+        role(user,urdd.role);
+        if(!urdd.role.startsWith(user)) { 
+               nullOrBlank("UserRole.ns",urdd.ns);
+               nullOrBlank("UserRole.rname",urdd.rname);
+        }
+        return this;
+    }
+
+    
     public ServiceValidator user_role(UserRoleDAO.Data urdd) {
         if (urdd==null) {
             msg("UserRole is null");
index a9c90f9..81e96b4 100644 (file)
@@ -20,4 +20,4 @@
 #
 
 . ./d.props
-${DOCKER:=docker} exec -it aaf-$1 bash -c "cd /opt/app/osaaf/logs && exec bash"
+${DOCKER:=docker} exec -it aaf-$1 bash -c "cd /opt/app && exec bash"
diff --git a/auth/docker/dinstall.sh b/auth/docker/dinstall.sh
new file mode 100644 (file)
index 0000000..22ea4c9
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash 
+#########
+#  ============LICENSE_START====================================================
+#  org.onap.aaf
+#  ===========================================================================
+#  Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+#  ===========================================================================
+#  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====================================================
+#
+# This is only called from HEAT, as it needs a single check and wait for Cassandra to be ready
+#
+cd ../auth-cass/docker
+. dinstall.sh $@
+cd -
+if [ "$1" = "publish" ]; then
+  shift
+fi
+. drun.sh 
index 648c497..1910f4a 100644 (file)
@@ -106,6 +106,7 @@ for AAF_COMPONENT in ${AAF_COMPONENTS}; do
         --env aaf_locator_container_ns=${NAMESPACE} \
         --env aaf_locator_fqdn=${HOSTNAME} \
         --env aaf_locator_public_fqdn=${HOSTNAME} \
+        --env aaf_deployed_version=${VERSION} \
         --env LATITUDE=${LATITUDE} \
         --env LONGITUDE=${LONGITUDE} \
         --env CASSANDRA_CLUSTER=${CASSANDRA_CLUSTER} \
index 5bb8351..b1c8e63 100644 (file)
@@ -1,4 +1,4 @@
-. ../../docker/d.props
+. ../../docker/aaf.props
 IMAGE=onap/aaf/aaf_agent:$VERSION
 
 kubectl -n onap run -it --rm aaf-agent-$USER --image=$IMAGE --overrides='
index 8d43070..3a0a377 100644 (file)
@@ -54,7 +54,7 @@ image:
   # When using Docker Repo, add, and include trailing "/"
   # repository: nexus3.onap.org:10003/
   # repository: localhost:5000/
-  version: 2.1.12-SNAPSHOT
+  version: 2.1.14-SNAPSHOT
 
 resources: {}
   # We usually recommend not to specify default resources and to leave this as a conscious
index 0f0f276..d0a1d28 100644 (file)
@@ -22,4 +22,4 @@ apiVersion: v1
 appVersion: "1.0"
 description: AAF Helm Chart
 name: aaf
-version: 2.1.12-SNAPSHOT
+version: 2.1.14-SNAPSHOT
index c31496f..4c54077 100644 (file)
@@ -90,6 +90,8 @@ spec:
               value: "{{.Values.services.aaf_locator_name}}"
             - name: aaf_locator_name_helm
               value: "{{.Values.services.aaf_locator_name_helm}}"
+            - name: aaf_deployed_version
+              value: "{{ .Values.image.version }}"
             - name: CASSANDRA_CLUSTER
               value: "{{.Values.services.cass.fqdn}}.{{.Values.services.ns}}"
 #            - name: CASSANDRA_USER
index 29d9f96..c14754a 100644 (file)
@@ -33,7 +33,7 @@ echo "# Properties passed in"
 
 # Set from CAP Based PROPS, if necessary
 aaf_env=${aaf_env:-"${AAF_ENV}"}
-aaf_release=${aaf_release:-"${VERSION}"}
+aaf_deployed_version=${aaf_deployed_version:-"${VERSION}"}
 cadi_latitude=${cadi_latitude:-"${LATITUDE}"}
 cadi_longitude=${cadi_longitude:-"${LONGITUDE}"}
 cadi_x509_issuers=${cadi_x509_issuers:-"${CADI_X509_ISSUERS}"}
index 8397619..cf70164 100644 (file)
@@ -1,9 +1,12 @@
-aaf|aaf_env|DEV
-aaf|aaf_oauth2_introspect_url|https://AAF_LOCATE_URL/%CNS.%AAF_NS.introspect:2.1/introspect
-aaf|aaf_oauth2_token_url|https://AAF_LOCATE_URL/%CNS.%AAF_NS.token:2.1/token
-aaf|aaf_url|https://AAF_LOCATE_URL/%CNS.%AAF_NS.service:2.1
-aaf|cadi_protocols|TLSv1.1,TLSv1.2
-aaf|cadi_x509_issuers|CN=intermediateCA_1, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_7, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_9, OU=OSAAF, O=ONAP, C=US
-aaf|cm_url|https://AAF_LOCATE_URL/%CNS.%AAF_NS.cm:2.1
-aaf|fs_url|https://AAF_LOCATE_URL/%CNS.%AAF_NS.fs:2.1
-aaf|gui_url|https://AAF_LOCATE_URL/%CNS.%AAF_NS.gui:2.1
+aaf,aaf_cm_url,https://AAF_LOCATE_URL/%CNS.%AAF_NS.cm:2.1\r
+aaf,aaf_env,DEV\r
+aaf,aaf_fs_url,https://AAF_LOCATE_URL/%CNS.%AAF_NS.fs:2.1\r
+aaf,aaf_gui_url,https://AAF_LOCATE_URL/%CNS.%AAF_NS.gui:2.1\r
+aaf,aaf_locate_url,https://aaf.dev.att.com:8095\r
+aaf,aaf_oauth2_introspect_url,https://AAF_LOCATE_URL/%CNS.%AAF_NS.introspect:2.1/introspect\r
+aaf,aaf_oauth2_token_url,https://AAF_LOCATE_URL/%CNS.%AAF_NS.token:2.1/token\r
+aaf,aaf_oauth_url,https://AAF_LOCATE_URL/%CNS.%AAF_NS.oauth:2.1\r
+aaf,aaf_root_ns,com.att.aaf\r
+aaf,aaf_url,https://AAF_LOCATE_URL/%CNS.%AAF_NS.service:2.1\r
+aaf,cadi_protocols,"TLSv1.1,TLSv1.2"\r
+aaf,cadi_x509_issuers,"CN=intermediateCA_1, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_7, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_9, OU=OSAAF, O=ONAP, C=US"\r
index be1d392..037ee8b 100644 (file)
@@ -83,6 +83,9 @@ public class AAFPermission implements Permission {
      * If you want a simple field comparison, it is faster without REGEX
      */
     public boolean match(Permission p) {
+       if(p==null) {
+               return false;
+       }
         String aafNS;
         String aafType;
         String aafInstance;
index e5a0a28..f02c17f 100644 (file)
@@ -76,7 +76,7 @@ public class TestConnectivity {
                 List<SecuritySetter<HttpURLConnection>> lss = loadSetters(access,si);
                 /////////
                 String directAAFURL = aaf_urls.get(Config.AAF_URL);
-                if(directAAFURL!=null && !directAAFURL.contains("/locate/")) {
+                if(directAAFURL!=null && !directAAFURL.contains("/locate/") || !directAAFURL.contains("AAF_LOCATE_URL")) {
                     print(true,"Test Connections by non-located aaf_url");
                     Locator<URI> locator = new SingleEndpointLocator(directAAFURL);
                     connectTest(locator,new URI(directAAFURL));
index 5542126..42efd89 100644 (file)
@@ -88,9 +88,13 @@ public class ErrMessage {
     public StringBuilder toMsg(StringBuilder sb, Error err) {
         sb.append(err.getMessageId());
         sb.append(' ');
-        String[] vars = new String[err.getVariables().size()];
+        Object[] vars = new String[err.getVariables().size()];
         err.getVariables().toArray(vars);
         Vars.convert(sb, err.getText(),vars);
         return sb;
     }
+    
+    public Error getError(Future<?> future) throws APIException {
+       return errDF.newData().in(TYPE.JSON).load(future.body()).asObject();
+    }
 }
index 606638a..ec0875c 100644 (file)
@@ -117,7 +117,7 @@ public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {
                 return "AAF Inaccessible";
             case UNVALIDATED:
                 addUser(new User<AAFPermission>(user,bytes,con.timeout));
-                return "User/Pass combo invalid for " + user;
+                return "user/pass combo invalid for " + user;
             case DENIED:
                 return "AAF denies API for " + user;
             default: 
index 99c3c3f..a25d250 100644 (file)
@@ -106,6 +106,7 @@ public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpT
 
         // Note: Either Carbon or Silicon based LifeForms ok
         String authz = req.getHeader("Authorization");
+        String target = "invalid";
         if (authz != null && authz.startsWith("Basic ")) {
             if (warn&&!req.isSecure()) {
                 aaf.access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");
@@ -131,7 +132,7 @@ public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpT
 
                 Miss miss = missed(bp.getName(), bp.getCred());
                 if (miss!=null && !miss.mayContinue()) {
-                    return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+                    return new BasicHttpTafResp(aaf.access,bp.getName(),buildMsg(bp,req,
                             "User/Pass Retry limit exceeded"), 
                             RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),true);
                 }
@@ -157,11 +158,11 @@ public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpT
                                 // 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,
+                                    return new BasicHttpTafResp(aaf.access,bp.getName(),buildMsg(bp,req,
                                             "user/pass combo invalid via AAF from " + req.getRemoteAddr()), 
                                             RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),true);
                                 } else {
-                                    return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
+                                    return new BasicHttpTafResp(aaf.access,bp.getName(),buildMsg(bp,req,
                                             "user/pass combo invalid via AAF from " + req.getRemoteAddr() + " - Retry limit exceeded"), 
                                             RESP.FAIL,resp,aaf.getRealm(),true);
                                 }
@@ -172,7 +173,7 @@ public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpT
             } 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);
+                return new BasicHttpTafResp(aaf.access,target,msg, RESP.TRY_AUTHENTICATING, resp, aaf.getRealm(),true);
             } catch (Exception e) {
                 String msg = buildMsg(null,req,"Authenticating Service unavailable");
                 try {
@@ -181,10 +182,10 @@ public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpT
                     aaf.access.log(e1, "Error Invalidating Client");
                 }
                 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,target,msg, RESP.FAIL, resp, aaf.getRealm(),false);
             }
         }
-        return new BasicHttpTafResp(aaf.access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),false);
+        return new BasicHttpTafResp(aaf.access,target,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),false);
     }
     
     private String buildMsg(Principal pr, HttpServletRequest req, Object... msg) {
index ac8168b..e43250a 100644 (file)
@@ -122,6 +122,9 @@ public abstract class AbsAAFLocator<TRANS extends Trans> implements Locator<URI>
     }
         
     public static Locator<URI> create(final String name, final String version) throws LocatorException {
+       if(locatorCreator==null) {
+               throw new LocatorException("LocatorCreator is not set");
+       }
         return locatorCreator.create(name, version);
     }
 
@@ -234,7 +237,7 @@ public abstract class AbsAAFLocator<TRANS extends Trans> implements Locator<URI>
     @Override
     public Item best() throws LocatorException {
         if (!hasItems()) {
-            throw new LocatorException("No Entries found for '" + aaf_locator_uri.toString() + "/locate/" + name + ':' + version + '\'');
+            throw new LocatorException("No Entries found for '" + aaf_locator_uri.toString() + '/' + name + ':' + version + '\'');
         }
         List<EP> lep = new ArrayList<>();
         EP first = null;
index e50b52d..98abfbf 100644 (file)
@@ -28,12 +28,14 @@ import java.io.IOException;
 import java.net.ConnectException;
 import java.net.HttpURLConnection;
 import java.net.InetAddress;
+import java.net.URISyntaxException;
 import java.net.UnknownHostException;
 import java.nio.file.Files;
 import java.security.KeyPair;
 import java.security.KeyStore;
 import java.security.cert.X509Certificate;
 import java.util.ArrayDeque;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Deque;
 import java.util.GregorianCalendar;
@@ -84,7 +86,8 @@ import locate.v1_1.Configuration;
 import locate.v1_1.Configuration.Props;
 
 public class Agent {
-    private static final String HASHES = "################################################################";
+    private static final String AGENT_LOAD_URLS = "Agent:loadURLs";
+       private static final String HASHES = "################################################################";
     private static final String PRINT = "print";
     private static final String FILE = "file";
     public static final String PKCS12 = "pkcs12";
@@ -233,8 +236,7 @@ public class Agent {
                             aafsso.setLogDefault();
                             aafsso.setStdErrDefault();
                             
-                            Map<String, String> aaf_urls = loadURLs(access);
-                            aafsso.addProp(Config.AAF_URL_CM, aaf_urls.get(Config.AAF_URL_CM));
+                            /*urls=*/loadURLs(access);
                             aafsso.writeFiles();
                         }
     
@@ -310,29 +312,41 @@ public class Agent {
                String dot_le = access.getProperty(Config.AAF_LOCATOR_CONTAINER,null);
                dot_le=dot_le==null?"":'.'+dot_le;
                String version = access.getProperty(Config.AAF_API_VERSION,Config.AAF_DEFAULT_API_VERSION);
-               for(String u : new String[] {"aaf","locate","oauth","cm","gui","fs","hello","token","introspect"}) {
-                       String proto = "fs".equals(u)?"http://":"https://";
-                       String lhost;
-                       if("locate".equals(u)) {
-                               lhost=rph.default_fqdn;
-                       } else {
-                               lhost=Config.AAF_LOCATE_URL_TAG;
-                       }
-                       String value = rph.replacements("Agent:loadURLs",
-                                       proto + lhost + "/%CNS.%AAF_NS." + ("aaf".equals(u)?"service":u) + ':' + version, 
-                                       null,dot_le);
+               for(String u : new String[] {"locate","aaf","oauth","cm","gui","fs","hello","token","introspect"}) {
+                       String tag;
+                       String append=null;
                        switch(u) {
-                               case "aaf": rv.put(Config.AAF_URL, value); break;
-                               case "locate": rv.put(Config.getAAFLocateUrl(access), value); break;
-                               case "token": rv.put(Config.AAF_OAUTH2_TOKEN_URL, value); break;
-                               case "introspect": rv.put(Config.AAF_OAUTH2_INTROSPECT_URL, value); break;
-                               case "cm": rv.put(Config.AAF_URL_CM, value); break;
-                               case "gui": rv.put(Config.AAF_URL_GUI, value); break;
-                               case "fs": rv.put(Config.AAF_URL_FS, value); break;
-                               case "hello": rv.put(Config.AAF_URL_HELLO, value); break;
+                               case "aaf":   tag = Config.AAF_URL; break;
+                               case "locate":tag = Config.AAF_LOCATE_URL; break;
+                               case "oauth": tag = Config.AAF_URL_OAUTH; break;
+                               case "token": tag = Config.AAF_OAUTH2_TOKEN_URL; append="/token"; break;
+                               case "introspect": tag = Config.AAF_OAUTH2_INTROSPECT_URL; append="/introspect"; break;
+                               case "cm":    tag = Config.AAF_URL_CM; break;
+                               case "gui":   tag = Config.AAF_URL_GUI; break;
+                               case "fs":    tag = Config.AAF_URL_FS; break;
+                               case "hello": tag = Config.AAF_URL_HELLO; break;
                                default:
-                               rv.put("aaf_url_" + u, value);
+                                       tag = "aaf_url_" + u;
+                       }
+                       String value;
+                       if((value=access.getProperty(tag,null))==null) {
+                               String proto = "fs".equals(u)?"http://":"https://";
+                               String lhost;
+                               if("locate".equals(u)) {
+                                       lhost=rph.default_fqdn;
+                               } else {
+                                       lhost=Config.AAF_LOCATE_URL_TAG;
+                               }
+                               value = rph.replacements(AGENT_LOAD_URLS,
+                                               proto + lhost + "/%CNS.%AAF_NS." + ("aaf".equals(u)?"service":u) + ':' + version, 
+                                               null,dot_le);
+                               if(append!=null) {
+                                       value+=append;
+                               }
+                       } else {
+                               value = rph.replacements(AGENT_LOAD_URLS, value,null,dot_le);
                        }
+                       rv.put(tag, value);
                };
                aaf_urls = rv;
                }
@@ -379,6 +393,9 @@ public class Agent {
     private static String fqi(Deque<String> cmds) {
         if (cmds.size()<1) {
             String alias = env.getProperty(Config.CADI_ALIAS);
+            if(alias==null) {
+               alias = env.getProperty(Config.AAF_APPID);
+            }
             return alias!=null?alias:AAFSSO.cons.readLine("AppID: ");
         }
         return cmds.removeFirst();    
@@ -825,9 +842,12 @@ public class Agent {
             
             app.add(Config.AAF_LOCATE_URL, Config.getAAFLocateUrl(propAccess));
             app.add(Config.AAF_ENV,propAccess, "DEV");
-            String release = propAccess.getProperty(Config.AAF_RELEASE);
+            String release = propAccess.getProperty(Config.AAF_DEPLOYED_VERSION);
+            if(release==null) {
+               release = System.getProperty(Config.AAF_DEPLOYED_VERSION,null);
+            }
             if(release!=null) {
-               app.add(Config.AAF_RELEASE, release);
+               app.add(Config.AAF_DEPLOYED_VERSION, release);
             }
             for(Entry<Object, Object> aaf_loc_prop : propAccess.getProperties().entrySet()) {
                String key = aaf_loc_prop.getKey().toString();
@@ -910,26 +930,15 @@ public class Agent {
                 } else {
                     aafcon = aafcon(propAccess);
                     if (aafcon!=null) { // get Properties from Remote AAF
-                        final String locator = getProperty(propAccess,aafcon.env,false,Config.AAF_LOCATE_URL,"AAF Locator URL: ");
-
-                        Future<Configuration> acf = aafcon.client(new SingleEndpointLocator(locator))
-                                .read("/configure/"+fqi+"/aaf", configDF);
-                        if (acf.get(TIMEOUT)) {
-                            for (Props props : acf.value.getProps()) {
-                               PropHolder ph = CRED_TAGS.contains(props.getTag())?cred:app;
-                               if(props.getTag().endsWith("_password")) {
-                                       ph.addEnc(props.getTag(), props.getValue());
-                               } else {
-                                       ph.add(props.getTag(), props.getValue());
-                               }
-                            }
-                        } else if (acf.code()==401){
-                            trans.error().log("Bad Password sent to AAF");
-                        } else if (acf.code()==404){
-                            trans.error().log("This version of AAF does not support remote Properties");
-                        } else {
-                            trans.error().log(errMsg.toMsg(acf));
+                        for (Props props : aafProps(trans,aafcon,getProperty(propAccess,aafcon.env,false,Config.AAF_LOCATE_URL,"AAF Locator URL: "),fqi)) {
+                               PropHolder ph = CRED_TAGS.contains(props.getTag())?cred:app;
+                               if(props.getTag().endsWith("_password")) {
+                                       ph.addEnc(props.getTag(), props.getValue());
+                               } else {
+                                       ph.add(props.getTag(), props.getValue());
+                               }
                         }
+
                     }
                 }
             }
@@ -940,6 +949,20 @@ public class Agent {
         }
     }
 
+    public static List<Props> aafProps(Trans trans, AAFCon<?> aafcon, String locator, String fqi) throws CadiException, APIException, URISyntaxException {
+       Future<Configuration> acf = aafcon.client(new SingleEndpointLocator(locator))
+                .read("/configure/"+fqi+"/aaf", configDF);
+        if (acf.get(TIMEOUT)) {
+               return acf.value.getProps();
+        } else if (acf.code()==401){
+            trans.error().log("Bad Password sent to AAF");
+        } else if (acf.code()==404){
+            trans.error().log("This version of AAF does not support remote Properties");
+        } else {
+            trans.error().log(errMsg.toMsg(acf));
+        }
+        return new ArrayList<>();
+    }
 
     private static void validate(final PropAccess pa) throws LocatorException, CadiException, APIException {
         System.out.println("Validating Configuration...");
index 7256af4..67b3df0 100644 (file)
@@ -66,17 +66,26 @@ public class PlaceArtifactInKeystore extends ArtifactDir {
             X509Certificate x509;
             List<X509Certificate> chainList = new ArrayList<>();
             Set<X509Certificate> caSet = new HashSet<>();
+            X509Certificate curr = null;
             for (Certificate c : certColl) {
                 x509 = (X509Certificate)c;
                 // Is a Root (self-signed, anyway)
                 if (x509.getSubjectDN().equals(x509.getIssuerDN())) {
                     caSet.add(x509);
                 } else {
-                    chainList.add(x509);
+                       // Expect Certs in Trust Chain Order. 
+                       if(curr==null) {
+                        chainList.add(x509);
+                        curr=x509;
+                       } else {
+                       // Only Add Cert next on the list
+                               if(curr.getIssuerDN().equals(x509.getSubjectDN())) {
+                                       chainList.add(x509);
+                                       curr=x509;
+                               }
+                       }
                 }
             }
-//            chainList.addAll(caSet);
-            //Collections.reverse(chainList);
 
             // Properties, etc
             // Add CADI Keyfile Entry to Properties
index b0c3294..14cf0f6 100644 (file)
@@ -29,6 +29,8 @@ import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.NoSuchAlgorithmException;
 import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.regex.Pattern;
 
@@ -55,6 +57,7 @@ import aafoauth.v2_0.Token;
 
 public class TokenClientFactory extends Persist<Token,TimedToken> {
     private static TokenClientFactory instance;
+    private final Set<String> alts;
     private Map<String,AAFConHttp> aafcons = new ConcurrentHashMap<>();
     private SecurityInfoC<HttpURLConnection> hsi;
     // Package on purpose
@@ -62,14 +65,26 @@ public class TokenClientFactory extends Persist<Token,TimedToken> {
 
     private TokenClientFactory(Access pa) throws APIException, GeneralSecurityException, IOException, CadiException {
         super(pa, new RosettaEnv(pa.getProperties()),Token.class,"outgoing");
+        
         Map<String, String> aaf_urls = Agent.loadURLs(pa);
+        alts = new TreeSet<>();
+        
         if (access.getProperty(Config.AAF_OAUTH2_TOKEN_URL,null)==null) {
             access.getProperties().put(Config.AAF_OAUTH2_TOKEN_URL, aaf_urls.get(Config.AAF_OAUTH2_TOKEN_URL)); // Default to AAF
         }
+        
         if (access.getProperty(Config.AAF_OAUTH2_INTROSPECT_URL,null)==null) {
             access.getProperties().put(Config.AAF_OAUTH2_INTROSPECT_URL, aaf_urls.get(Config.AAF_OAUTH2_INTROSPECT_URL)); // Default to AAF);
         }
-
+        
+        for(String tag : new String[] {Config.AAF_ALT_OAUTH2_TOKEN_URL, Config.AAF_ALT_OAUTH2_INTROSPECT_URL}) {
+               String value = access.getProperty(tag, null);
+               if(value!=null) {
+                       alts.add(tag);
+                       alts.add(value);
+               }
+        }
+        
         symm = Symm.encrypt.obtain();
         hsi = SecurityInfoC.instance(access, HttpURLConnection.class);
     }
@@ -105,15 +120,11 @@ public class TokenClientFactory extends Persist<Token,TimedToken> {
             }
         }
         char okind;
-        if ( Config.AAF_OAUTH2_TOKEN_URL.equals(tagOrURL) ||
-            Config.AAF_OAUTH2_INTROSPECT_URL.equals(tagOrURL) ||
-            tagOrURL.equals(access.getProperty(Config.AAF_OAUTH2_TOKEN_URL, null)) ||
-            tagOrURL.equals(access.getProperty(Config.AAF_OAUTH2_INTROSPECT_URL, null))
-            ) {
-                okind = Kind.AAF_OAUTH;
-            } else {
-                okind = Kind.OAUTH;
-            }
+        if (alts.contains(tagOrURL)) {
+               okind = Kind.OAUTH;
+        } else {
+            okind = Kind.AAF_OAUTH;
+        }
         TokenClient tci = new TokenClient(
                 okind,
                 this,
index 8c2cc82..4ae8ba5 100644 (file)
@@ -84,7 +84,7 @@ public class OBasicHttpTaf extends AbsOTafLur implements HttpTaf {
      */
     public TafResp validate(Taf.LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
         // See if Request implements BasicCred (aka CadiWrap or other), and if User/Pass has already been set separately
-        final String user;
+        String user = "invalid";
         String password=null;
         byte[] cred=null;
         if (req instanceof BasicCred) {
@@ -106,18 +106,18 @@ public class OBasicHttpTaf extends AbsOTafLur implements HttpTaf {
                     } else {
                         access.printf(Level.AUDIT,"Malformed BasicAuth entry ip=%s, entry=%s",req.getRemoteAddr(),
                                 access.encrypt(temp));
-                        return new BasicHttpTafResp(access,null,"Malformed BasicAuth entry",RESP.FAIL,resp,realm,false);
+                        return new BasicHttpTafResp(access,user,"Malformed BasicAuth entry",RESP.FAIL,resp,realm,false);
                     }
                     if (!rbac.validate(user,Type.PASSWORD,password.getBytes(),req)) {
-                        return new BasicHttpTafResp(access,null,buildMsg(null,req,"user/pass combo invalid for ",user,"from",req.getRemoteAddr()), 
+                        return new BasicHttpTafResp(access,user,buildMsg(null,req,"user/pass combo invalid for ",user,"from",req.getRemoteAddr()), 
                                 RESP.TRY_AUTHENTICATING,resp,realm,true);
                     }
                 } catch (IOException e) {
                     access.log(e, ERROR_GETTING_TOKEN_CLIENT);
-                    return new BasicHttpTafResp(access,null,ERROR_GETTING_TOKEN_CLIENT,RESP.FAIL,resp,realm,false);
+                    return new BasicHttpTafResp(access,user,ERROR_GETTING_TOKEN_CLIENT,RESP.FAIL,resp,realm,false);
                 }
             } else {
-                return new BasicHttpTafResp(access,null,"Not a Basic Auth",RESP.TRY_ANOTHER_TAF,resp,realm,false);
+                return new BasicHttpTafResp(access,user,"Not a Basic Auth",RESP.TRY_ANOTHER_TAF,resp,realm,false);
             }
         }
 
@@ -135,25 +135,25 @@ public class OBasicHttpTaf extends AbsOTafLur implements HttpTaf {
                 Result<TimedToken> rtt = pclient.content.getToken('B',scope);
                 if (rtt.isOK()) {
                     if (rtt.value.expired()) {
-                        return new BasicHttpTafResp(access,null,"BasicAuth/OAuth Token: Token Expired",RESP.FAIL,resp,realm,true);
+                        return new BasicHttpTafResp(access,user,"BasicAuth/OAuth Token: Token Expired",RESP.FAIL,resp,realm,true);
                     } else {
                         TimedToken tt = rtt.value;
                         Result<OAuth2Principal> prin = tkMgr.toPrincipal(tt.getAccessToken(), cred);
                         if (prin.isOK()) {
                             return new BasicHttpTafResp(access,prin.value,"BasicAuth/OAuth Token Authentication",RESP.IS_AUTHENTICATED,resp,realm,true);
                         } else {
-                            return new BasicHttpTafResp(access,null,"BasicAuth/OAuth Token: " + prin.code + ' ' + prin.error,RESP.FAIL,resp,realm,true);
+                            return new BasicHttpTafResp(access,user,"BasicAuth/OAuth Token: " + prin.code + ' ' + prin.error,RESP.FAIL,resp,realm,true);
                         }
                     }
                 } else {
-                    return new BasicHttpTafResp(access,null,"BasicAuth/OAuth Token: " + rtt.code + ' ' + rtt.error,RESP.FAIL,resp,realm,true);
+                    return new BasicHttpTafResp(access,user,"BasicAuth/OAuth Token: " + rtt.code + ' ' + rtt.error,RESP.FAIL,resp,realm,true);
                 }
             } finally {
                 pclient.done();
             }                
         } catch (APIException | CadiException | LocatorException | NoSuchAlgorithmException e) {
             access.log(e, ERROR_GETTING_TOKEN_CLIENT);
-            return new BasicHttpTafResp(access,null,ERROR_GETTING_TOKEN_CLIENT,RESP.TRY_ANOTHER_TAF,resp,realm,false);
+            return new BasicHttpTafResp(access,user,ERROR_GETTING_TOKEN_CLIENT,RESP.TRY_ANOTHER_TAF,resp,realm,false);
         }
     }
     
index cbf0339..8b879e4 100644 (file)
@@ -90,10 +90,11 @@ public class RegistrationCreator {
                                }
                                if(specificVersion!=null) {
                                        String split[] = Split.splitTrim('.', specificVersion);
-                                       locate.setPkg(split.length>3?Integer.parseInt(split[3]):0);
-                                       locate.setPatch(split.length>2?Integer.parseInt(split[2]):0);
-                                       locate.setMinor(split.length>1?Integer.parseInt(split[1]):0);
-                                       locate.setMajor(split.length>0?Integer.parseInt(split[0]):0);
+                                       String deply[]= Split.splitTrim('.', access.getProperty(Config.AAF_DEPLOYED_VERSION, ""));
+                                       locate.setMajor(best(split,deply,0));
+                                       locate.setMinor(best(split,deply,1));
+                                       locate.setPatch(best(split,deply,2));
+                                       locate.setPkg(best(split,deply,3));
                                }
 
                                String protocol = access.getProperty(Config.AAF_LOCATOR_PROTOCOL + dot_le, defProtocol);
@@ -131,7 +132,39 @@ public class RegistrationCreator {
        return me;
     }
        
-    private StringBuilder print(StringBuilder sb, List<MgmtEndpoint> lme) {
+    /*
+     * Find the best version between Actual Interface and Deployed version
+     */
+    private int best(String[] split, String[] deploy, int i) {
+       StringBuilder sb = new StringBuilder();
+       char c;
+               String s;
+       if(split.length>i) {
+               s=split[i];
+                       for(int j=0;j<s.length();++j) {
+                               if(Character.isDigit(c=s.charAt(j))) {
+                                       sb.append(c);
+                               } else {
+                                       break;
+                               }
+                       }
+       }       
+               
+               if(sb.length()==0 && deploy.length>i) {
+                       s=deploy[i];
+                       for(int j=0;j<s.length();++j) {
+                               if(Character.isDigit(c=s.charAt(j))) {
+                                       sb.append(c);
+                               } else {
+                                       break;
+                               }
+                       }
+               }
+               
+               return sb.length()==0?0:Integer.parseInt(sb.toString());
+    }
+
+       private StringBuilder print(StringBuilder sb, List<MgmtEndpoint> lme) {
        int cnt = 0;
                for(MgmtEndpoint m : lme) {
                        print(sb,cnt++,m);
@@ -155,9 +188,9 @@ public class RegistrationCreator {
                out.append('.');
                out.append(mep.getMinor());
                out.append('.');
-               out.append(mep.getPkg());
-               out.append('.');
                out.append(mep.getPatch());
+               out.append('.');
+               out.append(mep.getPkg());
                out.append("\n\tPort:       ");
                out.append(mep.getPort());
                out.append("\n\tProtocol:   ");
@@ -201,8 +234,8 @@ public class RegistrationCreator {
                out.setLongitude(mep.getLongitude());
                out.setMajor(mep.getMajor());
                out.setMinor(mep.getMinor());
-               out.setPkg(mep.getPkg());
                out.setPatch(mep.getPatch());
+               out.setPkg(mep.getPkg());
                out.setPort(mep.getPort());
                out.setProtocol(mep.getProtocol());
                out.getSpecialPorts().addAll(mep.getSpecialPorts());
index 10acc88..de31e66 100644 (file)
@@ -29,6 +29,7 @@ import java.io.InputStream;
 import java.io.PrintStream;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map.Entry;
@@ -36,14 +37,24 @@ import java.util.Properties;
 
 import org.onap.aaf.cadi.Access.Level;
 import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.LocatorException;
 import org.onap.aaf.cadi.PropAccess;
 import org.onap.aaf.cadi.Symm;
 import org.onap.aaf.cadi.aaf.Defaults;
+import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
+import org.onap.aaf.cadi.client.Future;
 import org.onap.aaf.cadi.config.Config;
 import org.onap.aaf.cadi.configure.ArtifactDir;
+import org.onap.aaf.cadi.locator.SingleEndpointLocator;
 import org.onap.aaf.cadi.util.MyConsole;
 import org.onap.aaf.cadi.util.SubStandardConsole;
 import org.onap.aaf.cadi.util.TheConsole;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.rosetta.env.RosettaDF;
+import org.onap.aaf.misc.rosetta.env.RosettaEnv;
+
+import locate.v1_1.Configuration;
+import locate.v1_1.Configuration.Props;
 
 public class AAFSSO {
     public static final MyConsole  cons = TheConsole.implemented() ? new TheConsole() : new SubStandardConsole();
@@ -179,16 +190,20 @@ public class AAFSSO {
                 appID=null;
             }
             
+            String aaf_container_ns = "";
             if (appID!=null) {
-               diskprops.setProperty(Config.AAF_APPID,appID);
                if( access.getProperty(Config.AAF_APPPASS)==null) {
-                       char[] password = cons.readPassword("Password for %s: ", appID);
+                       appID = user = cons.readLine("Deployer ID [%s]: ", user);
+                       access.setProperty(Config.AAF_APPID,appID);
+                       char[] password = cons.readPassword("Password for %s: ", user);
                        if(password.length>0) {
                                String app_pass = access.encrypt(new String(password));
                                access.setProperty(Config.AAF_APPPASS,app_pass);
                                diskprops.setProperty(Config.AAF_APPPASS,app_pass);
                        }
+                       aaf_container_ns = cons.readLine("Container Namespace (blank if none)? [\"\"]: ", aaf_container_ns);
                }
+               diskprops.setProperty(Config.AAF_APPID,appID);
             }
             
             String keystore=access.getProperty(Config.CADI_KEYSTORE);
@@ -298,36 +313,6 @@ public class AAFSSO {
                 err.append("-D" + Config.AAF_APPPASS + "=<passwd> ");
             }
             
-            String locateUrl = Config.getAAFLocateUrl(access);
-            if (locateUrl==null) {
-                locateUrl=AAFSSO.cons.readLine("AAF Locator URL=https://");
-                if (locateUrl==null || locateUrl.length()==0) {
-                    err = new StringBuilder(Config.AAF_LOCATE_URL);
-                    err.append(" is required.");
-                    ok = false;
-                    return;
-                } else {
-                    locateUrl="https://"+locateUrl;
-                }
-                access.setProperty(Config.AAF_LOCATE_URL, locateUrl);
-                addProp(Config.AAF_LOCATE_URL, locateUrl);
-            }
-            
-            final String apiVersion = access.getProperty(Config.AAF_API_VERSION, Config.AAF_DEFAULT_API_VERSION);
-            final String aaf_root_ns = access.getProperty(Config.AAF_ROOT_NS);
-            String locateRoot;
-            if(aaf_root_ns==null) {
-               locateRoot=Defaults.AAF_ROOT;
-            } else {
-               locateRoot = Defaults.AAF_LOCATE_CONST + "/%CNS." + aaf_root_ns;
-            }
-            if(access.getProperty(Config.AAF_URL)==null) {
-               
-               access.setProperty(Config.AAF_URL, locateRoot+".service:"+apiVersion);
-            }
-            if(access.getProperty(Config.AAF_URL_CM)==null) {
-               access.setProperty(Config.AAF_URL_CM, locateRoot+".cm:"+apiVersion);
-            }
             String cadiLatitude = access.getProperty(Config.CADI_LATITUDE);
             if (cadiLatitude==null) {
                 System.out.println("# If you do not know your Global Coordinates, we suggest bing.com/maps");
@@ -381,6 +366,55 @@ public class AAFSSO {
             }
             ok = err==null;
         }
+        String locateUrl = Config.getAAFLocateUrl(access);
+        if (locateUrl==null) {
+            locateUrl=AAFSSO.cons.readLine("AAF Locator URL=https://");
+            if (locateUrl==null || locateUrl.length()==0) {
+                err = new StringBuilder(Config.AAF_LOCATE_URL);
+                err.append(" is required.");
+                ok = false;
+                return;
+            } else {
+                locateUrl="https://"+locateUrl;
+            }
+            access.setProperty(Config.AAF_LOCATE_URL, locateUrl);
+            addProp(Config.AAF_LOCATE_URL, locateUrl);
+            try {
+               if(access.getProperty(Config.AAF_URL)==null) {
+                       access.setProperty(Config.AAF_URL, "https://AAF_LOCATE/AAF_NS.service:2.1");
+               }
+                               AAFCon<?> aafCon = AAFCon.newInstance(access);
+                       Future<Configuration> acf;
+                               RosettaDF<Configuration> configDF = new RosettaEnv().newDataFactory(Configuration.class);
+                               acf = aafCon.client(new SingleEndpointLocator(locateUrl))
+                                       .read("/configure/"+user+"/aaf", configDF);
+                       if (acf.get(aafCon.connTimeout)) {
+                               for(Props p : acf.value.getProps()) {
+                                       addProp(p.getTag(),p.getValue());
+                                       if(access.getProperty(p.getTag())==null) {
+                                               access.setProperty(p.getTag(), p.getValue());
+                                       }
+                               }
+                       } else {
+                               access.log(Level.INFO,acf.body());
+                       }
+                       } catch (LocatorException | APIException | URISyntaxException e) {
+                               access.log(e);
+                       }
+        }
+        
+        final String apiVersion = access.getProperty(Config.AAF_API_VERSION, Config.AAF_DEFAULT_API_VERSION);
+        final String aaf_root_ns = access.getProperty(Config.AAF_ROOT_NS);
+        String locateRoot;
+        if(aaf_root_ns==null) {
+               locateRoot=Defaults.AAF_ROOT;
+        } else {
+               locateRoot = Defaults.AAF_LOCATE_CONST + "/%CNS." + aaf_root_ns;
+        }
+        if(access.getProperty(Config.AAF_URL)==null) {
+               access.setProperty(Config.AAF_URL, locateRoot+".service:"+apiVersion);
+        }
+
         writeFiles();
     }
 
index 41b519b..962397c 100644 (file)
@@ -87,7 +87,7 @@ public class JU_AAFAuthn {
                        Future<String> futureObj = Mockito.mock(Future.class);
                        Mockito.doReturn(futureObj).when(rcliObj).read( "/authn/basicAuth","text/plain");
                        realm = authnObj.validate("test", "test","test");
-                       assertTrue(realm.contains("User/Pass combo invalid"));
+                       assertTrue(realm.contains("user/pass combo invalid"));
                } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
index ee0b719..d086290 100644 (file)
@@ -23,7 +23,7 @@
 AFT_LATITUDE=32.780140
 AFT_LONGITUDE=-96.800451
 AFT_ENVIRONMENT=AFTUAT
-DEPLOYED_VERSION=2.0.MITHRIL
+aaf_deployed_version=2.0.MITHRIL
 cadi_prop_files=/opt/app/aaf/common/com.att.aaf.props
 
 #cadi_keystore=/Volumes/Data/src/authz/common/cadiaaf.jks
index d6b8d56..fac6a3f 100644 (file)
@@ -42,7 +42,11 @@ import org.onap.aaf.cadi.util.Split;
 
 public class PropAccess implements Access {
     // Sonar says cannot be static... it's ok.  not too many PropAccesses created.
-    private final SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+    private final SimpleDateFormat iso8601 = newISO8601();
+               
+    public static SimpleDateFormat newISO8601() {
+       return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+    }
 
     public static final Level DEFAULT = Level.AUDIT;
     
@@ -101,7 +105,7 @@ public class PropAccess implements Access {
         init(nprops);
     }
     
-    protected void init(Properties p) {
+    protected synchronized void init(Properties p) {
         // Make sure these two are set before any changes in Logging
         name = "cadi";
         level=DEFAULT.maskOf();
@@ -258,10 +262,13 @@ public class PropAccess implements Access {
         }
     }
 
-    protected StringBuilder buildMsg(Level level, Object[] elements) {
+    public StringBuilder buildMsg(Level level, Object[] elements) {
         return buildMsg(name,iso8601,level,elements);
     }
-
+    
+    /*
+     * Need to pass in DateFormat per thread, because not marked as thread safe
+     */
     public static StringBuilder buildMsg(final String name, final DateFormat sdf, Level level, Object[] elements) {
        final StringBuilder sb;
         int end = elements.length;
index 66fbe84..2655b4c 100644 (file)
@@ -157,6 +157,7 @@ public class Config {
     public static final String AAF_LOCATE_URL = "aaf_locate_url"; //URL for AAF locator
     public static final String AAF_LOCATE_URL_TAG = "AAF_LOCATE_URL"; // Name of Above for use in Config Variables.
     public static final String AAF_DEFAULT_API_VERSION = "2.1";
+    public static final String AAF_DEPLOYED_VERSION="aaf_deployed_version";
     public static final String AAF_API_VERSION = "aaf_api_version";
     public static final String AAF_URL = "aaf_url"; //URL for AAF... Use to trigger AAF configuration   
     public static final String AAF_LOCATOR_CLASS = "aaf_locator_class";
@@ -219,8 +220,8 @@ public class Config {
     public static final String AAF_CERT_IDS = "aaf_cert_ids";
     public static final String AAF_DEBUG_IDS = "aaf_debug_ids"; // comma delimited
     public static final String AAF_DATA_DIR = "aaf_data_dir"; // AAF processes and Components only.
-    public static final String AAF_RELEASE = "aaf_release";
 
+    public static final String AAF_URL_OAUTH = "aaf_url_oauth";
     public static final String AAF_URL_GUI="aaf_url_gui";
     public static final String AAF_URL_FS="aaf_url_fs";
     public static final String AAF_URL_CM = "aaf_url_cm";
@@ -564,7 +565,7 @@ public class Config {
             }
             access.log(Level.INIT, sb);
 
-            Locator<URI> locator = loadLocator(si, logProp(rph, Config.getAAFLocateUrl(access), null));
+            Locator<URI> locator = loadLocator(si, aafURL);
             
             taf = new HttpEpiTaf(access,locator, tc, htarray); // ok to pass locator == null
             String level = logProp(access, CADI_LOGLEVEL, null);
@@ -849,6 +850,36 @@ public class Config {
         if (_url==null) {
             access.log(Level.INIT,"No URL passed to 'loadLocator'. Disabled");
         } else {
+               try {
+                       Class<?> aalCls = Class.forName("org.onap.aaf.cadi.aaf.v2_0.AbsAAFLocator");
+                       Method aalMth = aalCls.getMethod("create", String.class,String.class);
+                       int colon = _url.lastIndexOf(':');
+                       if(colon>=0) {
+                               int slash = _url.indexOf('/',colon);
+                               String version;
+                               if(slash<0) {
+                                       version = _url.substring(colon+1);
+                               } else {
+                                       version = _url.substring(colon+1,slash);
+                               }
+                               slash = _url.lastIndexOf('/',colon);
+                               if(slash>=0) {
+                                       Object aal = aalMth.invoke(null/*static*/, _url.substring(slash+1, colon),version);
+                                       return (Locator<URI>)aal;
+                               }
+                       }
+               } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+                       String msg;
+                       char quote;
+                       if(e.getCause()!=null) {
+                               msg=e.getCause().getMessage();
+                               quote='"';
+                       } else {
+                               msg = "-";
+                               quote=' ';
+                       }
+                       access.printf(Level.DEBUG, "Configured AbsAAFLocator not found%c%s%cContinuing Locator creation ",quote,msg,quote);
+               }
 //            String url = _url.replace("/AAF_NS.", "/%C%CID%AAF_NS.");
 //            String root_ns = access.getProperty(Config.AAF_ROOT_NS, null);
                String url;
@@ -877,7 +908,7 @@ public class Config {
                     Method meth = lcls.getMethod("create",Access.class,String.class);
                     locator = (Locator<URI>)meth.invoke(null,access,url);
                 } catch (Exception e) {
-                    access.log(Level.TRACE, "(Not fatal) Cannot load by create(String)", e);
+                    access.log(Level.NONE, "(Not fatal) Cannot load by create(String)", e);
                 }
                 if (locator==null) {
                     URI locatorURI = new URI(url);
index 50f17e8..2a8760f 100644 (file)
@@ -263,9 +263,10 @@ public class RegistrationPropHolder {
                if(value.indexOf("%NS")>=0) {
                        str = getNS(dot_le);
                        if(str==null || str.isEmpty()) {
-                               value = value.replace("%NS"+'.', str);
+                               value = value.replace("%NS"+'.', "");
+                       } else {
+                               value = value.replace("%NS", str);
                        }
-                       value = value.replace("%NS", str);
                }
 
                // aaf_root_ns
index 285c45e..5d1d23f 100644 (file)
@@ -91,12 +91,6 @@ public class SecurityInfo {
             this.access = access;
             // reuse DME2 Properties for convenience if specific Properties don't exist
             
-            msgHelp = String.format(INITIALIZING_ERR_FMT,"Keystore", access.getProperty(Config.CADI_KEYSTORE, ""));
-            initializeKeyManager();
-            
-            msgHelp = String.format(INITIALIZING_ERR_FMT,"Truststore", access.getProperty(Config.CADI_TRUSTSTORE, ""));
-            initializeTrustManager();
-            
             String str = access.getProperty(Config.CADI_ALIAS, null);
             if(str==null || str.isEmpty()) {
                defaultAlias = null;
@@ -113,7 +107,14 @@ public class SecurityInfo {
             } else {
                defaultClientAlias = str;
             }
+
+            msgHelp = String.format(INITIALIZING_ERR_FMT,"Keystore", access.getProperty(Config.CADI_KEYSTORE, ""));
+            initializeKeyManager();
             
+            msgHelp = String.format(INITIALIZING_ERR_FMT,"Truststore", access.getProperty(Config.CADI_TRUSTSTORE, ""));
+            initializeTrustManager();
+            
+
             msgHelp = String.format(INITIALIZING_ERR_FMT,"Trustmasks", access.getProperty(Config.CADI_TRUST_MASKS, ""));
             initializeTrustMasks();
 
@@ -239,13 +240,51 @@ public class SecurityInfo {
                 }
             }
         }
+        
+        StringBuilder sb = null;
         for (KeyManager keyManager : keyManagerFactory.getKeyManagers()) {
             if (keyManager instanceof X509KeyManager) {
-                keyManagers.add((X509KeyManager)keyManager);
+               X509KeyManager xkm = (X509KeyManager)keyManager;
+                keyManagers.add(xkm);
+                if(defaultAlias!=null) {
+                       sb=new StringBuilder("X509 Chain\n");
+                       x509Info(sb,xkm.getCertificateChain(defaultAlias));
+                }
+                if(defaultClientAlias!=null && !defaultClientAlias.equals(defaultAlias)) {
+                       if(sb==null) {
+                               sb = new StringBuilder();
+                       } else {
+                               sb.append('\n');
+                       }
+                       sb.append("X509 Client Chain\n");
+                       x509Info(sb,xkm.getCertificateChain(defaultAlias));
+                }
             }
         }
         x509KeyManager = new X509KeyManager[keyManagers.size()];
         keyManagers.toArray(x509KeyManager);
+        
+        if(sb!=null) {
+               access.log(Level.INIT, sb);
+        }
+    }
+    
+    private void x509Info(StringBuilder sb, X509Certificate[] chain) {
+       if(chain!=null) {
+               int i=0;
+               for(X509Certificate x : chain) {
+                       sb.append("  ");
+                       sb.append(i++);
+                       sb.append(')');
+                       sb.append("\n    Subject: ");
+                       sb.append(x.getSubjectDN());
+                       sb.append("\n    Issuer : ");
+                       sb.append(x.getIssuerDN());
+                       sb.append("\n    Expires: ");
+                       sb.append(x.getNotAfter());
+                       sb.append('\n');
+               }
+       }
     }
 
     protected void initializeTrustManager() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException, CadiException {
index bab758e..5920a26 100644 (file)
@@ -55,7 +55,13 @@ import org.onap.aaf.cadi.util.UserChainManip;
  *
  */
 public class CadiHTTPManip {
-    private static final String ACCESS_CADI_CONTROL = ".access|cadi|control";
+    private static final String ACCESS_DENIED = "Access Denied";
+       private static final String NO_TAF_WILL_AUTHORIZE = "No TAF will authorize";
+       private static final String AUTHENTICATION_FAILURE = "Authentication Failure";
+       private static final String AUTHENTICATING_VIA_REDIRECTION = "Authenticating via redirection";
+       private static final String MSG_FMT = "user=%s,ip=%s:%d,msg=\"%s: %s\"";
+       private static final String AUTHENTICATED = "Authenticated";
+       private static final String ACCESS_CADI_CONTROL = ".access|cadi|control";
     private static final String METH = "OPTIONS";
     private static final String CADI = "/cadi/";
     private static final String CADI_CACHE_PRINT = "/cadi/cache/print";
@@ -120,40 +126,42 @@ public class CadiHTTPManip {
         TafResp tresp = taf.validate(Taf.LifeForm.LFN, hreq, hresp);
         switch(tresp.isAuthenticated()) {
             case IS_AUTHENTICATED:
-                access.printf(Level.INFO,"Authenticated: %s from %s:%d"
-                        tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());
+                access.printf(Level.DEBUG,MSG_FMT,tresp.getTarget(),hreq.getRemoteAddr()
+                       hreq.getRemotePort(),AUTHENTICATED,tresp.desc());
                 break;
             case TRY_AUTHENTICATING:
                 switch (tresp.authenticate()) {
                     case IS_AUTHENTICATED:
-                        access.printf(Level.INFO,"Authenticated: %s from %s:%d"
-                                tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());
+                       access.printf(Level.DEBUG,MSG_FMT,tresp.getTarget(),hreq.getRemoteAddr()
+                               hreq.getRemotePort(),AUTHENTICATED,tresp.desc());
                         break;
                     case HTTP_REDIRECT_INVOKED:
-                        access.log(Level.INFO,"Authenticating via redirection: ", tresp.desc());
+                       access.printf(Level.DEBUG,MSG_FMT,tresp.getTarget(),hreq.getRemoteAddr(), 
+                               hreq.getRemotePort(),AUTHENTICATING_VIA_REDIRECTION,tresp.desc());
                         break;
                     case NO_FURTHER_PROCESSING:
-                        access.printf(Level.AUDIT,"Authentication Failure: %s from %s:%d"
-                                , tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());
+                        access.printf(Level.AUDIT,MSG_FMT,tresp.getTarget(),hreq.getRemoteAddr(), 
+                               hreq.getRemotePort(),AUTHENTICATION_FAILURE,tresp.desc());
                         hresp.sendError(403, tresp.desc()); // Forbidden
                         break;
 
                     default:
-                        access.printf(Level.AUDIT,"No TAF will authorize for request from %s:%d"
-                                , hreq.getRemoteAddr(), hreq.getRemotePort());
+                       access.printf(Level.AUDIT,MSG_FMT,tresp.getTarget(),hreq.getRemoteAddr(), 
+                               hreq.getRemotePort(),NO_TAF_WILL_AUTHORIZE,tresp.desc());
                         hresp.sendError(403, tresp.desc()); // Forbidden
                 }
                 break;
             case NO_FURTHER_PROCESSING:
-                access.printf(Level.AUDIT,"Authentication Failure: %s from %s:%d"
-                        tresp.desc(), hreq.getRemoteAddr(), hreq.getRemotePort());
-                hresp.sendError(403, "Access Denied"); // FORBIDDEN
+                access.printf(Level.AUDIT,MSG_FMT, tresp.getTarget(),hreq.getRemoteAddr()
+                               hreq.getRemotePort(),NO_TAF_WILL_AUTHORIZE,tresp.desc());
+                hresp.sendError(403, ACCESS_DENIED); // FORBIDDEN
                 break;
             default:
-                access.printf(Level.AUDIT,"No TAF will authorize for request from %s:%d"
-                        , hreq.getRemoteAddr(), hreq.getRemotePort());
-                hresp.sendError(403, "Access Denied"); // FORBIDDEN
+               access.printf(Level.AUDIT,MSG_FMT, tresp.getTarget(),hreq.getRemoteAddr(),
+                               hreq.getRemotePort(),NO_TAF_WILL_AUTHORIZE,tresp.desc());
+                hresp.sendError(403, ACCESS_DENIED); // FORBIDDEN
         }
+        
         return tresp;
     }
     
@@ -193,7 +201,7 @@ public class CadiHTTPManip {
         }
         return true;
     }
-
+    
     public Lur getLur() {
         return lur;
     }
index b3ac094..364a072 100644 (file)
@@ -37,7 +37,9 @@ public abstract class AbsTafResp implements TafResp {
 
     protected final Access access;
     protected final String tafName;
+    // Note: Valid Resp is based on Principal being non-null
     protected final TaggedPrincipal principal;
+    protected final String target;
     protected final String desc;
     private float timing;
 
@@ -58,6 +60,28 @@ public abstract class AbsTafResp implements TafResp {
         this.access = access;
         this.tafName = tafname;
         this.principal = principal;
+        this.target = principal==null?"unknown":principal.getName();
+        this.desc = description;
+    }
+    
+    /**
+     * AbsTafResp
+     * 
+     * Set and hold
+     * Description (for logging)
+     * Principal (as created by derived class)
+     * Access (for access to underlying container, i.e. for Logging, auditing, ClassLoaders, etc)
+     *  
+     * @param access
+     * @param tafname 
+     * @param principal
+     * @param description
+     */
+    public AbsTafResp(Access access, String tafname, String target, String description) {
+        this.access = access;
+        this.tafName = tafname;
+        this.principal = null;
+        this.target = target;
         this.desc = description;
     }
 
@@ -102,7 +126,15 @@ public abstract class AbsTafResp implements TafResp {
         return principal;
     }
 
-    /**
+    /* (non-Javadoc)
+        * @see org.onap.aaf.cadi.taf.TafResp#getTarget()
+        */
+       @Override
+       public String getTarget() {
+               return target;
+       }
+       
+       /**
      * getAccess()
      * 
      * Get the Access object from the TAF, so that appropriate Logging, etc can be coordinated.
index a5ce45b..d64fbe0 100644 (file)
@@ -37,7 +37,7 @@ public class LoginPageTafResp extends AbsTafResp {
     private final String loginPageURL;
 
     private LoginPageTafResp(Access access, final HttpServletResponse resp, String loginPageURL) {
-        super(access, "LoginPage", null, "Multiple Possible HTTP Logins available.  Redirecting to Login Choice Page");
+        super(access, "LoginPage","unknown", "Multiple Possible HTTP Logins available.  Redirecting to Login Choice Page");
         httpResp = resp;
         this.loginPageURL = loginPageURL;
     }
index a3c8f5b..fb66ec0 100644 (file)
@@ -60,7 +60,15 @@ class NullTafResp implements TafResp {
         return null;
     }
 
-    public Access getAccess() {
+    /* (non-Javadoc)
+        * @see org.onap.aaf.cadi.taf.TafResp#getTarget()
+        */
+       @Override
+       public String getTarget() {
+               return "unknown";
+       }
+
+       public Access getAccess() {
         return Access.NULL;
     }
 
index e655505..3bc278e 100644 (file)
@@ -63,7 +63,15 @@ public class PuntTafResp implements TafResp {
         return null;
     }
 
-    public Access getAccess() {
+    /* (non-Javadoc)
+        * @see org.onap.aaf.cadi.taf.TafResp#getTarget()
+        */
+       @Override
+       public String getTarget() {
+               return "punt";
+       }
+
+       public Access getAccess() {
         return NullTafResp.singleton().getAccess();
     }
 
index f3afde7..6850a37 100644 (file)
@@ -81,6 +81,11 @@ public interface TafResp {
      * @return
      */
     public TaggedPrincipal getPrincipal();
+    
+    /** Target - when Authentication Fails, need to know what ID was being attempted
+     * @return
+     */
+    public String getTarget();
 
     /**
      * get the Access object which created this object, allowing the responder to appropriate Log, etc
index 6b8adeb..f397cba 100644 (file)
@@ -62,7 +62,15 @@ public class TrustNotTafResp implements TafResp {
         return delegate.getPrincipal();
     }
 
-    @Override
+    /* (non-Javadoc)
+        * @see org.onap.aaf.cadi.taf.TafResp#getTarget()
+        */
+       @Override
+       public String getTarget() {
+               return delegate.getTarget();
+       }
+
+       @Override
     public Access getAccess() {
         return delegate.getAccess();
     }
index 91f9f8c..061d4e2 100644 (file)
@@ -64,7 +64,15 @@ public class TrustTafResp implements TafResp {
         return principal;
     }
 
-    @Override
+    /* (non-Javadoc)
+        * @see org.onap.aaf.cadi.taf.TafResp#getTarget()
+        */
+       @Override
+       public String getTarget() {
+               return delegate.getTarget();
+       }
+
+       @Override
     public Access getAccess() {
         return delegate.getAccess();
     }
index d5c8846..dcd27d6 100644 (file)
@@ -120,13 +120,15 @@ public class BasicHttpTaf implements HttpTaf {
                     return new BasicHttpTafResp(access,bp,bp.getName()+" authenticated by password",RESP.IS_AUTHENTICATED,resp,realm,false);
                 } else {
                     //TODO may need timed retries in a given time period
-                    return new BasicHttpTafResp(access,null,buildMsg(bp,req,"user/pass combo invalid for ",bc.getUser(),"from",req.getRemoteAddr()), 
+                    return new BasicHttpTafResp(access,bc.getUser(),buildMsg(bp,req,"user/pass combo invalid for ",bc.getUser(),"from",req.getRemoteAddr()), 
                             RESP.TRY_AUTHENTICATING,resp,realm,true);
                 }
             }
         }
         // Get User/Password from Authorization Header value
         String authz = req.getHeader("Authorization");
+        String target="unknown";
+
         if (authz != null && authz.startsWith("Basic ")) {
             if (warn&&!req.isSecure()) {
                 access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");
@@ -136,6 +138,7 @@ public class BasicHttpTaf implements HttpTaf {
             }
             try {
                 CachedBasicPrincipal ba = new CachedBasicPrincipal(this,authz,realm,timeToLive);
+                target=ba.getName();
                 if (DenialOfServiceTaf.isDeniedID(ba.getName())!=null) {
                     return DenialOfServiceTaf.respDenyID(access,ba.getName());
                 }
@@ -152,16 +155,16 @@ public class BasicHttpTaf implements HttpTaf {
                     return new BasicHttpTafResp(access,ba, ba.getName()+" authenticated by BasicAuth password",RESP.IS_AUTHENTICATED,resp,realm,false);
                 } else {
                     //TODO may need timed retries in a given time period
-                    return new BasicHttpTafResp(access,null,buildMsg(ba,req,"user/pass combo invalid"), 
+                    return new BasicHttpTafResp(access,target,buildMsg(ba,req,"user/pass combo invalid"), 
                             RESP.TRY_AUTHENTICATING,resp,realm,true);
                 }
             } catch (IOException e) {
                 String msg = buildMsg(null,req,"Failed HTTP Basic Authorization (", e.getMessage(), ')');
                 access.log(Level.INFO,msg);
-                return new BasicHttpTafResp(access,null,msg, RESP.TRY_AUTHENTICATING, resp, realm,true);
+                return new BasicHttpTafResp(access,target,msg, RESP.TRY_AUTHENTICATING, resp, realm,true);
             }
         }
-        return new BasicHttpTafResp(access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,realm,false);
+        return new BasicHttpTafResp(access,target,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,realm,false);
     }
     
     protected String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {
index d1acf5f..e217449 100644 (file)
@@ -45,6 +45,14 @@ public class BasicHttpTafResp extends AbsTafResp implements TafResp {
         this.wasFailed = wasFailed;
     }
 
+    public BasicHttpTafResp(Access access, String target, String description, RESP status, HttpServletResponse resp, String realm, boolean wasFailed) {
+        super(access, tafName, target, description);
+        httpResp = resp;
+        this.realm = realm;
+        this.status = status;
+        this.wasFailed = wasFailed;
+    }
+
     public RESP authenticate() throws IOException {
         httpResp.setStatus(401); // Unauthorized    
         httpResp.setHeader("WWW-Authenticate", "Basic realm=\""+realm+'"');
index fca99a3..5f5ff57 100644 (file)
@@ -266,6 +266,7 @@ public class X509Taf implements HttpTaf {
     
                 // if Principal is found, check for "AS_USER" and whether this entity is trusted to declare
                 if (prin!=null) {
+                       // Note: Tag for Certs is Fingerprint, but that takes computation... leaving off
                     return new X509HttpTafResp(
                         access,
                         prin,
index 2fcd155..2215a6f 100644 (file)
@@ -32,7 +32,7 @@ public class DenialOfServiceTafResp extends AbsTafResp  {
     private RESP ect;  // Homage to Arethra Franklin
 
     public DenialOfServiceTafResp(Access access, RESP resp, String description ) {
-        super(access, tafName, null, description);
+        super(access, tafName, "dos", description);
         ect = resp;
     }
 
index bf5a15f..4dba8ed 100644 (file)
@@ -73,7 +73,7 @@ public class JU_AbsTafResp {
         assertThat(tafResp.getAccess(), is(access));
         assertThat(tafResp.isFailedAttempt(), is(false));
 
-        tafResp = new AbsTafResp(null, JUNIT, null, null) {
+        tafResp = new AbsTafResp(null, JUNIT, "unknown", null) {
             @Override public RESP authenticate() throws IOException {
                 return null;
             }
@@ -82,6 +82,7 @@ public class JU_AbsTafResp {
         assertThat(tafResp.isValid(), is(false));
         assertThat(tafResp.isAuthenticated(), is(RESP.TRY_ANOTHER_TAF));
         assertThat(tafResp.getPrincipal(), is(nullValue()));
+        assertThat(tafResp.getTarget(), is("unknown"));
         assertThat(tafResp.getAccess(), is(nullValue()));
         assertThat(tafResp.taf(), is(JUNIT));
         assertThat(tafResp.isFailedAttempt(), is(false));
index 08602cb..8e10389 100644 (file)
@@ -76,6 +76,7 @@ public class JU_EpiTaf {
         @Override public RESP isAuthenticated() { return RESP.TRY_ANOTHER_TAF; } 
         @Override public RESP authenticate() throws IOException { return null; } 
         @Override public TaggedPrincipal getPrincipal() { return null; } 
+        @Override public String getTarget() {return "unknown";}
         @Override public Access getAccess() { return null; } 
         @Override public boolean isFailedAttempt() { return false; }
         @Override public float timing() { return 0; }
@@ -93,6 +94,7 @@ public class JU_EpiTaf {
         @Override public RESP isAuthenticated() { return RESP.TRY_AUTHENTICATING; } 
         @Override public RESP authenticate() throws IOException { return null; } 
         @Override public TaggedPrincipal getPrincipal() { return null; } 
+        @Override public String getTarget() {return "unknown";}
         @Override public Access getAccess() { return null; } 
         @Override public boolean isFailedAttempt() { return false; } 
         @Override public float timing() { return 0; }
diff --git a/docs/sections/installation/AAF_6_running.rst b/docs/sections/installation/AAF_6_running.rst
new file mode 100644 (file)
index 0000000..a57da6d
--- /dev/null
@@ -0,0 +1,54 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+
+Running AAF
+=========================
+
+The default methodology for running AAF for ONAP is to run as on of the ONAP OOM charts.  This allows AAF to be starting in the right order, be available, etc for ONAP Components. 
+
+AAF is very effective as Standalone Java processes, Docker or non OOM Helm Charts, because AAF is an infrastructure component used by ONAP.  It is not an integral ONAP Component, 
+which means that it can be run independently in a number way.  From someone's home computer to the extreme Scale and Resilency requirements of Class A Enterprises.
+
+OOM
+---
+
+Please see OOM Documentation to run AAF with other ONAP Components
+
+Helm
+----
+
+Use git to pull down "authz" code set.  Build if desired.
+
+       - Ensure Docker and K8s is install (Minikube is very useful for local machines, see internet)
+       - Ensure Helm is installed an configured (see internet)
+       - cd authz/auth/helm
+       - helm --namespace onap -n dublin install aaf
+               - Control with kubectl (see K8S/Minikub docs)
+        
+       - A sample App that generates all its certificates and configurations automatically is available as "aaf-hello
+       - helm --namespace onap -n hello install aaf-hello
+
+Docker
+------
+
+Use git to pull down "authz" code set. See Build info for Docker.
+
+       - cd authz/auth/docker
+       - if you need Docker Container, cd ../cass/docker
+               - bash dinstall.sh  
+                       - (note: if you add the word "publish", cqlsh is available for your local apps at port 9042)
+
+               - bash dcqlsh.sh    (puts you into CQLSH inside Docker)
+                       - docker container exec -it aaf-cass  bash -c "cqlsh -k authz --request-timeout=60"
+               - bash dbash.sh     (short cut to get you a Shell in the "cass" container)
+       
+       - all the d...sh scripts utilize short-cut names.  
+               - "cass" is actually aaf-cass in Docker, "service" is actually aaf-service in Docker
+
+       - dbuild.sh      (builds new Docker Containers, see Build)
+       - dclean.sh      (cleans out Docker Containers, getting ready for a new build)
+       - drun.sh <blank|shortcut name>       (Creates and Starts Container for all or one AAF components)
+        - dstop.sh <blank|shortcut name>      (Stops Container for all or one AAF Components)
+       - dstart.sh <blank|shortcut name>     (Use when container exists for all or one AAF Components)
index 4e6fcbd..a6b4806 100644 (file)
@@ -2,11 +2,10 @@
 .. http://creativecommons.org/licenses/by/4.0
 .. Copyright © 2017 AT&T Intellectual Property. All rights reserved.
 
-
 Release Notes
 =============
 
-Version: 2.1.13 (Dublin, 3.1.0-ONAP)
+Version: 2.1.13 (Dublin, 4.0.0-ONAP)
 ---------------------------------------
 
 :Release Date: 2019-06-06
@@ -38,6 +37,15 @@ Note: In general, Infrastructure must be accomplished in the release PRIOR to ge
        - `AAF-785 <https://jira.onap.org/browse/AAF-785>`_ non STAGING version on master
        - `AAF-822 <https://jira.onap.org/browse/AAF-822>`_ Startup issues with K8S, Certs
 
+**Usage Notes**
+       - AAF Core and SMS elements have consistently started from scratch. The one case where this didn't happen for SMS, 
+               it was found that incompatible data was left in volume.  Removal of old data for SMS (See SMS notes) should resolve
+        - On the same instance, one AAF Core component had a similar scenario.  A simple bounce of aaf-locator resolved.
+       - Existing Cassandra
+               - For each release, AAF maintains the authz/auth/auth-cass/cass_init/init.cql which is used to setup Keyspaces from scratch
+               - Any changes are also done in small CQL files, you MIGHT need authz/auth/auth-cass/cass_init/init2_10.cql for Dublin
+
+
 Version: 2.1.8 (Casablanca, 3.0.0-ONAP, Casablanca Maintenance Release)
 --------------------------------------------------------------------------
 
@@ -130,3 +138,5 @@ Version: 2.1.1 (Beijing, 2.0.0-ONAP)
        - `CII Best Practices Passing Badge information for AAF <https://bestpractices.coreinfrastructure.org/en/projects/2303?criteria_level=0>`_
        - `Project Vulnerability Review Table for AAF <https://wiki.onap.org/pages/viewpage.action?pageId=43385140>`_
 
+
+
index 9a615fb..85aae6f 100644 (file)
@@ -57,14 +57,20 @@ public class LogFileNamer {
      */\r
     public String setAppender(String appender) throws IOException {\r
        File f = new File(String.format(FIRST_FILE_FORMAT_STR, dir, root, appender));\r
+       File lock = new File(f.getAbsoluteFile()+".lock");\r
        if(f.exists()) {\r
-               int i = 0;\r
-               while ((f = new File(String.format(FILE_FORMAT_STR, dir, root, appender, i))).exists()) {\r
-                   ++i;\r
-               }\r
+               if(lock.exists()) {\r
+                       int i = 0;\r
+                       while ((f = new File(String.format(FILE_FORMAT_STR, dir, root, appender, i))).exists() &&\r
+                                  (lock = new File(f.getAbsoluteFile()+".lock")).exists()) {\r
+                           ++i;\r
+                       }\r
+               }\r
        }\r
         \r
         try {\r
+               lock.createNewFile();\r
+               lock.deleteOnExit();\r
                f.createNewFile();\r
         } catch (IOException e) {\r
                throw new IOException("Cannot create file '" + f.getCanonicalPath() + '\'', e);\r