X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=auth%2Fauth-cass%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Faaf%2Fauth%2Fdao%2Fhl%2FQuestion.java;h=2e8e55f5b068fda7fde27d8d8d807f766d14cb3e;hb=HEAD;hp=1b20b900b5c5490940888208d628fbf5f3caa76e;hpb=49a8ce0053b7a4c9655e87020b7eed83ae8c312f;p=aaf%2Fauthz.git 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 1b20b900..2e8e55f5 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 @@ -7,9 +7,9 @@ * 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. @@ -26,12 +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.Set; +import java.util.TreeMap; import java.util.TreeSet; import org.onap.aaf.auth.common.Define; @@ -80,9 +81,9 @@ import com.datastax.driver.core.Cluster; /** * Question HL DAO - * + * * A Data Access Combination Object which asks Security and other Questions - * + * * @author Jonathan * */ @@ -134,57 +135,57 @@ public class Question { public HistoryDAO historyDAO() { return historyDAO; } - + private final CachedNSDAO nsDAO; public CachedNSDAO nsDAO() { return nsDAO; } - + private final CachedRoleDAO roleDAO; public CachedRoleDAO roleDAO() { return roleDAO; } - + private final CachedPermDAO permDAO; public CachedPermDAO permDAO() { return permDAO; } - + private final CachedUserRoleDAO userRoleDAO; public CachedUserRoleDAO userRoleDAO() { return userRoleDAO; } - + private final CachedCredDAO credDAO; public CachedCredDAO credDAO() { return credDAO; } - + private final CachedCertDAO certDAO; public CachedCertDAO certDAO() { return certDAO; } - + private final DelegateDAO delegateDAO; public DelegateDAO delegateDAO() { return delegateDAO; } - + private final FutureDAO futureDAO; public FutureDAO futureDAO() { return futureDAO; } - + private final ApprovalDAO approvalDAO; public ApprovalDAO approvalDAO() { return approvalDAO; } - + public final LocateDAO locateDAO; public LocateDAO locateDAO() { return locateDAO; } - + private final CacheInfoDAO cacheInfoDAO; private final int cldays; private final boolean alwaysSpecial; @@ -215,18 +216,18 @@ public class Question { if (specialLogSlot==null) { specialLogSlot = trans.slot(AuthzTransFilter.SPECIAL_LOG_SLOT); } - + if (transIDSlot==null) { transIDSlot = trans.slot(AuthzTransFilter.TRANS_ID_SLOT); } - + AbsCassDAO.primePSIs(trans); - + cldays = Integer.parseInt(trans.getProperty(Config.AAF_CRED_WARN_DAYS, Config.AAF_CRED_WARN_DAYS_DFT)); - + alwaysSpecial = Boolean.parseBoolean(trans.getProperty("aaf_always_special", Boolean.FALSE.toString())); } - + /** * Note: This Constructor created for JUNIT Purposes. Do not use otherwise. */ @@ -258,7 +259,7 @@ public class Question { CachedDAO.startCleansing(env, credDAO, userRoleDAO); CachedDAO.startRefresh(env, cacheInfoDAO); } - + public void close(AuthzTrans trans) { historyDAO.close(trans); cacheInfoDAO.close(trans); @@ -282,7 +283,7 @@ public class Question { pdd.type = type.substring(colon+1); pdd.instance = instance; pdd.action = action; - + return Result.ok(pdd); } else { return Result.err(Result.ERR_BadData,"Could not extract ns and type from " + type); @@ -300,10 +301,10 @@ public class Question { /** * getPermsByUser - * + * * Because this call is frequently called internally, AND because we already * look for it in the initial Call, we cache within the Transaction - * + * * @param trans * @param user * @return @@ -311,26 +312,26 @@ public class Question { public Result> getPermsByUser(AuthzTrans trans, String user, boolean lookup) { return PermLookup.get(trans, this, user).getPerms(lookup); } - + public Result> getPermsByUserFromRolesFilter(AuthzTrans trans, String user, String forUser) { PermLookup plUser = PermLookup.get(trans, this, user); Result> plPermNames = plUser.getPermNames(); if (plPermNames.notOK()) { return Result.err(plPermNames); } - + Set nss; if (forUser.equals(user)) { nss = null; } else { - // Setup a TreeSet to check on Namespaces to + // Setup a TreeSet to check on Namespaces to nss = new TreeSet<>(); PermLookup fUser = PermLookup.get(trans, this, forUser); Result> forUpn = fUser.getPermNames(); if (forUpn.notOK()) { return Result.err(forUpn); } - + for (String pn : forUpn.value) { Result decoded = PermDAO.Data.decodeToArray(trans, this, pn); if (decoded.isOKhasData()) { @@ -355,7 +356,7 @@ public class Question { trans.error().log(pn,", derived from a Role, is invalid. Run Data Cleanup:",rpdd.errorString()); } } - return Result.ok(rlpUser); + return Result.ok(rlpUser); } public Result> getPermsByType(AuthzTrans trans, String type) { @@ -388,7 +389,7 @@ public class Question { if (nss.notOK()) { return Result.err(nss); } - + return permDAO.read(trans, nss.value.ns, nss.value.name, instance,action); } } @@ -461,22 +462,22 @@ public class Question { /** * Derive NS - * + * * Given a Child Namespace, figure out what the best Namespace parent is. - * + * * For instance, if in the NS table, the parent "org.osaaf" exists, but not * "org.osaaf.child" or "org.osaaf.a.b.c", then passing in either * "org.osaaf.child" or "org.osaaf.a.b.c" will return "org.osaaf" - * + * * Uses recursive search on Cached DAO data - * + * * @param trans * @param child * @return */ public Result deriveNs(AuthzTrans trans, String child) { Result> r = nsDAO.read(trans, child); - + if (r.isOKhasData()) { return Result.ok(r.value.get(0)); } else { @@ -496,11 +497,12 @@ public class Question { Result> rld = nsDAO.read(trans, lookup); if (rld.isOKhasData()) { nsd=rld.value.get(0); + lookup = nsd.parent; if (type.type == nsd.type) { return Result.ok(nsd); } else { int dot = str.lastIndexOf('.'); - + if (dot < 0) { return Result.err(Status.ERR_NsNotFound, "No Namespace for [%s]", str); } else { @@ -509,7 +511,7 @@ public class Question { } } else { int dot = str.lastIndexOf('.'); - + if (dot < 0) { return Result.err(Status.ERR_NsNotFound,"There is no valid Company Namespace for %s",str); } else { @@ -537,9 +539,9 @@ public class Question { /** * Translate an ID into it's domain - * + * * i.e. myid1234@aaf.att.com results in domain of com.att.aaf - * + * * @param id * @return */ @@ -566,9 +568,9 @@ public class Question { /** * Validate Namespace of ID@Domain - * + * * Namespace is reverse order of Domain. - * + * * @param trans * @param id * @return @@ -582,7 +584,7 @@ public class Question { ns = domain2ns(id); } if (ns.length() > 0) { - if (!trans.org().getDomain().equals(ns)) { + if (!trans.org().getDomain().equals(ns)) { Result> rlnsd = nsDAO.read(trans, ns); if (rlnsd.isOKhasData()) { return Result.ok(rlnsd.value.get(0)); @@ -609,7 +611,7 @@ public class Question { ns = ns.substring(0, last); } } while (last >= 0); - + // SAFETY - Do not allow these when NS is Root if(!isRoot) { // com.att.aaf.ns|::ns| @@ -679,7 +681,7 @@ public class Question { // 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, + Result rv = mayUserVirtueOfNS(trans, user, ndd, ":" + rdd.ns + ":ns", access.name()); if (rv.isOK()) { return rv; @@ -715,7 +717,7 @@ public class Question { 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; @@ -784,16 +786,22 @@ public class Question { return Result.err(Status.ERR_BadData, "[%s] cannot be a delegate for self", dd.user); } - if (!isUser && !isGranted(trans, trans.user(), ROOT_NS,DELG, - org.getDomain(), Question.CREATE)) { - return Result.err(Status.ERR_Denied, + if (!isUser) { + String supportedDomain = org.supportedDomain(dd.user); + if(supportedDomain==null) { + return Result.err(Status.ERR_Denied, + "[%s] may not create a delegate for the domain for [%s]", + trans.user(), dd.user); + } else if(!isGranted(trans, trans.user(), ROOT_NS,DELG,supportedDomain,Question.CREATE)) { + return Result.err(Status.ERR_Denied, "[%s] may not create a delegate for [%s]", trans.user(), dd.user); + } } break; case read: case write: - if (!isUser && !isDelegate && + if (!isUser && !isDelegate && !isGranted(trans, trans.user(), ROOT_NS,DELG,org.getDomain(), access.name())) { return Result.err(Status.ERR_Denied, "[%s] may not %s delegates for [%s]", trans.user(), @@ -816,14 +824,14 @@ public class Question { String ns = nsd.name; // If an ADMIN of the Namespace, then allow - + Result> rurd; if ((rurd = userRoleDAO.readUserInRole(trans, user, ns+DOT_ADMIN)).isOKhasData()) { return Result.ok(nsd); } else if (rurd.status==Result.ERR_Backend) { return Result.err(rurd); } - + // If Specially granted Global Permission if (isGranted(trans, user, ROOT_NS,NS, ns_and_type, access)) { return Result.ok(nsd); @@ -849,13 +857,13 @@ public class Question { ns_and_type); } - + /** * isGranted - * + * * Important function - Check internal Permission Schemes for Permission to * do things - * + * * @param trans * @param type * @param instance @@ -869,7 +877,7 @@ public class Question { if (ns.equals(pd.ns)) { if (type.equals(pd.type)) { if (PermEval.evalInstance(pd.instance, instance)) { - if (PermEval.evalAction(pd.action, action)) { // don't return action here, might miss other action + if (PermEval.evalAction(pd.action, action)) { // don't return action here, might miss other action return true; } } @@ -898,31 +906,41 @@ public class Question { } } else { Date now = new Date(); - // Bug noticed 6/22. Sorting on the result can cause Concurrency Issues. - List 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 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 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; } - + Date expired = null; StringBuilder debug = willSpecialLog(trans,user)?new StringBuilder():null; for (CredDAO.Data cdd : cddl) { if (!cdd.id.equals(user)) { trans.error().log("doesUserCredMatch DB call does not match for user: " + user); } - if (cdd.expires.after(now)) { + if (cdd.expires.after(now) || trans.org().isUserExpireExempt(cdd.id, cdd.expires)) { byte[] dbcred = cdd.cred.array(); - + try { switch(cdd.type) { case CredDAO.BASIC_AUTH: @@ -940,7 +958,7 @@ public class Question { bb.putInt(cdd.other); bb.put(cred); byte[] hash = Hash.hashSHA256(bb.array()); - + if (Hash.compareTo(hash,dbcred)==0) { checkLessThanDays(trans,cldays,now,cdd); trans.setTag(cdd.tag); @@ -962,7 +980,7 @@ public class Question { } } } // end for each - + if (expired!=null) { // Note: this is only returned if there are no good Credentials rv = Result.err(Status.ERR_Security, @@ -1003,7 +1021,7 @@ public class Question { if (cexp userCredCheck(AuthzTrans trans, CredDAO.Data orig, final byte[] raw) { Result rv; TimeTaken tt = trans.start("CheckCred Cred", Env.SUB); @@ -1193,7 +1211,7 @@ public class Question { } return b; } - + public static void logEncryptTrace(AuthzTrans trans, String data) { long ti; trans.put(transIDSlot, ti=nextTraceID()); @@ -1210,7 +1228,7 @@ public class Question { } boolean rc = specialLog.add(id); if (rc) { - trans.trace().printf("Trace on for %s requested by %s",id,trans.user()); + trans.trace().printf("Trace on for %s requested by %s",id,trans.user()); } return rc; } @@ -1224,12 +1242,12 @@ public class Question { specialLog = null; } if (rv) { - trans.trace().printf("Trace off for %s requested by %s",id,trans.user()); + trans.trace().printf("Trace off for %s requested by %s",id,trans.user()); } return rv; } - /** + /** * canMove * Which Types can be moved * @param nsType @@ -1255,19 +1273,19 @@ public class Question { if (rur.isOKhasData()) { Date now = new Date(); for (UserRoleDAO.Data urdd : rur.value){ - if (urdd.expires.after(now)) { + if (urdd.expires.after(now) || trans.org().isUserExpireExempt(urdd.user, urdd.expires)) { return true; } } }; return false; } - + public boolean isOwner(AuthzTrans trans, String user, String ns) { Result> rur = userRoleDAO().read(trans, user,ns+DOT_OWNER); if (rur.isOKhasData()) {for (UserRoleDAO.Data urdd : rur.value){ Date now = new Date(); - if (urdd.expires.after(now)) { + if (urdd.expires.after(now) || trans.org().isUserExpireExempt(urdd.user, urdd.expires)) { return true; } }}; @@ -1279,20 +1297,20 @@ public class Question { Date now = new Date(); int count = 0; if (rur.isOKhasData()) {for (UserRoleDAO.Data urdd : rur.value){ - if (urdd.expires.after(now)) { + if (urdd.expires.after(now) || trans.org().isUserExpireExempt(urdd.user, urdd.expires)) { ++count; } }}; return count; } - + /** * Return a Unique String, (same string, if it is already unique), with only * lowercase letters, digits and the '.' character. - * + * * @param name * @return - * @throws IOException + * @throws IOException */ public static String toUnique(String name) throws IOException { byte[] from = name.getBytes(); @@ -1305,7 +1323,7 @@ public class Question { } return sb.toString(); } - + public static String fromUnique(String name) throws IOException { byte[] from = name.getBytes(); StringBuilder sb = new StringBuilder();