update Approvals from Testing 13/90813/1
authorInstrumental <jonathan.gathman@att.com>
Tue, 2 Jul 2019 21:19:59 +0000 (16:19 -0500)
committerInstrumental <jonathan.gathman@att.com>
Tue, 2 Jul 2019 21:20:03 +0000 (16:20 -0500)
Issue-ID: AAF-857
Change-Id: Ic7780678991f5d3f25f2634d1a8b15cc03f62592
Signed-off-by: Instrumental <jonathan.gathman@att.com>
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/FutureDAO.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/user/Cred.java
auth/auth-core/src/main/java/org/onap/aaf/auth/server/AbsServiceStarter.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/facade/AuthzFacadeImpl.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/mapper/Mapper_2_0.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/client/ErrMessage.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 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 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 f583113..11ba656 100644 (file)
@@ -128,6 +128,7 @@ public abstract class AbsServiceStarter<ENV extends RosettaEnv, TRANS extends Tr
                        _start(service);
                } catch (Exception e) {
                        e.printStackTrace();
+                       shutdown();
                }
        }
 
index 8fc2ad5..37ca509 100644 (file)
@@ -73,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;
@@ -85,6 +86,7 @@ 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;
@@ -113,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;}
     
@@ -1988,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;
                     }
@@ -1997,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);
         }
         
     }
@@ -2300,13 +2306,17 @@ 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
@@ -2317,17 +2327,38 @@ public class AuthzCassServiceImpl    <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DE
             }
             // Get the Namespace
             if (nsd.isOK()) {
-                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;
@@ -2626,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 {
@@ -2644,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);
                 }
@@ -2733,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",
@@ -2795,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;
@@ -2824,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");
         }
@@ -2856,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);
@@ -3014,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",
@@ -3060,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 
  ***********************************/
index 61dbbd9..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);
 
     /**
      * 
index 253f91d..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());
index 7a5d0c1..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;
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();
+    }
 }