From 6309ef454e6960d95d13534645e1f15904de6862 Mon Sep 17 00:00:00 2001 From: Instrumental Date: Tue, 3 Sep 2019 12:31:32 -0500 Subject: [PATCH] Update Fixes from testing Issue-ID: AAF-961 Change-Id: I142e460607bf32a785037fa2360b1c0efc3948b1 Signed-off-by: Instrumental --- .../org/onap/aaf/auth/batch/helpers/CQLBatch.java | 30 ++++ .../onap/aaf/auth/batch/helpers/CQLBatchLoop.java | 2 +- .../java/org/onap/aaf/auth/batch/helpers/Cred.java | 17 ++- .../java/org/onap/aaf/auth/batch/helpers/X509.java | 9 +- .../main/java/org/onap/aaf/auth/dao/Cached.java | 2 +- .../java/org/onap/aaf/auth/dao/CassAccess.java | 2 + .../onap/aaf/auth/dao/cached/CachedCredDAO.java | 69 +++++++-- .../org/onap/aaf/auth/dao/cached/FileGetter.java | 149 ++++++++++++++++++ .../java/org/onap/aaf/auth/dao/cass/CredDAO.java | 14 ++ .../java/org/onap/aaf/auth/dao/hl/Question.java | 144 ++++++++++-------- .../org/onap/aaf/auth/cm/facade/FacadeImpl.java | 1 + .../org/onap/aaf/auth/cm/mapper/Mapper1_0.java | 1 - .../org/onap/aaf/auth/cm/service/CMService.java | 168 ++++++++++++++------- .../java/org/onap/aaf/auth/cm/service/Code.java | 2 +- .../main/java/org/onap/aaf/auth/cmd/AAFcli.java | 22 ++- .../java/org/onap/aaf/auth/cmd/perm/Rename.java | 41 +++-- .../org/onap/aaf/auth/cmd/role/ListByPerm.java | 27 ++-- .../onap/aaf/auth/cmd/user/ListForPermission.java | 34 +++-- .../java/org/onap/aaf/auth/env/AuthzTrans.java | 2 + .../java/org/onap/aaf/auth/env/AuthzTransImpl.java | 5 + .../main/java/org/onap/aaf/auth/env/NullTrans.java | 5 + .../src/main/java/org/onap/aaf/auth/gui/Page.java | 4 + .../org/onap/aaf/auth/service/api/API_Perms.java | 6 +- .../org/onap/aaf/auth/service/api/API_Roles.java | 5 +- .../org/onap/aaf/auth/service/api/API_User.java | 5 +- .../aaf/auth/service/mapper/JU_Mapper_2_0.java | 28 ++-- .../org/onap/aaf/cadi/aaf/v2_0/AAFLocator.java | 76 ++++++++-- .../org/onap/aaf/cadi/aaf/v2_0/AbsAAFLocator.java | 7 +- .../aaf/cadi/aaf/v2_0/test/JU_AbsAAFLocator.java | 17 ++- .../org/onap/aaf/cadi/oauth/test/JU_TzHClient.java | 17 ++- .../java/org/onap/aaf/cadi/locator/DNSLocator.java | 7 + .../aaf/misc/env/impl/JU_Log4JLogTargetTest.java | 2 + 32 files changed, 694 insertions(+), 226 deletions(-) create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/FileGetter.java diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatch.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatch.java index b626bae7..d62c7781 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatch.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatch.java @@ -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(); } diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatchLoop.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatchLoop.java index 2604364b..1a1bdf33 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatchLoop.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatchLoop.java @@ -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; diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Cred.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Cred.java index 1f5a1f40..83638cc7 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Cred.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Cred.java @@ -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 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() { diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/X509.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/X509.java index c68a9945..e2d86947 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/X509.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/X509.java @@ -59,10 +59,15 @@ public class X509 { public static void load(Trans trans, Session session, Visitor 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 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 visitor) { + private static void load(Trans trans, Session session, Visitor visitor, String query) { trans.info().log( "query: " + query ); TimeTaken tt = trans.start("Read X509", Env.REMOTE); diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cached.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cached.java index 1888b3ac..a31e7b5b 100644 --- a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cached.java +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cached.java @@ -99,7 +99,7 @@ public class Cached extends Cache { + public interface Getter { public abstract Result> get(); }; diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassAccess.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassAccess.java index cde26117..c5ad4599 100644 --- a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassAccess.java +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassAccess.java @@ -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(); } diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCredDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCredDAO.java index 106999d3..6bdc22bc 100644 --- a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCredDAO.java +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCredDAO.java @@ -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 { + private final ReadID readID; + private final ReadID readIDBath; + public CachedCredDAO(CredDAO dao, CIDAO info, long expiresIn) { super(dao, info, CredDAO.CACHE_SEG, expiresIn); + if(FileGetter.isLoaded) { + readID = new ReadID() { + @Override + public Result> 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> read(AuthzTrans trans, final String id) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + return dao().readID(trans, id); + } + }; + + Result> 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> read(AuthzTrans trans, final String id) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + return dao().readIDBAth(trans, id); + } + }; + + Result> 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 return dao().readNS(trans, ns); } - + public Result> readID(AuthzTrans trans, final String id) { - DAOGetter getter = new DAOGetter(trans,dao()) { - public Result> call() { - return dao().readID(trans, id); - } - }; - - Result> 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> readIDBAth(AuthzTrans trans, String id) { + return readIDBath.read(trans,id); } + private interface ReadID { + public Result> 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 index 00000000..b7a6c59d --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/FileGetter.java @@ -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> 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 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 getter(String id) { + return new FGetter(id); + } + private static List EMPTY = new ArrayList<>(); + public class FGetter implements Getter { + private final List lcdd; + public FGetter(final String id) { + lcdd = data.get(id); + } + @Override + public Result> 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 g = fg.getter(id); + Result> r = g.get(); + if(r.isOKhasData()) { + for(CredDAO.Data cdd : r.value) { + System.out.println(cdd); + } + } + } + } +} + diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CredDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CredDAO.java index 9a2511d2..71401882 100644 --- a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CredDAO.java +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CredDAO.java @@ -64,6 +64,7 @@ public class CredDAO extends CassDAOImpl { private CIDAO 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 { 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 { return psID.read(trans, R_TEXT, new Object[]{id}); } + public Result> readIDBAth(AuthzTrans trans, String id) { + return psIDBath.read(trans, R_TEXT, new Object[] {id}); + } + /** * Log Modification statements to History * diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java index b797ca05..dddf3b51 100644 --- a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java @@ -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 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 mayUser(AuthzTrans trans, String user,NsDAO.Data ndd, Access access) { // .access|:role:| 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|::ns| - // AAF-724 - Make consistent response for May User", and not take the - // last check... too confusing. - Result 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|::ns| + // AAF-724 - Make consistent response for May User", and not take the + // last check... too confusing. + Result 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 mayUser(AuthzTrans trans, String user, RoleDAO.Data rdd, Access access) { @@ -630,49 +640,56 @@ public class Question { } public Result mayUser(AuthzTrans trans, String user, NsDAO.Data ndd, RoleDAO.Data rdd, Access access) { - // 1) Is User in the Role? - Result> 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> rurd = userRoleDAO.readUserInRole(trans, user, rdd.fullName()); + if (rurd.isOKhasData()) { + return Result.ok(ndd); + } } String roleInst = ":role:" + rdd.name; // .access|:role:| 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|::role:name| - Result 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|::role:name| + Result 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 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 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 mayUser(AuthzTrans trans, String user,PermDAO.Data pdd, Access access) { @@ -695,43 +712,50 @@ public class Question { } public Result 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; // .access|:role:| 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|::role:name| - Result 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|::role:name| + Result 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 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 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 mayUser(AuthzTrans trans, DelegateDAO.Data dd, Access access) { @@ -861,7 +885,7 @@ public class Question { Result> result; TimeTaken tt = trans.start("Read DB Cred", Env.REMOTE); try { - result = credDAO.readID(trans, user); + result = credDAO.readIDBAth(trans, user); } finally { tt.done(); } diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeImpl.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeImpl.java index a93b7cb4..f381a9e8 100644 --- a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeImpl.java +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeImpl.java @@ -98,6 +98,7 @@ public abstract class FacadeImpl extends org.onap.aaf. private Mapper mapper; // private Slot sCertAuth; private final String voidResp; + public FacadeImpl(AAF_CM certman, CMService service, Mapper mapper, diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper1_0.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper1_0.java index 82639e21..1c951961 100644 --- a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper1_0.java +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper1_0.java @@ -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; diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java index 48fe8d81..4788ee45 100644 --- a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java @@ -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 .certman||"+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 .certman||"+IGNORE_IPS); } } public Result requestCert(final AuthzTrans trans, final Result 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 notes = null; - List fqdns = new ArrayList<>(req.value.fqdns); + List 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> 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 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 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> 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 certs = Factory.toX509Certificate(cdd.x509); + for(Iterator 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 +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/Code.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/Code.java index a6663ad7..fdf2447d 100644 --- a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/Code.java +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/Code.java @@ -29,7 +29,7 @@ import org.onap.aaf.auth.rserv.HttpCode; public abstract class Code extends HttpCode 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 } diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/AAFcli.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/AAFcli.java index 4cd628e8..6ca37c33 100644 --- a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/AAFcli.java +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/AAFcli.java @@ -250,7 +250,13 @@ public class AAFcli { pw.println("Press 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); diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Rename.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Rename.java index dbadd8a0..5a7b5dee 100644 --- a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Rename.java +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Rename.java @@ -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 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 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; } }); diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByPerm.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByPerm.java index feb1dec8..5d291ace 100644 --- a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByPerm.java +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByPerm.java @@ -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 fp = client.read( - "/authz/roles/perm/"+type+'/'+instance+'/'+action, - getDF(Roles.class) - ); - return list(fp,client, HEADER+type+'|'+instance+'|'+action); + try { + Future 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); + } } }); } diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForPermission.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForPermission.java index dff3dc5e..b40c96ce 100644 --- a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForPermission.java +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForPermission.java @@ -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 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) (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 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) (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(); } }); } diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTrans.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTrans.java index 454d46d2..ac16833d 100644 --- a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTrans.java +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTrans.java @@ -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); diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransImpl.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransImpl.java index c68f71ab..037ce4ee 100644 --- a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransImpl.java +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransImpl.java @@ -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) { diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/NullTrans.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/NullTrans.java index 9189cc30..df086cda 100644 --- a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/NullTrans.java +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/NullTrans.java @@ -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; diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java index 96c0fc48..02654696 100644 --- a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java @@ -309,6 +309,10 @@ public class Page extends HTMLCacheGen { if(theme==null) { theme = defaultTheme; } + List 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); diff --git a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Perms.java b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Perms.java index ae94553c..04654d47 100644 --- a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Perms.java +++ b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Perms.java @@ -232,8 +232,10 @@ public class API_Perms { HttpServletRequest req, HttpServletResponse resp) throws Exception { - Result r = context.renamePerm(trans, req, resp, pathParam(req, "type"), - pathParam(req, "instance"), pathParam(req, "action")); + Result 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); diff --git a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Roles.java b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Roles.java index 2c93bc38..6088dd36 100644 --- a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Roles.java +++ b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Roles.java @@ -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 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: diff --git a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_User.java b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_User.java index 0ce1dfe2..d5ce00c3 100644 --- a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_User.java +++ b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_User.java @@ -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 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: diff --git a/auth/auth-service/src/test/java/org/onap/aaf/auth/service/mapper/JU_Mapper_2_0.java b/auth/auth-service/src/test/java/org/onap/aaf/auth/service/mapper/JU_Mapper_2_0.java index dc580ef4..fd664d6c 100644 --- a/auth/auth-service/src/test/java/org/onap/aaf/auth/service/mapper/JU_Mapper_2_0.java +++ b/auth/auth-service/src/test/java/org/onap/aaf/auth/service/mapper/JU_Mapper_2_0.java @@ -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 result = mapper.cred(transaction, createCredRequest(id, password), true); + Result 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 result = mapper.cred(transaction, createCredRequest(id, password), true); + Result 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 Map of(Object ... tag_value) { Map rv = new HashMap<>(); for(int i=0;i List newArrayList(Collection ... init ) { List rv = new ArrayList<>(); for(Collection o : init) { diff --git a/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFLocator.java b/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFLocator.java index ed24b1ee..a993109a 100644 --- a/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFLocator.java +++ b/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AAFLocator.java @@ -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 { private static RosettaEnv env; - HClient client; + private HClient client; + private HClient lclient; private RosettaDF epsDF; + private DNSLocator locatorLocator; + private Item locatorItem; + public AAFLocator(SecurityInfoC 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 { 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 { } 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 fr = client.futureRead(epsDF, TYPE.JSON); - if (fr.get(client.timeout())) { + int max = locatorLocator.size(); + for(int i=0;i fr = lclient.futureRead(epsDF, TYPE.JSON); + if (fr.get(lclient.timeout())) { List epl = new LinkedList<>(); for (Endpoint endpoint : fr.value.getEndpoint()) { epl.add(new EP(endpoint,latitude,longitude)); diff --git a/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AbsAAFLocator.java b/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AbsAAFLocator.java index 2fe3ffdb..5ef25bcd 100644 --- a/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AbsAAFLocator.java +++ b/cadi/aaf/src/main/java/org/onap/aaf/cadi/aaf/v2_0/AbsAAFLocator.java @@ -72,6 +72,7 @@ public abstract class AbsAAFLocator implements Locator } 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 implements Locator } 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 implements Locator 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 implements Locator } return null; } - + protected static class AAFLItem implements Item { private Iterator iter; private URI uri; diff --git a/cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/v2_0/test/JU_AbsAAFLocator.java b/cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/v2_0/test/JU_AbsAAFLocator.java index 64e9572e..004eed3a 100644 --- a/cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/v2_0/test/JU_AbsAAFLocator.java +++ b/cadi/aaf/src/test/java/org/onap/aaf/cadi/aaf/v2_0/test/JU_AbsAAFLocator.java @@ -21,18 +21,23 @@ 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; diff --git a/cadi/aaf/src/test/java/org/onap/aaf/cadi/oauth/test/JU_TzHClient.java b/cadi/aaf/src/test/java/org/onap/aaf/cadi/oauth/test/JU_TzHClient.java index 11dce825..805b13f1 100644 --- a/cadi/aaf/src/test/java/org/onap/aaf/cadi/oauth/test/JU_TzHClient.java +++ b/cadi/aaf/src/test/java/org/onap/aaf/cadi/oauth/test/JU_TzHClient.java @@ -21,12 +21,13 @@ 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)); } diff --git a/cadi/client/src/main/java/org/onap/aaf/cadi/locator/DNSLocator.java b/cadi/client/src/main/java/org/onap/aaf/cadi/locator/DNSLocator.java index 4711aee6..d64de699 100644 --- a/cadi/client/src/main/java/org/onap/aaf/cadi/locator/DNSLocator.java +++ b/cadi/client/src/main/java/org/onap/aaf/cadi/locator/DNSLocator.java @@ -40,6 +40,8 @@ public class DNSLocator implements Locator { 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 { } } 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 { } public void destroy() {} + + public int size() { + return size; + } } diff --git a/misc/env/src/test/java/org/onap/aaf/misc/env/impl/JU_Log4JLogTargetTest.java b/misc/env/src/test/java/org/onap/aaf/misc/env/impl/JU_Log4JLogTargetTest.java index fe72d01e..b5101158 100644 --- a/misc/env/src/test/java/org/onap/aaf/misc/env/impl/JU_Log4JLogTargetTest.java +++ b/misc/env/src/test/java/org/onap/aaf/misc/env/impl/JU_Log4JLogTargetTest.java @@ -47,6 +47,8 @@ public class JU_Log4JLogTargetTest { @Test public void testLoggable() { + Logger l4jLogger = Logger.getLogger("testLogger"); + l4jLogger.setLevel(Level.DEBUG); Log4JLogTarget logObj = null; try { logObj = new Log4JLogTarget( "testLogger", Level.DEBUG); -- 2.16.6