Update Fixes from testing 57/94857/3
authorInstrumental <jonathan.gathman@att.com>
Tue, 3 Sep 2019 17:31:32 +0000 (12:31 -0500)
committerInstrumental <jonathan.gathman@att.com>
Tue, 3 Sep 2019 18:04:31 +0000 (13:04 -0500)
Issue-ID: AAF-961
Change-Id: I142e460607bf32a785037fa2360b1c0efc3948b1
Signed-off-by: Instrumental <jonathan.gathman@att.com>
32 files changed:
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatch.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatchLoop.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Cred.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/X509.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cached.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassAccess.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCredDAO.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/FileGetter.java [new file with mode: 0644]
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CredDAO.java
auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java
auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeImpl.java
auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper1_0.java
auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java
auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/Code.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/perm/Rename.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByPerm.java
auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForPermission.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/AuthzTransImpl.java
auth/auth-core/src/main/java/org/onap/aaf/auth/env/NullTrans.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Perms.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Roles.java
auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_User.java
auth/auth-service/src/test/java/org/onap/aaf/auth/service/mapper/JU_Mapper_2_0.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFLocator.java
cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AbsAAFLocator.java
cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/v2_0/test/JU_AbsAAFLocator.java
cadi/aaf/src/test/java/org/onap/aaf/cadi/oauth/test/JU_TzHClient.java
cadi/client/src/main/java/org/onap/aaf/cadi/locator/DNSLocator.java
misc/env/src/test/java/org/onap/aaf/misc/env/impl/JU_Log4JLogTargetTest.java

index b626bae..d62c778 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.aaf.auth.batch.helpers;
 
+import org.onap.aaf.cadi.Access;
 import org.onap.aaf.misc.env.LogTarget;
 
 import com.datastax.driver.core.ResultSet;
