From 6309ef454e6960d95d13534645e1f15904de6862 Mon Sep 17 00:00:00 2001 From: Instrumental Date: Tue, 3 Sep 2019 12:31:32 -0500 Subject: Update Fixes from testing Issue-ID: AAF-961 Change-Id: I142e460607bf32a785037fa2360b1c0efc3948b1 Signed-off-by: Instrumental --- .../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 +++++++++++--------- 6 files changed, 307 insertions(+), 73 deletions(-) create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/FileGetter.java (limited to 'auth/auth-cass') 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(); } -- cgit 1.2.3-korg