diff options
Diffstat (limited to 'auth/auth-cass')
9 files changed, 332 insertions, 84 deletions
diff --git a/auth/auth-cass/.gitignore b/auth/auth-cass/.gitignore index 5fd2ede3..d0b9b474 100644 --- a/auth/auth-cass/.gitignore +++ b/auth/auth-cass/.gitignore @@ -2,3 +2,4 @@ /.project /target/ /.classpath +/*.tgz diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cacheable.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cacheable.java index 3632aa15..818ae148 100644 --- a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cacheable.java +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cacheable.java @@ -3,6 +3,7 @@ * org.onap.aaf * =========================================================================== * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019 IBM. * =========================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +30,7 @@ package org.onap.aaf.auth.dao; * @author Jonathan * */ +@FunctionalInterface public interface Cacheable { public int[] invalidate(Cached<?,?> cache); } 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<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(); }; 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<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 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<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); + } + } + } + } +} + diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ApprovalDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ApprovalDAO.java index 54f57449..7e90bbb9 100644 --- a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ApprovalDAO.java +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ApprovalDAO.java @@ -212,7 +212,7 @@ public class ApprovalDAO extends CassDAOImpl<AuthzTrans,ApprovalDAO.Data> { } ApprovalLoader.deflt.load(data, rd.value.one()); } - if ("approved".equals(data.status) || "denied".equals(data.status)) { + if (APPROVED.equals(data.status) || DENIED.equals(data.status)) { StringBuilder sb = new StringBuilder("BEGIN BATCH\n"); sb.append("INSERT INTO "); sb.append(TABLELOG); 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<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 * 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..c7ee5938 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 @@ -26,13 +26,13 @@ import java.nio.ByteBuffer; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.ArrayList; -import java.util.Collections; +import java.util.Collection; 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.TreeMap; import java.util.TreeSet; import org.onap.aaf.auth.common.Define; @@ -45,6 +45,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 +125,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 +203,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 +598,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 +641,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 +713,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 +886,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(); } @@ -875,18 +900,28 @@ public class Question { } } else { Date now = new Date(); - // Bug noticed 6/22. Sorting on the result can cause Concurrency Issues. - List<CredDAO.Data> cddl; + // Bug noticed 6/22. Sorting on the result can cause Concurrency Issues. + // 9/14/2019. Use TreeSet for sorting, and using only the LAST of a Tagged entry + Collection<CredDAO.Data> cddl; if (result.value.size() > 1) { - cddl = new ArrayList<>(result.value.size()); - for (CredDAO.Data old : result.value) { - if (old.type==CredDAO.BASIC_AUTH || old.type==CredDAO.BASIC_AUTH_SHA256) { - cddl.add(old); + Map<String,CredDAO.Data> mcdd = new TreeMap<>(); + CredDAO.Data cdd; + String tag; + int pseudoTag = 0; + for (CredDAO.Data rcdd : result.value) { + if (rcdd.type==CredDAO.BASIC_AUTH || rcdd.type==CredDAO.BASIC_AUTH_SHA256) { + if(rcdd.tag==null) { + mcdd.put(Integer.toString(++pseudoTag),rcdd); + } else { + tag = rcdd.tag; + cdd = mcdd.get(tag); + if(cdd==null || cdd.expires.before(rcdd.expires)) { + mcdd.put(tag,rcdd); + } + } } } - if (cddl.size()>1) { - Collections.sort(cddl, (a, b) -> b.expires.compareTo(a.expires)); - } + cddl = mcdd.values(); } else { cddl = result.value; } |