@@ -30,12 +31,15 @@ public class CQLBatch {
     private StringBuilder sb;
     private int hasAdded;
     private LogTarget log;
+    private long sleep;
+    private long last;
 
     public CQLBatch(LogTarget log, Session session) {
         this.log = log;
         this.session = session;
         sb = new StringBuilder();
         hasAdded = 0;
+        sleep = 0L;
     }
     public StringBuilder begin() {
         sb.setLength(0);
@@ -56,6 +60,17 @@ public class CQLBatch {
     
     public ResultSet execute() {
         if(end()) {
+            if(sleep>0) {
+                long left = last - System.currentTimeMillis();
+                if(left>0) {
+                    try {
+                        Thread.sleep(left);
+                    } catch (InterruptedException e) {
+                        Access.NULL.log(e); // Keep code check idiocy at bay
+                    }
+                }
+                last = System.currentTimeMillis()+sleep;
+            }
             return session.execute(sb.toString());
         } else {
             return null;
@@ -65,6 +80,17 @@ public class CQLBatch {
     public ResultSet execute(boolean dryRun) {
         ResultSet rv = null;
         if(dryRun) {
+            if(sleep>0) {
+                long left = last - System.currentTimeMillis();
+                if(left>0) {
+                    try {
+                        Thread.sleep(left);
+                    } catch (InterruptedException e) {
+                        Access.NULL.log(e); // Keep code check idiocy at bay
+                    }
+                }
+                last = System.currentTimeMillis()+sleep;
+            }
             end();
         } else {
             rv = execute();
@@ -93,6 +119,10 @@ public class CQLBatch {
         execute(dryRun);
     }
     
+    public void sleep(int j) {
+        sleep = j*1000;
+    }
+    
     public String toString() {
         return sb.toString();
     }
index 2604364..1a1bdf3 100644 (file)
@@ -32,7 +32,7 @@ public class CQLBatchLoop {
     private int batches;
     private final StringBuilder current;
     private boolean showProgress;
-    
+
     public CQLBatchLoop(CQLBatch cb, int max, boolean dryRun) {
         cqlBatch = cb;
         i=0;
index 1f5a1f4..83638cc 100644 (file)
@@ -21,6 +21,7 @@
 
 package org.onap.aaf.auth.batch.helpers;
 
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.GregorianCalendar;
@@ -139,7 +140,7 @@ public class Cred  {
     }
 
     public static void loadOneNS(Trans trans, Session session, String ns,int ... types ) {
-        load(trans, session,"select id, type, expires, other, writetime(cred), tag from authz.cred WHERE ns='" + ns + "';");
+        load(trans, session,"select id, type, expires, other, writetime(cred), tag from authz.cred WHERE ns='" + ns + "';", types);
     }
 
     private static void load(Trans trans, Session session, String query, int ...types) {
@@ -315,16 +316,22 @@ public class Cred  {
                 inst.expires.getTime(),inst.tag,reason);
     }
 
-
+    static SimpleDateFormat sdf =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+SSSS");
     public static void batchDelete(StringBuilder sb, List<String> row) {
+        Long l = Long.parseLong(row.get(5));
+        String date = sdf.format(new Date(l));
         sb.append("DELETE from authz.cred WHERE id='");
         sb.append(row.get(1));
         sb.append("' AND type=");
         sb.append(Integer.parseInt(row.get(3)));
         // Note: We have to work with long, because Expires is part of Key... can't easily do date.
-        sb.append(" AND expires=dateof(maxtimeuuid(");
-        sb.append(row.get(5));
-        sb.append("));\n");
+        sb.append(" AND expires='");
+        sb.append(date);
+        sb.append("';\n");
+//        sb.append(" AND expires=dateof(maxtimeuuid(");
+//        sb.append(row.get(5));
+//        sb.append("));\n");
+        
     }
 
     public String toString() {
index c68a994..e2d8694 100644 (file)
@@ -59,10 +59,15 @@ public class X509 {
     
 
     public static void load(Trans trans, Session session, Visitor<X509> visitor) {
-        load(trans,session,"select ca, id, x500, x509, serial from authz.x509;", visitor);
+        load(trans,session, "" , visitor);
     }
+    
+    public static void load(Trans trans, Session session, String where, Visitor<X509> visitor) {
+        load(trans,session, visitor,"select ca, id, x500, x509, serial from authz.x509 " + where +';');
+    }
+
 
-    private static void load(Trans trans, Session session, String query, Visitor<X509> visitor) {
+    private static void load(Trans trans, Session session, Visitor<X509> visitor, String query) {
         trans.info().log( "query: " + query );
         TimeTaken tt = trans.start("Read X509", Env.REMOTE);
        
index 1888b3a..a31e7b5 100644 (file)
@@ -99,7 +99,7 @@ public class Cached<TRANS extends Trans, DATA extends Cacheable> extends Cache<T
         return Result.ok();
     }
 
-    protected interface Getter<D> {
+    public interface Getter<D> {
         public abstract Result<List<D>> get();
     };
     
index cde2611..c5ad459 100644 (file)
@@ -34,6 +34,7 @@ import org.onap.aaf.misc.env.util.Split;
 
 import com.datastax.driver.core.Cluster;
 import com.datastax.driver.core.Cluster.Builder;
+import com.datastax.driver.core.SocketOptions;
 import com.datastax.driver.core.policies.DCAwareRoundRobinPolicy;
 import com.datastax.driver.core.policies.TokenAwarePolicy;
 
@@ -162,6 +163,7 @@ public class CassAccess {
                 env.init().printf("Cassandra is using Default Policy, which is not DC aware");
             }
         }
+        cb.withSocketOptions(new SocketOptions().setReadTimeoutMillis(6500000));
         return cb.build();
     }
     
index 106999d..6bdc22b 100644 (file)
@@ -26,13 +26,61 @@ import java.util.List;
 import org.onap.aaf.auth.dao.CIDAO;
 import org.onap.aaf.auth.dao.CachedDAO;
 import org.onap.aaf.auth.dao.cass.CredDAO;
+import org.onap.aaf.auth.dao.cass.CredDAO.Data;
 import org.onap.aaf.auth.dao.cass.Status;
 import org.onap.aaf.auth.env.AuthzTrans;
 import org.onap.aaf.auth.layer.Result;
 
 public class CachedCredDAO extends CachedDAO<AuthzTrans, CredDAO, CredDAO.Data> {
+    private final ReadID readID;
+    private final ReadID readIDBath;
+    
     public CachedCredDAO(CredDAO dao, CIDAO<AuthzTrans> info, long expiresIn) {
         super(dao, info, CredDAO.CACHE_SEG, expiresIn);
+        if(FileGetter.isLoaded) {
+            readID = new ReadID() {
+                @Override
+                public Result<List<Data>> read(AuthzTrans trans, final String id) {
+                    return FileGetter.singleton(null).getter(id).get();
+                }
+            };
+            // Both are the same... File read in only does BAth
+            readIDBath = readID;
+        } else {
+            readID = new ReadID() {
+                @Override
+                public Result<List<Data>> read(AuthzTrans trans, final String id) {
+                    DAOGetter getter = new DAOGetter(trans,dao()) {
+                        public Result<List<CredDAO.Data>> call() {
+                            return dao().readID(trans, id);
+                        }
+                    };
+                    
+                    Result<List<CredDAO.Data>> lurd = get(trans, id, getter);
+                    if (lurd.isOK() && lurd.isEmpty()) {
+                        return Result.err(Status.ERR_UserNotFound,"No User Cred found");
+                    }
+                    return lurd;
+                }
+            };
+            
+            readIDBath = new ReadID() {
+                @Override
+                public Result<List<Data>> read(AuthzTrans trans, final String id) {
+                     DAOGetter getter = new DAOGetter(trans,dao()) {
+                         public Result<List<CredDAO.Data>> call() {
+                             return dao().readIDBAth(trans, id);
+                         }
+                     };
+                     
+                     Result<List<CredDAO.Data>> lurd = get(trans, id, getter);
+                     if (lurd.isOK() && lurd.isEmpty()) {
+                         return Result.err(Status.ERR_UserNotFound,"No User Cred found");
+                     }
+                     return lurd;
+                }
+            };
+        }
     }
     
     /**
@@ -48,19 +96,16 @@ public class CachedCredDAO extends CachedDAO<AuthzTrans, CredDAO, CredDAO.Data>
         
         return dao().readNS(trans, ns);
     }
-    
+
     public Result<List<CredDAO.Data>> readID(AuthzTrans trans, final String id) {
-        DAOGetter getter = new DAOGetter(trans,dao()) {
-            public Result<List<CredDAO.Data>> call() {
-                return dao().readID(trans, id);
-            }
-        };
-        
-        Result<List<CredDAO.Data>> lurd = get(trans, id, getter);
-        if (lurd.isOK() && lurd.isEmpty()) {
-            return Result.err(Status.ERR_UserNotFound,"No User Cred found");
-        }
-        return lurd;
+        return readID.read(trans, id);
+    }
+
+    public Result<List<Data>> readIDBAth(AuthzTrans trans, String id) {
+        return readIDBath.read(trans,id);
     }
 
+    private interface ReadID {
+        public Result<List<CredDAO.Data>> read(final AuthzTrans trans, final String id);
+    }
 }
diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/FileGetter.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/FileGetter.java
new file mode 100644 (file)
index 0000000..b7a6c59
--- /dev/null
@@ -0,0 +1,149 @@
+/**
+ * ============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.dao.cached;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.onap.aaf.auth.dao.Cached.Getter;
+import org.onap.aaf.auth.dao.cass.CredDAO;
+import org.onap.aaf.auth.dao.cass.CredDAO.Data;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.Access.Level;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.Hash;
+import org.onap.aaf.cadi.PropAccess;
+import org.onap.aaf.cadi.util.CSV;
+
+public class FileGetter {
+       private static final String AAF_FILEGETTER = "aaf_filegetter";
+       public static boolean isLoaded = false;
+       private static FileGetter singleton;
+
+       private Map<String,List<CredDAO.Data>> data; 
+       private SimpleDateFormat sdf;
+       private FileGetter(Access access) {
+               if(access!=null) {
+                       String filename = access.getProperty(AAF_FILEGETTER,null);
+                       if(filename!=null) {
+                               if(!isLoaded) {
+                                       data = new TreeMap<>();
+                                       sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+SSSS");
+                                       CSV csv = new CSV(access, filename).setDelimiter('|');
+                                       try {
+                                               access.log(Level.INIT, "Loading Filebased Cred from",filename);
+                                       csv.visit(row -> {
+                                               if(row.size()<1) {
+                                                       access.log(Level.INIT, "Bad Row");
+                                               }
+                                               int type;
+                                                 try {
+                                                         type =Integer.parseInt(row.get(1));
+                                                 } catch(Exception e) {
+                                                         access.log(Level.INIT, e, "skipping ", row.get(0));
+                                                         return;
+                                                 }
+                                               if(CredDAO.CERT_SHA256_RSA == type) {
+                                                       return;
+                                               }
+                                               CredDAO.Data cdd = new CredDAO.Data();
+                                               cdd.id=row.get(0);
+                                               cdd.type = type;
+                                               try {
+                                                               cdd.expires = sdf.parse(row.get(2));
+                                                               cdd.cred = ByteBuffer.wrap(Hash.fromHex(row.get(3)));
+                                                               cdd.notes= row.get(4);
+                                                               cdd.ns = row.get(5);
+                                                               cdd.other = Integer.parseInt(row.get(6));
+                                                               if(row.size()>8) {
+                                                                       cdd.tag = row.get(8);
+                                                               } else {
+                                                                       cdd.tag = "";
+                                                               }
+                                                               List<CredDAO.Data> lcdd = data.get(cdd.id);
+                                                               if(lcdd == null) {
+                                                                       lcdd = new ArrayList<>();
+                                                                       data.put(cdd.id, lcdd);
+                                                               }
+                                                               lcdd.add(cdd);
+                                                               
+                                                       } catch (ParseException e) {
+                                                               access.log(Level.INIT, e);
+                                                       }
+                                               
+                                       });
+                                       access.printf(Level.INIT, "Filebased Cred finished...");
+                                               isLoaded = true;
+                                       } catch( CadiException | IOException e) {
+                                               access.log(Level.ERROR, e);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       public static synchronized FileGetter singleton(Access access) {
+               if(singleton==null) {
+                       singleton = new FileGetter(access);
+               }
+               return singleton;
+               
+       }
+       public Getter<CredDAO.Data> getter(String id) {
+               return new FGetter(id);
+       }
+       private static List<CredDAO.Data> EMPTY = new ArrayList<>(); 
+       public class FGetter implements Getter<CredDAO.Data> {
+               private final List<CredDAO.Data> lcdd;  
+               public FGetter(final String id) {
+                       lcdd = data.get(id);
+               }
+               @Override
+               public Result<List<Data>> get() {
+                       return Result.ok(lcdd==null?EMPTY:lcdd);
+               }
+       }
+       
+       public static void main(String[] args) {
+               PropAccess access = new PropAccess(args);
+               access.setProperty(AAF_FILEGETTER,"/Users/jg1555/cred.dat");
+               FileGetter fg = FileGetter.singleton(access);
+               
+               for(String id : new String[] {"m01891@aaf.att.com","bogus"}) {
+                       Getter<CredDAO.Data> g = fg.getter(id);
+                       Result<List<CredDAO.Data>> r = g.get();
+                       if(r.isOKhasData()) {
+                               for(CredDAO.Data cdd : r.value) {
+                                       System.out.println(cdd);
+                               }
+                       }
+               }
+       }
+}
+
index 9a2511d..7140188 100644 (file)
@@ -64,6 +64,7 @@ public class CredDAO extends CassDAOImpl<AuthzTrans,CredDAO.Data> {
     private CIDAO<AuthzTrans> infoDAO;
     private PSInfo psNS;
     private PSInfo psID;
+    private PSInfo psIDBath;
     
     public CredDAO(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException {
         super(trans, CredDAO.class.getSimpleName(),cluster, keyspace, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE));
@@ -219,6 +220,15 @@ public class CredDAO extends CassDAOImpl<AuthzTrans,CredDAO.Data> {
         
         psID = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE +
                 " WHERE id = ?", CredLoader.deflt,readConsistency);
+        
+        // NOTE: (type) in ((1),(2)) is valid for Cass 2.1.14.  After 2.1.14, more obvious
+        // syntax of type in (1,2) is available
+        // ALSO, 1 & 2 STAND FOR BASIC_AUTH (MD5) AND BASIC_AUTH_SHA256(with salt).
+        // If more Basic Auth Protocols become available, add here but do NOT
+        // add X509, and there can be man Certs, and we don't need to read them every time, or
+        // as discovered, or provide CASS Outage due to too many Certs to read.
+        psIDBath = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE +
+                " WHERE id = ? and (type) in ((1),(2))", CredLoader.deflt,readConsistency);
     }
     
     /* (non-Javadoc)
@@ -245,6 +255,10 @@ public class CredDAO extends CassDAOImpl<AuthzTrans,CredDAO.Data> {
         return psID.read(trans, R_TEXT, new Object[]{id});
     }
     
+    public Result<List<Data>> readIDBAth(AuthzTrans trans, String id) {
+        return psIDBath.read(trans, R_TEXT, new Object[] {id});
+    }
+
     /**
      * Log Modification statements to History
      *
index b797ca0..dddf3b5 100644 (file)
@@ -31,7 +31,6 @@ import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Random;
 import java.util.Set;
 import java.util.TreeSet;
 
@@ -45,6 +44,7 @@ import org.onap.aaf.auth.dao.cached.CachedNSDAO;
 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.cached.FileGetter;
 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
 import org.onap.aaf.auth.dao.cass.CacheInfoDAO;
 import org.onap.aaf.auth.dao.cass.CertDAO;
@@ -124,7 +124,7 @@ public class Question {
     static Slot PERMS;
 
     private static Set<String> specialLog = null;
-    public static final Random random = new SecureRandom();
+    public static final SecureRandom random = new SecureRandom();
     private static long traceID = random.nextLong();
     private static Slot specialLogSlot = null;
     private static Slot transIDSlot = null;
@@ -202,6 +202,8 @@ public class Question {
         permDAO = new CachedPermDAO(new PermDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn);
         roleDAO = new CachedRoleDAO(new RoleDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn);
         userRoleDAO = new CachedUserRoleDAO(new UserRoleDAO(trans, historyDAO,cacheInfoDAO), cacheInfoDAO, expiresIn);
+        // Create if aaf_file_cred exists with file
+        FileGetter.singleton(trans.env().access());
         credDAO = new CachedCredDAO(new CredDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn);
         certDAO = new CachedCertDAO(new CertDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn);
 
@@ -595,27 +597,35 @@ public class Question {
     public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,NsDAO.Data ndd, Access access) {
         // <ns>.access|:role:<role name>|<read|write>
         String ns = ndd.name;
+        boolean isRoot = ns.startsWith(Define.ROOT_NS());
         int last;
         do {
             if (isGranted(trans, user, ns, ACCESS, ":ns", access.name())) {
                 return Result.ok(ndd);
             }
+            if(isRoot) {
+                break;
+            }
             if ((last = ns.lastIndexOf('.')) >= 0) {
                 ns = ns.substring(0, last);
             }
         } while (last >= 0);
-        // com.att.aaf.ns|:<client ns>:ns|<access>
-        // AAF-724 - Make consistent response for May User", and not take the
-        // last check... too confusing.
-        Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":"    + ndd.name + ":ns", access.name());
-        if (rv.isOK()) {
-            return rv;
-        } else if (rv.status==Result.ERR_Backend) {
-            return Result.err(rv);
-        } else {
-            return Result.err(Status.ERR_Denied, "[%s] may not %s in NS [%s]",
-                    user, access.name(), ndd.name);
-        }
+        
+        // SAFETY - Do not allow these when NS is Root
+        if(!isRoot) {
+            // com.att.aaf.ns|:<client ns>:ns|<access>
+            // AAF-724 - Make consistent response for May User", and not take the
+            // last check... too confusing.
+            Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":"    + ndd.name + ":ns", access.name());
+                if (rv.isOK()) {
+                    return rv;
+                } else if (rv.status==Result.ERR_Backend) {
+                    return Result.err(rv);
+                }
+            }
+        return Result.err(Status.ERR_Denied, "[%s] may not %s in NS [%s]",
+                user, access.name(), ndd.name);
+
     }
 
     public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user, RoleDAO.Data rdd, Access access) {
@@ -630,49 +640,56 @@ public class Question {
     }
 
     public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user, NsDAO.Data ndd, RoleDAO.Data rdd, Access access) {
-        // 1) Is User in the Role?
-        Result<List<UserRoleDAO.Data>> rurd = userRoleDAO.readUserInRole(trans, user, rdd.fullName());
-        if (rurd.isOKhasData()) {
-            return Result.ok(ndd);
+        // 1) For "read", Is User in the Role is enough
+        if(Access.read.equals(access)) {
+            Result<List<UserRoleDAO.Data>> rurd = userRoleDAO.readUserInRole(trans, user, rdd.fullName());
+            if (rurd.isOKhasData()) {
+                return Result.ok(ndd);
+            }
         }
 
         String roleInst = ":role:" + rdd.name;
         // <ns>.access|:role:<role name>|<read|write>
         String ns = rdd.ns;
+        boolean isRoot = ns.startsWith(Define.ROOT_NS());
         int last;
         do {
             if (isGranted(trans, user, ns,ACCESS, roleInst, access.name())) {
                 return Result.ok(ndd);
             }
+            if(isRoot) {
+                break;
+            }
             if ((last = ns.lastIndexOf('.')) >= 0) {
                 ns = ns.substring(0, last);
             }
         } while (last >= 0);
 
-        // Check if Access by Global Role perm
-        // com.att.aaf.ns|:<client ns>:role:name|<access>
-        Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":"
-                + rdd.ns + roleInst, access.name());
-        if (rnsd.isOK()) {
-            return rnsd;
-        } else if (rnsd.status==Result.ERR_Backend) {
-            return Result.err(rnsd);
-        }
+        // SAFETY - Do not allow these when NS is Root
+        if(!isRoot) {
+            // Check if Access by Global Role perm
+            // com.att.aaf.ns|:<client ns>:role:name|<access>
+            Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":"
+                    + rdd.ns + roleInst, access.name());
+            if (rnsd.isOK()) {
+                return rnsd;
+            } else if (rnsd.status==Result.ERR_Backend) {
+                return Result.err(rnsd);
+            }
 
-        // Check if Access to Whole NS
-        // AAF-724 - Make consistent response for May User", and not take the
-        // last check... too confusing.
-        Result<org.onap.aaf.auth.dao.cass.NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, 
-                ":" + rdd.ns + ":ns", access.name());
-        if (rv.isOK()) {
-            return rv;
-        } else if (rnsd.status==Result.ERR_Backend) {
-            return Result.err(rnsd);
-        } else {
-            return Result.err(Status.ERR_Denied, "[%s] may not %s Role [%s]",
-                    user, access.name(), rdd.fullName());
+            // Check if Access to Whole NS
+            // AAF-724 - Make consistent response for May User", and not take the
+            // last check... too confusing.
+            Result<org.onap.aaf.auth.dao.cass.NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, 
+                    ":" + rdd.ns + ":ns", access.name());
+            if (rv.isOK()) {
+                return rv;
+            } else if (rnsd.status==Result.ERR_Backend) {
+                return Result.err(rnsd);
+            }
         }
-
+        return Result.err(Status.ERR_Denied, "[%s] may not %s Role [%s]",
+                    user, access.name(), rdd.fullName());
     }
 
     public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,PermDAO.Data pdd, Access access) {
@@ -695,43 +712,50 @@ public class Question {
     }
 
     public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,NsDAO.Data ndd, PermDAO.Data pdd, Access access) {
+        // Most common occurrence... if granted Permission
         if (isGranted(trans, user, pdd.ns, pdd.type, pdd.instance, pdd.action)) {
             return Result.ok(ndd);
         }
+        
         String permInst = ":perm:" + pdd.type + ':' + pdd.instance + ':' + pdd.action;
         // <ns>.access|:role:<role name>|<read|write>
         String ns = ndd.name;
+        boolean isRoot = ns.startsWith(Define.ROOT_NS());
         int last;
         do {
             if (isGranted(trans, user, ns, ACCESS, permInst, access.name())) {
                 return Result.ok(ndd);
             }
+            if(isRoot) {
+                break;
+            }
             if ((last = ns.lastIndexOf('.')) >= 0) {
                 ns = ns.substring(0, last);
             }
         } while (last >= 0);
 
-        // Check if Access by NS perm
-        // com.att.aaf.ns|:<client ns>:role:name|<access>
-        Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + permInst, access.name());
-        if (rnsd.isOK()) {
-            return rnsd;
-        } else if (rnsd.status==Result.ERR_Backend) {
-            return Result.err(rnsd);
-        }
+        // SAFETY - Do not allow these when NS is Root
+        if(!isRoot) {
+            // Check if Access by NS perm
+            // com.att.aaf.ns|:<client ns>:role:name|<access>
+            Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + permInst, access.name());
+            if (rnsd.isOK()) {
+                return rnsd;
+            } else if (rnsd.status==Result.ERR_Backend) {
+                return Result.err(rnsd);
+            }
 
-        // Check if Access to Whole NS
-        // AAF-724 - Make consistent response for May User", and not take the
-        // last check... too confusing.
-        Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":"    + pdd.ns + ":ns", access.name());
-        if (rv.isOK()) {
-            return rv;
-        } else {
-            return Result.err(Status.ERR_Denied,
-                    "[%s] may not %s Perm [%s|%s|%s]", user, access.name(),
-                    pdd.fullType(), pdd.instance, pdd.action);
+            // Check if Access to Whole NS
+            // AAF-724 - Make consistent response for May User", and not take the
+            // last check... too confusing.
+            Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":"    + pdd.ns + ":ns", access.name());
+            if (rv.isOK()) {
+                return rv;
+            }
         }
-
+        return Result.err(Status.ERR_Denied,
+                "[%s] may not %s Perm [%s|%s|%s]", user, access.name(),
+                pdd.fullType(), pdd.instance, pdd.action);
     }
 
     public Result<Void> mayUser(AuthzTrans trans, DelegateDAO.Data dd, Access access) {
@@ -861,7 +885,7 @@ public class Question {
         Result<List<CredDAO.Data>> result;
         TimeTaken tt = trans.start("Read DB Cred", Env.REMOTE);
         try {
-            result = credDAO.readID(trans, user);
+            result = credDAO.readIDBAth(trans, user);
         } finally {
             tt.done();
         }
index a93b7cb..f381a9e 100644 (file)
@@ -98,6 +98,7 @@ public abstract class FacadeImpl<REQ,CERT,ARTIFACTS,ERROR> extends org.onap.aaf.
     private Mapper<REQ, CERT, ARTIFACTS, ERROR>     mapper;
 //    private Slot sCertAuth;
     private final String voidResp;
+
     public FacadeImpl(AAF_CM certman,
                       CMService service, 
                       Mapper<REQ,CERT,ARTIFACTS,ERROR> mapper, 
index 82639e2..1c95196 100644 (file)
@@ -36,7 +36,6 @@ import org.onap.aaf.auth.dao.cass.ArtiDAO.Data;
 import org.onap.aaf.auth.dao.cass.CertDAO;
 import org.onap.aaf.auth.env.AuthzTrans;
 import org.onap.aaf.auth.layer.Result;
-import org.onap.aaf.cadi.util.FQI;
 import org.onap.aaf.cadi.util.Vars;
 
 import aaf.v2_0.Error;
index 48fe8d8..4788ee4 100644 (file)
@@ -27,10 +27,13 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -44,6 +47,7 @@ import org.onap.aaf.auth.cm.data.CertRenew;
 import org.onap.aaf.auth.cm.data.CertReq;
 import org.onap.aaf.auth.cm.data.CertResp;
 import org.onap.aaf.auth.cm.validation.CertmanValidator;
+import org.onap.aaf.auth.common.Define;
 import org.onap.aaf.auth.dao.CassAccess;
 import org.onap.aaf.auth.dao.cass.ArtiDAO;
 import org.onap.aaf.auth.dao.cass.CacheInfoDAO;
@@ -58,9 +62,9 @@ import org.onap.aaf.auth.layer.Result;
 import org.onap.aaf.auth.org.Organization;
 import org.onap.aaf.auth.org.Organization.Identity;
 import org.onap.aaf.auth.org.OrganizationException;
+import org.onap.aaf.cadi.Access.Level;
 import org.onap.aaf.cadi.Hash;
 import org.onap.aaf.cadi.Permission;
-import org.onap.aaf.cadi.Access.Level;
 import org.onap.aaf.cadi.aaf.AAFPermission;
 import org.onap.aaf.cadi.config.Config;
 import org.onap.aaf.cadi.configure.Factory;
@@ -73,12 +77,16 @@ public class CMService {
     private static final int STD_RENEWAL = 30;
     private static final int MAX_RENEWAL = 60;
     private static final int MIN_RENEWAL = 10;
-
+    // Limit total requests
+    private static final int MAX_X509s = 200; // Need a "LIMIT Exception" DB.
+    private static final String MAX_X509S_TAG = "cm_max_x509s"; // be able to adjust limit in future
+    
     public static final String REQUEST = "request";
     public static final String IGNORE_IPS = "ignoreIPs";
     public static final String RENEW = "renew";
     public static final String DROP = "drop";
     public static final String DOMAIN = "domain";
+    public static final String DYNAMIC_SANS="dynamic_sans";
 
     private static final String CERTMAN = "certman";
     private static final String ACCESS = "access";
@@ -90,7 +98,8 @@ public class CMService {
     private final ArtiDAO artiDAO;
     private AAF_CM certManager;
     private Boolean allowIgnoreIPs;
-    private Boolean alwaysIgnoreIPs;
+    private AAFPermission limitOverridePerm;
+    private int max_509s;
 
     // @SuppressWarnings("unchecked")
     public CMService(final AuthzTrans trans, AAF_CM certman) throws APIException, IOException {
@@ -111,20 +120,21 @@ public class CMService {
                 "*",
                 "read"
         );
-        alwaysIgnoreIPs = Boolean.valueOf(certman.access.getProperty(Config.CM_ALWAYS_IGNORE_IPS, "false"));
-        if(alwaysIgnoreIPs) {
-            trans.env().access().log(Level.INIT, "DNS Evaluation for Cert Creation is turned off with " + Config.CM_ALWAYS_IGNORE_IPS );
-        } else {
-            allowIgnoreIPs = Boolean.valueOf(certman.access.getProperty(Config.CM_ALLOW_IGNORE_IPS, "false"));
-            if(allowIgnoreIPs) {
-                trans.env().access().log(Level.INIT, "Allowing DNS Evaluation to be turned off with <ns>.certman|<ca name>|"+IGNORE_IPS);
-            }
+        try {
+            max_509s = Integer.parseInt(trans.env().getProperty(MAX_X509S_TAG,Integer.toString(MAX_X509s)));
+        } catch (Exception e) {
+            trans.env().log(e, "");
+            max_509s = MAX_X509s;
+        }
+        limitOverridePerm = new AAFPermission(Define.ROOT_NS(),"certman","quantity","override");
+        allowIgnoreIPs = Boolean.valueOf(certman.access.getProperty(Config.CM_ALLOW_IGNORE_IPS, "false"));
+        if(allowIgnoreIPs) {
+            trans.env().access().log(Level.INIT, "Allowing DNS Evaluation to be turned off with <ns>.certman|<ca name>|"+IGNORE_IPS);
         }
     }
 
     public Result<CertResp> requestCert(final AuthzTrans trans, final Result<CertReq> req, final CA ca) {
         if (req.isOK()) {
-
             if (req.value.fqdns.isEmpty()) {
                 return Result.err(Result.ERR_BadData, "No Machines passed in Request");
             }
@@ -138,7 +148,31 @@ public class CMService {
             }
 
             List<String> notes = null;
-            List<String> fqdns = new ArrayList<>(req.value.fqdns);
+            List<String> fqdns;
+            boolean domain_based = false;
+            boolean dynamic_sans = false;
+
+            if(req.value.fqdns.isEmpty()) {
+               fqdns = new ArrayList<>();
+            } else {
+               // Only Template or Dynamic permitted to pass in FQDNs
+               if (req.value.fqdns.get(0).startsWith("*")) { // Domain set
+                    if (trans.fish(new AAFPermission(null,ca.getPermType(), ca.getName(), DOMAIN))) {
+                       domain_based = true;
+                    } else {
+                        return Result.err(Result.ERR_Denied,
+                              "Domain based Authorizations (" + req.value.fqdns.get(0) + ") requires Exception");
+                    }
+               } else {
+                       if(trans.fish(new AAFPermission(null, ca.getPermType(), ca.getName(),DYNAMIC_SANS))) {
+                               dynamic_sans = true;
+                       } else {
+                        return Result.err(Result.ERR_Denied,
+                            "Dynamic SANs for (" + req.value.mechid + ") requires Permission");                                
+                       }
+               }
+               fqdns = new ArrayList<>(req.value.fqdns);
+            }
 
             String email = null;
 
@@ -146,9 +180,7 @@ public class CMService {
                 Organization org = trans.org();
 
                 boolean ignoreIPs;
-                if(alwaysIgnoreIPs) {
-                    ignoreIPs=true;
-                } else if(allowIgnoreIPs) {
+                if(allowIgnoreIPs) {
                     ignoreIPs = trans.fish(new AAFPermission(mechNS,CERTMAN, ca.getName(), IGNORE_IPS));
                 } else {
                     ignoreIPs = false;
@@ -157,33 +189,30 @@ public class CMService {
 
                 InetAddress primary = null;
                 // Organize incoming information to get to appropriate Artifact
-                if (!fqdns.isEmpty()) {
+                if (!fqdns.isEmpty()) { // Passed in FQDNS, validated above
                     // Accept domain wild cards, but turn into real machines
                     // Need *domain.com:real.machine.domain.com:san.machine.domain.com:...
-                    if (fqdns.get(0).startsWith("*")) { // Domain set
-                        if (!trans.fish(new AAFPermission(null,ca.getPermType(), ca.getName(), DOMAIN))) {
-                            return Result.err(Result.ERR_Denied,
-                                    "Domain based Authorizations (" + fqdns.get(0) + ") requires Exception");
-                        }
-
+                    if (domain_based) { // Domain set
                         // check for Permission in Add Artifact?
-                        String domain = fqdns.get(0).substring(1);
+                        String domain = fqdns.get(0).substring(1); // starts with *, see above
                         fqdns.remove(0);
                         if (fqdns.isEmpty()) {
-                            return Result.err(Result.ERR_Denied, "Requests using domain require machine declaration");
+                            return Result.err(Result.ERR_Denied, 
+                               "Requests using domain require machine declaration");
                         }
 
                         if (!ignoreIPs) {
                             InetAddress ia = InetAddress.getByName(fqdns.get(0));
                             if (ia == null) {
                                 return Result.err(Result.ERR_Denied,
-                                        "Request not made from matching IP matching domain");
+                                     "Request not made from matching IP matching domain");
                             } else if (ia.getHostName().endsWith(domain)) {
                                 primary = ia;
                             }
                         }
 
                     } else {
+                       // Passed in FQDNs, but not starting with *
                         if (!ignoreIPs) {
                             for (String cn : req.value.fqdns) {
                                 try {
@@ -211,7 +240,7 @@ public class CMService {
                 if (ignoreIPs) {
                     host = req.value.fqdns.get(0);
                 } else if (primary == null) {
-                    return Result.err(Result.ERR_Denied, "Request not made from matching IP (%s)", trans.ip());
+                    return Result.err(Result.ERR_Denied, "Request not made from matching IP (%s)", req.value.fqdns.get(0));
                 } else {
                     String thost = primary.getHostName();
                     host = thost==null?primary.getHostAddress():thost;
@@ -220,35 +249,42 @@ public class CMService {
                 ArtiDAO.Data add = null;
                 Result<List<ArtiDAO.Data>> ra = artiDAO.read(trans, req.value.mechid, host);
                 if (ra.isOKhasData()) {
-                    if (add == null) {
-                        add = ra.value.get(0); // single key
+                    add = ra.value.get(0); // single key
+                    if(dynamic_sans && (add.sans!=null && !add.sans.isEmpty())) { // do not allow both Dynamic and Artifact SANS
+                        return Result.err(Result.ERR_Denied,"Authorization must not include SANS when doing Dynamic SANS (%s, %s)", req.value.mechid, key);
                     }
                 } else {
-                    ra = artiDAO.read(trans, req.value.mechid, key);
-                    if (ra.isOKhasData()) { // is the Template available?
-                        add = ra.value.get(0);
-                        add.machine = host;
-                        for (String s : fqdns) {
-                            if (!s.equals(add.machine)) {
-                                add.sans(true).add(s);
-                            }
-                        }
-                        Result<ArtiDAO.Data> rc = artiDAO.create(trans, add); // Create new Artifact from Template
-                        if (rc.notOK()) {
-                            return Result.err(rc);
-                        }
-                    } else {
-                        add = ra.value.get(0);
-                    }
+                       if(domain_based) {
+                           ra = artiDAO.read(trans, req.value.mechid, key);
+                           if (ra.isOKhasData()) { // is the Template available?
+                               add = ra.value.get(0);
+                               add.machine = host;
+                               for (String s : fqdns) {
+                                   if (!s.equals(add.machine)) {
+                                       add.sans(true).add(s);
+                                   }
+                               }
+                               Result<ArtiDAO.Data> rc = artiDAO.create(trans, add); // Create new Artifact from Template
+                               if (rc.notOK()) {
+                                   return Result.err(rc);
+                               }
+                           } else {
+                               return Result.err(Result.ERR_Denied,"No Authorization Template for %s, %s", req.value.mechid, key);
+                           }
+                       } else {
+                        return Result.err(Result.ERR_Denied,"No Authorization found for %s, %s", req.value.mechid, key);
+                       }
                 }
 
                 // Add Artifact listed FQDNs
-                if (add.sans != null) {
-                    for (String s : add.sans) {
-                        if (!fqdns.contains(s)) {
-                            fqdns.add(s);
-                        }
-                    }
+                if(!dynamic_sans) {
+                       if (add.sans != null) {
+                           for (String s : add.sans) {
+                               if (!fqdns.contains(s)) {
+                                   fqdns.add(s);
+                               }
+                           }
+                       }
                 }
 
                 // Policy 2: If Config marked as Expired, do not create or renew
@@ -318,6 +354,31 @@ public class CMService {
             try {
                 csrMeta = BCFactory.createCSRMeta(ca, req.value.mechid, email, fqdns);
                 csrMeta.environment(ca.getEnv());
+                
+                // Before creating, make sure they don't have too many
+                if(!trans.fish(limitOverridePerm)) {
+                    Result<List<CertDAO.Data>> existing = certDAO.readID(trans, req.value.mechid);
+                    if(existing.isOK()) {
+                        String cn = "CN=" + csrMeta.cn();
+                        int count = 0;
+                        Date now = new Date();
+                        for (CertDAO.Data cdd : existing.value) {
+                            Collection<? extends Certificate> certs = Factory.toX509Certificate(cdd.x509);
+                            for(Iterator<? extends Certificate> iter = certs.iterator(); iter.hasNext();) {
+                                X509Certificate x509 = (X509Certificate)iter.next();
+                                if(x509.getNotAfter().after(now) && x509.getSubjectDN().getName().contains(cn)) {
+                                    if(++count>MAX_X509s) {
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                        if(count>max_509s) {
+                            return Result.err(Result.ERR_Denied, "There are too many Certificates generated for " + cn + " for " + req.value.mechid);
+                        }
+                    }
+                }
+                // Here is where we send off to CA for Signing.
                 X509andChain x509ac = ca.sign(trans, csrMeta);
                 if (x509ac == null) {
                     return Result.err(Result.ERR_ActionNotCompleted, "x509 Certificate not signed by CA");
@@ -331,6 +392,7 @@ public class CMService {
                 cdd.id = req.value.mechid;
                 cdd.x500 = x509.getSubjectDN().getName();
                 cdd.x509 = Factory.toString(trans, x509);
+                
                 certDAO.create(trans, cdd);
 
                 CredDAO.Data crdd = new CredDAO.Data();
@@ -340,7 +402,7 @@ public class CMService {
                 crdd.id = req.value.mechid;
                 crdd.ns = Question.domain2ns(crdd.id);
                 crdd.type = CredDAO.CERT_SHA256_RSA;
-                crdd.tag = cdd.serial.toString(16);
+                crdd.tag = cdd.ca + '|' + cdd.serial.toString();
                 credDAO.create(trans, crdd);
 
                 CertResp cr = new CertResp(trans, ca, x509, csrMeta, x509ac.getTrustChain(), compileNotes(notes));
@@ -716,4 +778,4 @@ public class CMService {
         byte[] hash = Hash.hashSHA256(bb.array());
         return ByteBuffer.wrap(hash);
     }
-}
\ No newline at end of file
+}
index a6663ad..fdf2447 100644 (file)
@@ -29,7 +29,7 @@ import org.onap.aaf.auth.rserv.HttpCode;
 public abstract class Code extends HttpCode<AuthzTrans,Facade1_0> implements Cloneable {
 
     public Code(AAF_CM cma, String description, String ... roles) {
-        super(cma.facade1_0, description, roles);
+        super(AAF_CM.facade1_0, description, roles);
         // Note, the first "Code" will be created with default Facade, "JSON".
         // use clone for another Code with XML
     }
index 4cd628e..6ca37c3 100644 (file)
@@ -250,7 +250,13 @@ public class AAFcli {
                     pw.println("Press <Return> to continue...");
                     ++idx;
                     // Sonar insists we do something with the string, though it's only a pause.  Not very helpful...
-                    String sonar = new BufferedReader(new InputStreamReader(System.in)).readLine();
+                    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+                    String sonar;
+                    try {
+                        sonar = br.readLine();
+                    } finally {
+                        br.close();
+                    }
                     sonar=""; // this useless code brought to you by Sonar.
                     pw.print(sonar);
                     continue;
@@ -569,12 +575,16 @@ public class AAFcli {
                                 }
                             } else if (rdr != null) {
                                 BufferedReader br = new BufferedReader(rdr);
-                                String line;
-                                while ((line = br.readLine()) != null) {
-                                    if (!aafcli.eval(line) && exitOnFailure) {
-                                        rv = 1;
-                                        break;
+                                try {
+                                    String line;
+                                    while ((line = br.readLine()) != null) {
+                                        if (!aafcli.eval(line) && exitOnFailure) {
+                                            rv = 1;
+                                            break;
+                                        }
                                     }
+                                } finally {
+                                    br.close();
                                 }
                             } else { // just run the command line
                                 aafcli.verbose(false);
index dbadd8a..5a7b5de 100644 (file)
@@ -22,6 +22,9 @@
 package org.onap.aaf.auth.cmd.perm;
 
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
 import org.onap.aaf.auth.cmd.AAFcli;
 import org.onap.aaf.auth.cmd.Cmd;
 import org.onap.aaf.auth.cmd.Param;
@@ -31,6 +34,7 @@ import org.onap.aaf.cadi.LocatorException;
 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 aaf.v2_0.PermRequest;
@@ -65,24 +69,31 @@ public class Rename extends Cmd {
                 
                 // Set Start/End commands
                 setStartEnd(pr);
-                Future<PermRequest> fp = client.update(
-                        "/authz/perm/"+origType+"/"+origInstance+"/"+origAction,
-                        getDF(PermRequest.class),
-                        pr
-                        );
-                int rv;
-                if (fp.get(AAFcli.timeout())) {
-                    rv = fp.code();
-                    pw().println("Updated Permission");
-                } else {
-                    rv = fp.code();
-                    if (rv==202) {
-                        pw().println("Permission Update Accepted, but requires Approvals before actualizing");
+                try {
+                    Future<PermRequest> fp = client.update(
+                            "/authz/perm/"+
+                            origType+ '/' +
+                            URLEncoder.encode(origInstance,Config.UTF_8) + '/' +
+                            origAction,
+                            getDF(PermRequest.class),
+                            pr
+                            );
+                    int rv;
+                    if (fp.get(AAFcli.timeout())) {
+                        rv = fp.code();
+                        pw().println("Updated Permission");
                     } else {
-                        error(fp);
+                        rv = fp.code();
+                        if (rv==202) {
+                            pw().println("Permission Update Accepted, but requires Approvals before actualizing");
+                        } else {
+                            error(fp);
+                        }
                     }
+                    return rv;
+                } catch (UnsupportedEncodingException e) {
+                    throw new CadiException(e);
                 }
-                return rv;
             }
         });
         
index feb1dec..5d291ac 100644 (file)
@@ -22,6 +22,9 @@
 
 package org.onap.aaf.auth.cmd.role;
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
 import org.onap.aaf.auth.cmd.Cmd;
 import org.onap.aaf.auth.cmd.Param;
 import org.onap.aaf.auth.rserv.HttpMethods;
@@ -29,6 +32,7 @@ import org.onap.aaf.cadi.CadiException;
 import org.onap.aaf.cadi.LocatorException;
 import org.onap.aaf.cadi.client.Future;
 import org.onap.aaf.cadi.client.Rcli;
+import org.onap.aaf.cadi.config.Config;
 import org.onap.aaf.misc.env.APIException;
 
 import aaf.v2_0.Roles;
@@ -51,20 +55,25 @@ public class ListByPerm extends Cmd {
 
     @Override
     public int _exec(int idx0, final String ... args) throws CadiException, APIException, LocatorException {
-            int idx = idx0;
+        int idx = idx0;
         final String type=args[idx];
         final String instance=args[++idx];
-        final String action=args[++idx];
-
+        final String action = args[++idx];
+        
         return same(((List)parent).new ListRoles() {
             @Override
             public Integer code(Rcli<?> client) throws CadiException, APIException {
-
-                Future<Roles> fp = client.read(
-                        "/authz/roles/perm/"+type+'/'+instance+'/'+action, 
-                        getDF(Roles.class)
-                        );
-                return list(fp,client, HEADER+type+'|'+instance+'|'+action);
+                try {
+                    Future<Roles> fp = client.read(
+                            "/authz/roles/perm/"+type+'/' + 
+                                URLEncoder.encode(instance,Config.UTF_8)+'/'+
+                                action, 
+                            getDF(Roles.class)
+                            );
+                    return list(fp,client, HEADER+type+'|'+instance+'|'+action);
+                } catch (UnsupportedEncodingException e) {
+                    throw new CadiException(e);
+                }
             }
         });
     }
index dff3dc5..b40c96c 100644 (file)
@@ -21,6 +21,8 @@
 
 package org.onap.aaf.auth.cmd.user;
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
 import java.util.Collections;
 import java.util.Comparator;
 
@@ -33,6 +35,7 @@ import org.onap.aaf.cadi.LocatorException;
 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 aaf.v2_0.Users;
@@ -63,19 +66,26 @@ public class ListForPermission extends Cmd {
                 if ("\\*".equals(instance))instance="*";
                 String action = args[idx++];
                 if ("\\*".equals(action))action="*";
-                Future<Users> fp = client.read(
-                        "/authz/users/perm/"+type+'/'+instance+'/'+action, 
-                        getDF(Users.class)
-                        );
-                if (fp.get(AAFcli.timeout())) {
-                    if (aafcli.isTest())
-                        Collections.sort(fp.value.getUser(), (Comparator<User>) (u1, u2) -> u1.getId().compareTo(u2.getId()));
-                    ((org.onap.aaf.auth.cmd.user.List)parent).report(fp.value,false,HEADER,type+"|"+instance+"|"+action);
-                    if (fp.code()==404)return 200;
-                } else {
-                    error(fp);
+                try {
+                    Future<Users> fp = client.read(
+                            "/authz/users/perm/" + 
+                                type + '/' +
+                                URLEncoder.encode(instance,Config.UTF_8) + '/' + 
+                                action, 
+                            getDF(Users.class)
+                            );
+                    if (fp.get(AAFcli.timeout())) {
+                        if (aafcli.isTest())
+                            Collections.sort(fp.value.getUser(), (Comparator<User>) (u1, u2) -> u1.getId().compareTo(u2.getId()));
+                        ((org.onap.aaf.auth.cmd.user.List)parent).report(fp.value,false,HEADER,type+"|"+instance+"|"+action);
+                        if (fp.code()==404)return 200;
+                    } else {
+                        error(fp);
+                    }
+                    return fp.code();
+                } catch (UnsupportedEncodingException e) {
+                    throw new CadiException(e);
                 }
-                return fp.code();
             }
         });
     }
index 454d46d..ac16833 100644 (file)
@@ -67,6 +67,8 @@ public interface AuthzTrans extends TransStore {
     public abstract AuthzEnv env();
 
     public abstract void setLur(Lur lur);
+    
+    public abstract Lur getLur();
 
     public abstract boolean fish(Permission ... p);
     
index c68f71a..037ce4e 100644 (file)
@@ -176,6 +176,11 @@ public class AuthzTransImpl extends BasicTrans implements AuthzTrans {
         this.lur = lur;
     }
     
+    @Override
+    public Lur getLur() {
+       return lur;
+    }
+    
     @Override
     public boolean fish(Permission ... pond) {
         if (lur!=null) {
index 9189cc3..df086cd 100644 (file)
@@ -207,6 +207,11 @@ public class NullTrans implements AuthzTrans {
     public void setLur(Lur lur) {
     }
 
+    @Override
+    public Lur getLur() {
+       return null;
+    }
+
     @Override
     public boolean fish(Permission ... p) {
         return false;
index 96c0fc4..0265469 100644 (file)
@@ -309,6 +309,10 @@ public class Page extends HTMLCacheGen {
                                 if(theme==null) {
                                     theme = defaultTheme;
                                 }
+                                List<String> ls = getThemeFiles(trans, theme);
+                                if(ls==null) {
+                                       throw new APIException("Theme " + theme + " does not exist.");
+                                }
                                 Cookie cookie = new Cookie(AAF_GUI_THEME,theme);
                                 cookie.setMaxAge(604_800); // one week
                                 trans.hresp().addCookie(cookie);
index ae94553..04654d4 100644 (file)
@@ -232,8 +232,10 @@ public class API_Perms {
                     HttpServletRequest req,
                     HttpServletResponse resp) throws Exception {
                 
-                Result<Void> r = context.renamePerm(trans, req, resp, pathParam(req, "type"), 
-                        pathParam(req, "instance"), pathParam(req, "action"));
+                Result<Void> r = context.renamePerm(trans, req, resp, 
+                        pathParam(req, "type"), 
+                        URLDecoder.decode(pathParam(req, "instance"),Config.UTF_8), 
+                        pathParam(req, "action"));
                 switch(r.status) {
                     case OK: 
                         resp.setStatus(HttpStatus.OK_200); 
index 2c93bc3..6088dd3 100644 (file)
@@ -27,6 +27,8 @@ import static org.onap.aaf.auth.rserv.HttpMethods.GET;
 import static org.onap.aaf.auth.rserv.HttpMethods.POST;
 import static org.onap.aaf.auth.rserv.HttpMethods.PUT;
 
+import java.net.URLDecoder;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -38,6 +40,7 @@ import org.onap.aaf.auth.service.AAF_Service;
 import org.onap.aaf.auth.service.Code;
 import org.onap.aaf.auth.service.facade.AuthzFacade;
 import org.onap.aaf.auth.service.mapper.Mapper.API;
+import org.onap.aaf.cadi.config.Config;
 
 public class API_Roles {
     public static void init(AAF_Service authzAPI, AuthzFacade facade) throws Exception {
@@ -231,7 +234,7 @@ public class API_Roles {
                 
                 Result<Void> r = context.getRolesByPerm(trans, resp, 
                         pathParam(req, "type"),
-                        pathParam(req, "instance"),
+                        URLDecoder.decode(pathParam(req, "instance"),Config.UTF_8),
                         pathParam(req, "action"));
                 switch(r.status) {
                     case OK: 
index 0ce1dfe..d5ce00c 100644 (file)
@@ -24,6 +24,8 @@ package org.onap.aaf.auth.service.api;
 import static org.onap.aaf.auth.layer.Result.OK;
 import static org.onap.aaf.auth.rserv.HttpMethods.GET;
 
+import java.net.URLDecoder;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -34,6 +36,7 @@ import org.onap.aaf.auth.service.AAF_Service;
 import org.onap.aaf.auth.service.Code;
 import org.onap.aaf.auth.service.facade.AuthzFacade;
 import org.onap.aaf.auth.service.mapper.Mapper.API;
+import org.onap.aaf.cadi.config.Config;
 
 /**
  * User Role APIs
@@ -61,7 +64,7 @@ public class API_User {
 //
                 Result<Void> r = context.getUsersByPermission(trans, resp,
                         pathParam(req, ":type"),
-                        pathParam(req, ":instance"),
+                        URLDecoder.decode(pathParam(req, ":instance"),Config.UTF_8),
                         pathParam(req, ":action"));
                 switch(r.status) {
                     case OK:
index dc580ef..fd664d6 100644 (file)
@@ -40,12 +40,6 @@ import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.onap.aaf.auth.layer.Result.ERR_BadData;
 import static org.onap.aaf.auth.layer.Result.ERR_General;
 
-import aaf.v2_0.Certs;
-import aaf.v2_0.Certs.Cert;
-import aaf.v2_0.History;
-import aaf.v2_0.History.Item;
-import aaf.v2_0.Users;
-import aaf.v2_0.Users.User;
 import java.io.IOException;
 import java.math.BigInteger;
 import java.util.ArrayList;
@@ -61,7 +55,6 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
 
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -92,7 +85,11 @@ import org.onap.aaf.misc.env.APIException;
 import org.onap.aaf.misc.env.Env;
 import org.onap.aaf.misc.env.TimeTaken;
 
+import aaf.v2_0.Certs;
+import aaf.v2_0.Certs.Cert;
 import aaf.v2_0.CredRequest;
+import aaf.v2_0.History;
+import aaf.v2_0.History.Item;
 import aaf.v2_0.NsRequest;
 import aaf.v2_0.Nss;
 import aaf.v2_0.Nss.Ns;
@@ -107,6 +104,8 @@ import aaf.v2_0.Roles;
 import aaf.v2_0.UserRole;
 import aaf.v2_0.UserRoleRequest;
 import aaf.v2_0.UserRoles;
+import aaf.v2_0.Users;
+import aaf.v2_0.Users.User;
 
 @RunWith(MockitoJUnitRunner.class)
 public class JU_Mapper_2_0 {
@@ -665,11 +664,11 @@ public class JU_Mapper_2_0 {
     public void cred_shouldReturnError_whenGivenPasswordDoesNotFulfillPolicy() {
         //given
         String id = "aaf@aaf.osaaf.org";
-        String password = "invalid";
-        given(org.isValidPassword(transaction, id, password)).willReturn("Password does not match org.osaaf Password Standards");
+        String strp = "invalid";
+        given(org.isValidPassword(transaction, id, strp)).willReturn("Password does not match org.osaaf Password Standards");
 
         //when
-        Result<CredDAO.Data> result = mapper.cred(transaction, createCredRequest(id, password), true);
+        Result<CredDAO.Data> result = mapper.cred(transaction, createCredRequest(id, strp), true);
 
         //then
         assertFalse(result.isOK());
@@ -698,13 +697,13 @@ public class JU_Mapper_2_0 {
         //given
         String ns = "org.osaaf.aaf";
         String id = "aaf@aaf.osaaf.org";
-        String password = "SomeValidPassword123!";
+        String strp = "SomeValidPassword123!";
         GregorianCalendar expiration = new GregorianCalendar();
         given(org.expiration(isA(GregorianCalendar.class), eq(Expiration.Password), eq(id))).willReturn(expiration);
-        given(org.isValidPassword(transaction, id, password)).willReturn("");
+        given(org.isValidPassword(transaction, id, strp)).willReturn("");
 
         //when
-        Result<CredDAO.Data> result = mapper.cred(transaction, createCredRequest(id, password), true);
+        Result<CredDAO.Data> result = mapper.cred(transaction, createCredRequest(id, strp), true);
 
         //then
         assertTrue(result.isOK());
@@ -939,6 +938,7 @@ public class JU_Mapper_2_0 {
      *
      */
     public static class ImmutableMap {
+        @SuppressWarnings("unchecked")
         public static <T,U> Map<T,U> of(Object ... tag_value) {
             Map<T,U> rv = new HashMap<>();
             for(int i=0;i<tag_value.length-1;i+=2) {
@@ -970,7 +970,7 @@ public class JU_Mapper_2_0 {
      *
      */
     public static class Lists {
-        @SuppressWarnings("unchecked")
+        @SafeVarargs
         public static <T> List<T> newArrayList(Collection<T> ... init ) {
             List<T> rv = new ArrayList<>();
             for(Collection<T> o : init) {
index ed24b1e..a993109 100644 (file)
@@ -29,6 +29,7 @@ import java.util.LinkedList;
 import java.util.List;
 
 import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.Access.Level;
 import org.onap.aaf.cadi.CadiException;
 import org.onap.aaf.cadi.LocatorException;
 import org.onap.aaf.cadi.SecuritySetter;
@@ -36,6 +37,7 @@ import org.onap.aaf.cadi.client.Future;
 import org.onap.aaf.cadi.config.Config;
 import org.onap.aaf.cadi.config.SecurityInfoC;
 import org.onap.aaf.cadi.http.HClient;
+import org.onap.aaf.cadi.locator.DNSLocator;
 import org.onap.aaf.cadi.util.FixURIinfo;
 import org.onap.aaf.cadi.util.Split;
 import org.onap.aaf.misc.env.APIException;
@@ -49,8 +51,12 @@ import locate.v1_0.Endpoints;
 
 public class AAFLocator extends AbsAAFLocator<BasicTrans>  {
     private static RosettaEnv env;
-    HClient client;
+    private HClient client;
+    private HClient lclient;
     private RosettaDF<Endpoints> epsDF;
+    private DNSLocator locatorLocator;
+    private Item locatorItem;
+
 
     public AAFLocator(SecurityInfoC<HttpURLConnection> si, URI locatorURI) throws LocatorException {
         super(si.access, nameFromLocatorURI(locatorURI), 10000L /* Wait at least 10 seconds between refreshes */);
@@ -73,13 +79,6 @@ public class AAFLocator extends AbsAAFLocator<BasicTrans>  {
                     sb.append(path[i]);
                 }
                 setPathInfo(sb.toString());
-//                URI uri = new URI(
-//                            locatorURI.getScheme(),
-//                            locatorURI.getAuthority(),
-//                            locatorURI.getPath(),
-//                            null,
-//                            null
-//                            );
                 client = createClient(si.defSS, locatorURI, connectTimeout);
             } else {
                 client = new HClient(si.defSS, locatorURI, connectTimeout);
@@ -89,19 +88,72 @@ public class AAFLocator extends AbsAAFLocator<BasicTrans>  {
         } catch (APIException /*| URISyntaxException*/ e) {
             throw new LocatorException(e);
         }
+        lclient = new HClient(si.defSS, locatorURI, connectTimeout);
         
         if(si.access.willLog(Access.Level.DEBUG)) {
             si.access.log(Access.Level.DEBUG, "Root URI:",client.getURI());
         }
+        
+        String dnsString;
+        if(locatorURI.getPort()<0) {
+               dnsString=locatorURI.getScheme() + "://" + locatorURI.getHost();
+        } else {
+               dnsString=locatorURI.getScheme() + "://" +locatorURI.getHost()+':'+locatorURI.getPort();
+        }
+        if(dnsString.contains("null")) { // for Testing Purposes, mostly.
+               locatorLocator = null;
+        } else {
+               locatorLocator = new DNSLocator(access, dnsString);
+               locatorItem = locatorLocator.best();
+        }
+    }
+
+    private URI locatorFail(URI uri) throws LocatorException, URISyntaxException {
+        locatorLocator.invalidate(locatorItem);
+        locatorItem = locatorLocator.best();
+        URI newURI = locatorLocator.get(locatorItem);
+        return new URI(uri.getScheme(),
+                       uri.getUserInfo(),
+                       newURI.getHost(),
+                       newURI.getPort(),
+                       uri.getPath(),
+                       uri.getQuery(),
+                       uri.getFragment());
     }
 
+    protected final int maxIters() {
+        return locatorLocator.size();
+    }
+
+
     @Override
     public boolean refresh() {
         try {
-            client.setMethod("GET");
-            client.send();
-            Future<Endpoints> fr = client.futureRead(epsDF, TYPE.JSON);
-            if (fr.get(client.timeout())) {
+            int max = locatorLocator.size();
+            for(int i=0;i<max;) {
+                ++i;
+                try {
+                    lclient.setMethod("GET");
+                    lclient.send();
+                    break;
+                } catch (APIException connectE) {
+                    Throwable ce = connectE.getCause();
+                    if(ce!=null && ce instanceof java.net.ConnectException && i< maxIters()) {
+                        try {
+                            URI old = client.getURI();
+                            lclient.setURI(locatorFail(old));
+                            access.printf(Level.INFO, "AAF Locator changed from %s to %s",old, lclient.getURI());
+                            continue;
+                        } catch (LocatorException e) {
+                            throw connectE;
+                        }
+                    }
+                    // last one, just throw
+                    throw connectE;
+                }
+            }
+            Future<Endpoints> fr = lclient.futureRead(epsDF, TYPE.JSON);
+            if (fr.get(lclient.timeout())) {
                 List<EP> epl = new LinkedList<>();
                 for (Endpoint endpoint : fr.value.getEndpoint()) {
                     epl.add(new EP(endpoint,latitude,longitude));
index 2fe3ffd..5ef25bc 100644 (file)
@@ -72,6 +72,7 @@ public abstract class AbsAAFLocator<TRANS extends Trans> implements Locator<URI>
         } catch (UnknownHostException | CadiException e1) {
             throw new LocatorException(e1);
         }
+        URI aaf_locator_uri;
         try {
             aaf_locator_host = rph.replacements(getClass().getSimpleName(),"https://"+Config.AAF_LOCATE_URL_TAG,null,null);
             if(aaf_locator_host.endsWith("/locate")) {
@@ -79,7 +80,6 @@ public abstract class AbsAAFLocator<TRANS extends Trans> implements Locator<URI>
             } else {
                 aaf_locator_uri = new URI(aaf_locator_host+"/locate");
             }
-            
             access.printf(Level.INFO, "AbsAAFLocator AAF URI is %s",aaf_locator_uri);
         } catch (URISyntaxException e) {
             throw new LocatorException(e);
@@ -110,9 +110,8 @@ public abstract class AbsAAFLocator<TRANS extends Trans> implements Locator<URI>
             this.name = split[0];
             this.version = (split.length > 1) ? split[1] : access.getProperty(Config.AAF_API_VERSION,Config.AAF_DEFAULT_API_VERSION);
         }
-        
     }
-
+    
     /**
      * This is the way to setup specialized AAFLocators ahead of time.
      * @param preload
@@ -368,7 +367,7 @@ public abstract class AbsAAFLocator<TRANS extends Trans> implements Locator<URI>
         }
         return null;
     }
-
+    
     protected static class AAFLItem implements Item {
             private Iterator<EP> iter;
             private URI uri;
index 64e9572..004eed3 100644 (file)
 
 package org.onap.aaf.cadi.aaf.v2_0.test;
 
-import static org.junit.Assert.*;
-import static org.hamcrest.CoreMatchers.*;
-import static org.mockito.Matchers.*;
-import static org.mockito.Mockito.*;
-import org.junit.*;
-import org.mockito.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.net.URI;
 import java.net.URISyntaxException;
 
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.onap.aaf.cadi.Access;
 import org.onap.aaf.cadi.Locator.Item;
 import org.onap.aaf.cadi.LocatorException;
index 11dce82..805b13f 100644 (file)
 
 package org.onap.aaf.cadi.oauth.test;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
-import static org.hamcrest.CoreMatchers.is; 
-import static org.hamcrest.CoreMatchers.nullValue; 
-import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.PrintStream;
@@ -38,7 +39,6 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-
 import org.onap.aaf.cadi.CadiException;
 import org.onap.aaf.cadi.Locator;
 import org.onap.aaf.cadi.Locator.Item;
@@ -46,11 +46,11 @@ import org.onap.aaf.cadi.LocatorException;
 import org.onap.aaf.cadi.PropAccess;
 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.cadi.config.SecurityInfoC;
 import org.onap.aaf.cadi.oauth.TimedToken;
 import org.onap.aaf.cadi.oauth.TzHClient;
 import org.onap.aaf.misc.env.APIException;
-import org.onap.aaf.cadi.config.Config;
-import org.onap.aaf.cadi.config.SecurityInfoC;
 
 public class JU_TzHClient {
     
@@ -72,8 +72,9 @@ public class JU_TzHClient {
         MockitoAnnotations.initMocks(this);
         access = new PropAccess(new PrintStream(new ByteArrayOutputStream()), new String[0]);
         access.setProperty(Config.CADI_LATITUDE, "38.62");  // St Louis approx lat
-        access.setProperty(Config.CADI_LONGITUDE, "90.19");  // St Louis approx lon    }
-        
+        access.setProperty(Config.CADI_LONGITUDE, "90.19");  // St Louis approx long
+       //access.setProperty("tag", "http://aaf.something.com");
+       
         errStream = new ByteArrayOutputStream();
         System.setErr(new PrintStream(errStream));
     }
index 4711aee..d64de69 100644 (file)
@@ -40,6 +40,8 @@ public class DNSLocator implements Locator<URI> {
     private Host[] hosts;
     private int startPort, endPort;
     private String suffix;
+
+    private int size = 1; // initial, until refreshed.
     
     public DNSLocator(Access access, String protocol, String host, String range) {
         this.host = host;
@@ -156,6 +158,7 @@ public class DNSLocator implements Locator<URI> {
                 }
             }
             hosts = temp;
+            size = temp.length * (endPort-startPort+1);
             return true;
         } catch (Exception e) {
             access.log(Level.ERROR, e);
@@ -238,4 +241,8 @@ public class DNSLocator implements Locator<URI> {
     }
     
     public void destroy() {}
+
+    public int size() {
+        return size;
+    }
 }
index fe72d01..b510115 100644 (file)
@@ -47,6 +47,8 @@ public class JU_Log4JLogTargetTest {
     \r
     @Test\r
     public void testLoggable() {\r
+       Logger l4jLogger = Logger.getLogger("testLogger");\r
+       l4jLogger.setLevel(Level.DEBUG);\r
         Log4JLogTarget logObj = null;\r
         try {\r
             logObj = new Log4JLogTarget( "testLogger", Level.DEBUG);\r