diff options
Diffstat (limited to 'auth')
26 files changed, 598 insertions, 196 deletions
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<String> row) { + Long l = Long.parseLong(row.get(5)); + String date = sdf.format(new Date(l)); sb.append("DELETE from authz.cred WHERE id='"); sb.append(row.get(1)); sb.append("' AND type="); sb.append(Integer.parseInt(row.get(3))); // Note: We have to work with long, because Expires is part of Key... can't easily do date. - sb.append(" AND expires=dateof(maxtimeuuid("); - sb.append(row.get(5)); - sb.append("));\n"); + sb.append(" AND expires='"); + sb.append(date); + sb.append("';\n"); +// sb.append(" AND expires=dateof(maxtimeuuid("); +// sb.append(row.get(5)); +// sb.append("));\n"); + } public String toString() { 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<X509> visitor) { - load(trans,session,"select ca, id, x500, x509, serial from authz.x509;", visitor); + load(trans,session, "" , visitor); } + + public static void load(Trans trans, Session session, String where, Visitor<X509> visitor) { + load(trans,session, visitor,"select ca, id, x500, x509, serial from authz.x509 " + where +';'); + } + - private static void load(Trans trans, Session session, String query, Visitor<X509> visitor) { + private static void load(Trans trans, Session session, Visitor<X509> visitor, String query) { trans.info().log( "query: " + query ); TimeTaken tt = trans.start("Read X509", Env.REMOTE); 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/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..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<String> specialLog = null; - public static final Random random = new SecureRandom(); + public static final SecureRandom random = new SecureRandom(); private static long traceID = random.nextLong(); private static Slot specialLogSlot = null; private static Slot transIDSlot = null; @@ -202,6 +202,8 @@ public class Question { permDAO = new CachedPermDAO(new PermDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn); roleDAO = new CachedRoleDAO(new RoleDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn); userRoleDAO = new CachedUserRoleDAO(new UserRoleDAO(trans, historyDAO,cacheInfoDAO), cacheInfoDAO, expiresIn); + // Create if aaf_file_cred exists with file + FileGetter.singleton(trans.env().access()); credDAO = new CachedCredDAO(new CredDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn); certDAO = new CachedCertDAO(new CertDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn); @@ -595,27 +597,35 @@ public class Question { public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,NsDAO.Data ndd, Access access) { // <ns>.access|:role:<role name>|<read|write> String ns = ndd.name; + boolean isRoot = ns.startsWith(Define.ROOT_NS()); int last; do { if (isGranted(trans, user, ns, ACCESS, ":ns", access.name())) { return Result.ok(ndd); } + if(isRoot) { + break; + } if ((last = ns.lastIndexOf('.')) >= 0) { ns = ns.substring(0, last); } } while (last >= 0); - // com.att.aaf.ns|:<client ns>:ns|<access> - // AAF-724 - Make consistent response for May User", and not take the - // last check... too confusing. - Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":" + ndd.name + ":ns", access.name()); - if (rv.isOK()) { - return rv; - } else if (rv.status==Result.ERR_Backend) { - return Result.err(rv); - } else { - return Result.err(Status.ERR_Denied, "[%s] may not %s in NS [%s]", - user, access.name(), ndd.name); - } + + // SAFETY - Do not allow these when NS is Root + if(!isRoot) { + // com.att.aaf.ns|:<client ns>:ns|<access> + // AAF-724 - Make consistent response for May User", and not take the + // last check... too confusing. + Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":" + ndd.name + ":ns", access.name()); + if (rv.isOK()) { + return rv; + } else if (rv.status==Result.ERR_Backend) { + return Result.err(rv); + } + } + return Result.err(Status.ERR_Denied, "[%s] may not %s in NS [%s]", + user, access.name(), ndd.name); + } public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user, RoleDAO.Data rdd, Access access) { @@ -630,49 +640,56 @@ public class Question { } public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user, NsDAO.Data ndd, RoleDAO.Data rdd, Access access) { - // 1) Is User in the Role? - Result<List<UserRoleDAO.Data>> rurd = userRoleDAO.readUserInRole(trans, user, rdd.fullName()); - if (rurd.isOKhasData()) { - return Result.ok(ndd); + // 1) For "read", Is User in the Role is enough + if(Access.read.equals(access)) { + Result<List<UserRoleDAO.Data>> rurd = userRoleDAO.readUserInRole(trans, user, rdd.fullName()); + if (rurd.isOKhasData()) { + return Result.ok(ndd); + } } String roleInst = ":role:" + rdd.name; // <ns>.access|:role:<role name>|<read|write> String ns = rdd.ns; + boolean isRoot = ns.startsWith(Define.ROOT_NS()); int last; do { if (isGranted(trans, user, ns,ACCESS, roleInst, access.name())) { return Result.ok(ndd); } + if(isRoot) { + break; + } if ((last = ns.lastIndexOf('.')) >= 0) { ns = ns.substring(0, last); } } while (last >= 0); - // Check if Access by Global Role perm - // com.att.aaf.ns|:<client ns>:role:name|<access> - Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":" - + rdd.ns + roleInst, access.name()); - if (rnsd.isOK()) { - return rnsd; - } else if (rnsd.status==Result.ERR_Backend) { - return Result.err(rnsd); - } + // SAFETY - Do not allow these when NS is Root + if(!isRoot) { + // Check if Access by Global Role perm + // com.att.aaf.ns|:<client ns>:role:name|<access> + Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":" + + rdd.ns + roleInst, access.name()); + if (rnsd.isOK()) { + return rnsd; + } else if (rnsd.status==Result.ERR_Backend) { + return Result.err(rnsd); + } - // Check if Access to Whole NS - // AAF-724 - Make consistent response for May User", and not take the - // last check... too confusing. - Result<org.onap.aaf.auth.dao.cass.NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, - ":" + rdd.ns + ":ns", access.name()); - if (rv.isOK()) { - return rv; - } else if (rnsd.status==Result.ERR_Backend) { - return Result.err(rnsd); - } else { - return Result.err(Status.ERR_Denied, "[%s] may not %s Role [%s]", - user, access.name(), rdd.fullName()); + // Check if Access to Whole NS + // AAF-724 - Make consistent response for May User", and not take the + // last check... too confusing. + Result<org.onap.aaf.auth.dao.cass.NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, + ":" + rdd.ns + ":ns", access.name()); + if (rv.isOK()) { + return rv; + } else if (rnsd.status==Result.ERR_Backend) { + return Result.err(rnsd); + } } - + return Result.err(Status.ERR_Denied, "[%s] may not %s Role [%s]", + user, access.name(), rdd.fullName()); } public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,PermDAO.Data pdd, Access access) { @@ -695,43 +712,50 @@ public class Question { } public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,NsDAO.Data ndd, PermDAO.Data pdd, Access access) { + // Most common occurrence... if granted Permission if (isGranted(trans, user, pdd.ns, pdd.type, pdd.instance, pdd.action)) { return Result.ok(ndd); } + String permInst = ":perm:" + pdd.type + ':' + pdd.instance + ':' + pdd.action; // <ns>.access|:role:<role name>|<read|write> String ns = ndd.name; + boolean isRoot = ns.startsWith(Define.ROOT_NS()); int last; do { if (isGranted(trans, user, ns, ACCESS, permInst, access.name())) { return Result.ok(ndd); } + if(isRoot) { + break; + } if ((last = ns.lastIndexOf('.')) >= 0) { ns = ns.substring(0, last); } } while (last >= 0); - // Check if Access by NS perm - // com.att.aaf.ns|:<client ns>:role:name|<access> - Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + permInst, access.name()); - if (rnsd.isOK()) { - return rnsd; - } else if (rnsd.status==Result.ERR_Backend) { - return Result.err(rnsd); - } + // SAFETY - Do not allow these when NS is Root + if(!isRoot) { + // Check if Access by NS perm + // com.att.aaf.ns|:<client ns>:role:name|<access> + Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + permInst, access.name()); + if (rnsd.isOK()) { + return rnsd; + } else if (rnsd.status==Result.ERR_Backend) { + return Result.err(rnsd); + } - // Check if Access to Whole NS - // AAF-724 - Make consistent response for May User", and not take the - // last check... too confusing. - Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + ":ns", access.name()); - if (rv.isOK()) { - return rv; - } else { - return Result.err(Status.ERR_Denied, - "[%s] may not %s Perm [%s|%s|%s]", user, access.name(), - pdd.fullType(), pdd.instance, pdd.action); + // Check if Access to Whole NS + // AAF-724 - Make consistent response for May User", and not take the + // last check... too confusing. + Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + ":ns", access.name()); + if (rv.isOK()) { + return rv; + } } - + return Result.err(Status.ERR_Denied, + "[%s] may not %s Perm [%s|%s|%s]", user, access.name(), + pdd.fullType(), pdd.instance, pdd.action); } public Result<Void> mayUser(AuthzTrans trans, DelegateDAO.Data dd, Access access) { @@ -861,7 +885,7 @@ public class Question { Result<List<CredDAO.Data>> result; TimeTaken tt = trans.start("Read DB Cred", Env.REMOTE); try { - result = credDAO.readID(trans, user); + result = credDAO.readIDBAth(trans, user); } finally { tt.done(); } 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<REQ,CERT,ARTIFACTS,ERROR> extends org.onap.aaf. private Mapper<REQ, CERT, ARTIFACTS, ERROR> mapper; // private Slot sCertAuth; private final String voidResp; + public FacadeImpl(AAF_CM certman, CMService service, Mapper<REQ,CERT,ARTIFACTS,ERROR> mapper, 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 <ns>.certman|<ca name>|"+IGNORE_IPS); - } + try { + max_509s = Integer.parseInt(trans.env().getProperty(MAX_X509S_TAG,Integer.toString(MAX_X509s))); + } catch (Exception e) { + trans.env().log(e, ""); + max_509s = MAX_X509s; + } + limitOverridePerm = new AAFPermission(Define.ROOT_NS(),"certman","quantity","override"); + allowIgnoreIPs = Boolean.valueOf(certman.access.getProperty(Config.CM_ALLOW_IGNORE_IPS, "false")); + if(allowIgnoreIPs) { + trans.env().access().log(Level.INIT, "Allowing DNS Evaluation to be turned off with <ns>.certman|<ca name>|"+IGNORE_IPS); } } public Result<CertResp> requestCert(final AuthzTrans trans, final Result<CertReq> req, final CA ca) { if (req.isOK()) { - if (req.value.fqdns.isEmpty()) { return Result.err(Result.ERR_BadData, "No Machines passed in Request"); } @@ -138,7 +148,31 @@ public class CMService { } List<String> notes = null; - List<String> fqdns = new ArrayList<>(req.value.fqdns); + List<String> fqdns; + boolean domain_based = false; + boolean dynamic_sans = false; + + if(req.value.fqdns.isEmpty()) { + fqdns = new ArrayList<>(); + } else { + // Only Template or Dynamic permitted to pass in FQDNs + if (req.value.fqdns.get(0).startsWith("*")) { // Domain set + if (trans.fish(new AAFPermission(null,ca.getPermType(), ca.getName(), DOMAIN))) { + domain_based = true; + } else { + return Result.err(Result.ERR_Denied, + "Domain based Authorizations (" + req.value.fqdns.get(0) + ") requires Exception"); + } + } else { + if(trans.fish(new AAFPermission(null, ca.getPermType(), ca.getName(),DYNAMIC_SANS))) { + dynamic_sans = true; + } else { + return Result.err(Result.ERR_Denied, + "Dynamic SANs for (" + req.value.mechid + ") requires Permission"); + } + } + fqdns = new ArrayList<>(req.value.fqdns); + } String email = null; @@ -146,9 +180,7 @@ public class CMService { Organization org = trans.org(); boolean ignoreIPs; - if(alwaysIgnoreIPs) { - ignoreIPs=true; - } else if(allowIgnoreIPs) { + if(allowIgnoreIPs) { ignoreIPs = trans.fish(new AAFPermission(mechNS,CERTMAN, ca.getName(), IGNORE_IPS)); } else { ignoreIPs = false; @@ -157,33 +189,30 @@ public class CMService { InetAddress primary = null; // Organize incoming information to get to appropriate Artifact - if (!fqdns.isEmpty()) { + if (!fqdns.isEmpty()) { // Passed in FQDNS, validated above // Accept domain wild cards, but turn into real machines // Need *domain.com:real.machine.domain.com:san.machine.domain.com:... - if (fqdns.get(0).startsWith("*")) { // Domain set - if (!trans.fish(new AAFPermission(null,ca.getPermType(), ca.getName(), DOMAIN))) { - return Result.err(Result.ERR_Denied, - "Domain based Authorizations (" + fqdns.get(0) + ") requires Exception"); - } - + if (domain_based) { // Domain set // check for Permission in Add Artifact? - String domain = fqdns.get(0).substring(1); + String domain = fqdns.get(0).substring(1); // starts with *, see above fqdns.remove(0); if (fqdns.isEmpty()) { - return Result.err(Result.ERR_Denied, "Requests using domain require machine declaration"); + return Result.err(Result.ERR_Denied, + "Requests using domain require machine declaration"); } if (!ignoreIPs) { InetAddress ia = InetAddress.getByName(fqdns.get(0)); if (ia == null) { return Result.err(Result.ERR_Denied, - "Request not made from matching IP matching domain"); + "Request not made from matching IP matching domain"); } else if (ia.getHostName().endsWith(domain)) { primary = ia; } } } else { + // Passed in FQDNs, but not starting with * if (!ignoreIPs) { for (String cn : req.value.fqdns) { try { @@ -211,7 +240,7 @@ public class CMService { if (ignoreIPs) { host = req.value.fqdns.get(0); } else if (primary == null) { - return Result.err(Result.ERR_Denied, "Request not made from matching IP (%s)", trans.ip()); + return Result.err(Result.ERR_Denied, "Request not made from matching IP (%s)", req.value.fqdns.get(0)); } else { String thost = primary.getHostName(); host = thost==null?primary.getHostAddress():thost; @@ -220,35 +249,42 @@ public class CMService { ArtiDAO.Data add = null; Result<List<ArtiDAO.Data>> ra = artiDAO.read(trans, req.value.mechid, host); if (ra.isOKhasData()) { - if (add == null) { - add = ra.value.get(0); // single key + add = ra.value.get(0); // single key + if(dynamic_sans && (add.sans!=null && !add.sans.isEmpty())) { // do not allow both Dynamic and Artifact SANS + return Result.err(Result.ERR_Denied,"Authorization must not include SANS when doing Dynamic SANS (%s, %s)", req.value.mechid, key); } } else { - ra = artiDAO.read(trans, req.value.mechid, key); - if (ra.isOKhasData()) { // is the Template available? - add = ra.value.get(0); - add.machine = host; - for (String s : fqdns) { - if (!s.equals(add.machine)) { - add.sans(true).add(s); - } - } - Result<ArtiDAO.Data> rc = artiDAO.create(trans, add); // Create new Artifact from Template - if (rc.notOK()) { - return Result.err(rc); - } - } else { - add = ra.value.get(0); - } + if(domain_based) { + ra = artiDAO.read(trans, req.value.mechid, key); + if (ra.isOKhasData()) { // is the Template available? + add = ra.value.get(0); + add.machine = host; + for (String s : fqdns) { + if (!s.equals(add.machine)) { + add.sans(true).add(s); + } + } + Result<ArtiDAO.Data> rc = artiDAO.create(trans, add); // Create new Artifact from Template + if (rc.notOK()) { + return Result.err(rc); + } + } else { + return Result.err(Result.ERR_Denied,"No Authorization Template for %s, %s", req.value.mechid, key); + } + } else { + return Result.err(Result.ERR_Denied,"No Authorization found for %s, %s", req.value.mechid, key); + } } // Add Artifact listed FQDNs - if (add.sans != null) { - for (String s : add.sans) { - if (!fqdns.contains(s)) { - fqdns.add(s); - } - } + if(!dynamic_sans) { + if (add.sans != null) { + for (String s : add.sans) { + if (!fqdns.contains(s)) { + fqdns.add(s); + } + } + } } // Policy 2: If Config marked as Expired, do not create or renew @@ -318,6 +354,31 @@ public class CMService { try { csrMeta = BCFactory.createCSRMeta(ca, req.value.mechid, email, fqdns); csrMeta.environment(ca.getEnv()); + + // Before creating, make sure they don't have too many + if(!trans.fish(limitOverridePerm)) { + Result<List<CertDAO.Data>> existing = certDAO.readID(trans, req.value.mechid); + if(existing.isOK()) { + String cn = "CN=" + csrMeta.cn(); + int count = 0; + Date now = new Date(); + for (CertDAO.Data cdd : existing.value) { + Collection<? extends Certificate> certs = Factory.toX509Certificate(cdd.x509); + for(Iterator<? extends Certificate> iter = certs.iterator(); iter.hasNext();) { + X509Certificate x509 = (X509Certificate)iter.next(); + if(x509.getNotAfter().after(now) && x509.getSubjectDN().getName().contains(cn)) { + if(++count>MAX_X509s) { + break; + } + } + } + } + if(count>max_509s) { + return Result.err(Result.ERR_Denied, "There are too many Certificates generated for " + cn + " for " + req.value.mechid); + } + } + } + // Here is where we send off to CA for Signing. X509andChain x509ac = ca.sign(trans, csrMeta); if (x509ac == null) { return Result.err(Result.ERR_ActionNotCompleted, "x509 Certificate not signed by CA"); @@ -331,6 +392,7 @@ public class CMService { cdd.id = req.value.mechid; cdd.x500 = x509.getSubjectDN().getName(); cdd.x509 = Factory.toString(trans, x509); + certDAO.create(trans, cdd); CredDAO.Data crdd = new CredDAO.Data(); @@ -340,7 +402,7 @@ public class CMService { crdd.id = req.value.mechid; crdd.ns = Question.domain2ns(crdd.id); crdd.type = CredDAO.CERT_SHA256_RSA; - crdd.tag = cdd.serial.toString(16); + crdd.tag = cdd.ca + '|' + cdd.serial.toString(); credDAO.create(trans, crdd); CertResp cr = new CertResp(trans, ca, x509, csrMeta, x509ac.getTrustChain(), compileNotes(notes)); @@ -716,4 +778,4 @@ public class CMService { byte[] hash = Hash.hashSHA256(bb.array()); return ByteBuffer.wrap(hash); } -}
\ No newline at end of file +} 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<AuthzTrans,Facade1_0> implements Cloneable { public Code(AAF_CM cma, String description, String ... roles) { - super(cma.facade1_0, description, roles); + super(AAF_CM.facade1_0, description, roles); // Note, the first "Code" will be created with default Facade, "JSON". // use clone for another Code with XML } 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 <Return> to continue..."); ++idx; // Sonar insists we do something with the string, though it's only a pause. Not very helpful... - String sonar = new BufferedReader(new InputStreamReader(System.in)).readLine(); + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + String sonar; + try { + sonar = br.readLine(); + } finally { + br.close(); + } sonar=""; // this useless code brought to you by Sonar. pw.print(sonar); continue; @@ -569,12 +575,16 @@ public class AAFcli { } } else if (rdr != null) { BufferedReader br = new BufferedReader(rdr); - String line; - while ((line = br.readLine()) != null) { - if (!aafcli.eval(line) && exitOnFailure) { - rv = 1; - break; + try { + String line; + while ((line = br.readLine()) != null) { + if (!aafcli.eval(line) && exitOnFailure) { + rv = 1; + break; + } } + } finally { + br.close(); } } else { // just run the command line aafcli.verbose(false); 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<PermRequest> fp = client.update( - "/authz/perm/"+origType+"/"+origInstance+"/"+origAction, - getDF(PermRequest.class), - pr - ); - int rv; - if (fp.get(AAFcli.timeout())) { - rv = fp.code(); - pw().println("Updated Permission"); - } else { - rv = fp.code(); - if (rv==202) { - pw().println("Permission Update Accepted, but requires Approvals before actualizing"); + try { + Future<PermRequest> fp = client.update( + "/authz/perm/"+ + origType+ '/' + + URLEncoder.encode(origInstance,Config.UTF_8) + '/' + + origAction, + getDF(PermRequest.class), + pr + ); + int rv; + if (fp.get(AAFcli.timeout())) { + rv = fp.code(); + pw().println("Updated Permission"); } else { - error(fp); + rv = fp.code(); + if (rv==202) { + pw().println("Permission Update Accepted, but requires Approvals before actualizing"); + } else { + error(fp); + } } + return rv; + } catch (UnsupportedEncodingException e) { + throw new CadiException(e); } - return rv; } }); 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<Roles> fp = client.read( - "/authz/roles/perm/"+type+'/'+instance+'/'+action, - getDF(Roles.class) - ); - return list(fp,client, HEADER+type+'|'+instance+'|'+action); + try { + Future<Roles> fp = client.read( + "/authz/roles/perm/"+type+'/' + + URLEncoder.encode(instance,Config.UTF_8)+'/'+ + action, + getDF(Roles.class) + ); + return list(fp,client, HEADER+type+'|'+instance+'|'+action); + } catch (UnsupportedEncodingException e) { + throw new CadiException(e); + } } }); } 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<Users> fp = client.read( - "/authz/users/perm/"+type+'/'+instance+'/'+action, - getDF(Users.class) - ); - if (fp.get(AAFcli.timeout())) { - if (aafcli.isTest()) - Collections.sort(fp.value.getUser(), (Comparator<User>) (u1, u2) -> u1.getId().compareTo(u2.getId())); - ((org.onap.aaf.auth.cmd.user.List)parent).report(fp.value,false,HEADER,type+"|"+instance+"|"+action); - if (fp.code()==404)return 200; - } else { - error(fp); + try { + Future<Users> fp = client.read( + "/authz/users/perm/" + + type + '/' + + URLEncoder.encode(instance,Config.UTF_8) + '/' + + action, + getDF(Users.class) + ); + if (fp.get(AAFcli.timeout())) { + if (aafcli.isTest()) + Collections.sort(fp.value.getUser(), (Comparator<User>) (u1, u2) -> u1.getId().compareTo(u2.getId())); + ((org.onap.aaf.auth.cmd.user.List)parent).report(fp.value,false,HEADER,type+"|"+instance+"|"+action); + if (fp.code()==404)return 200; + } else { + error(fp); + } + return fp.code(); + } catch (UnsupportedEncodingException e) { + throw new CadiException(e); } - return fp.code(); } }); } 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 @@ -177,6 +177,11 @@ public class AuthzTransImpl extends BasicTrans implements AuthzTrans { } @Override + public Lur getLur() { + return lur; + } + + @Override public boolean fish(Permission ... pond) { if (lur!=null) { return lur.fish(user, pond); 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 @@ -208,6 +208,11 @@ public class NullTrans implements AuthzTrans { } @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<String> ls = getThemeFiles(trans, theme); + if(ls==null) { + throw new APIException("Theme " + theme + " does not exist."); + } Cookie cookie = new Cookie(AAF_GUI_THEME,theme); cookie.setMaxAge(604_800); // one week trans.hresp().addCookie(cookie); 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<Void> r = context.renamePerm(trans, req, resp, pathParam(req, "type"), - pathParam(req, "instance"), pathParam(req, "action")); + Result<Void> r = context.renamePerm(trans, req, resp, + pathParam(req, "type"), + URLDecoder.decode(pathParam(req, "instance"),Config.UTF_8), + pathParam(req, "action")); switch(r.status) { case OK: resp.setStatus(HttpStatus.OK_200); 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<Void> r = context.getRolesByPerm(trans, resp, pathParam(req, "type"), - pathParam(req, "instance"), + URLDecoder.decode(pathParam(req, "instance"),Config.UTF_8), pathParam(req, "action")); switch(r.status) { case OK: 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<Void> r = context.getUsersByPermission(trans, resp, pathParam(req, ":type"), - pathParam(req, ":instance"), + URLDecoder.decode(pathParam(req, ":instance"),Config.UTF_8), pathParam(req, ":action")); switch(r.status) { case OK: 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<CredDAO.Data> result = mapper.cred(transaction, createCredRequest(id, password), true); + Result<CredDAO.Data> result = mapper.cred(transaction, createCredRequest(id, strp), true); //then assertFalse(result.isOK()); @@ -698,13 +697,13 @@ public class JU_Mapper_2_0 { //given String ns = "org.osaaf.aaf"; String id = "aaf@aaf.osaaf.org"; - String password = "SomeValidPassword123!"; + String strp = "SomeValidPassword123!"; GregorianCalendar expiration = new GregorianCalendar(); given(org.expiration(isA(GregorianCalendar.class), eq(Expiration.Password), eq(id))).willReturn(expiration); - given(org.isValidPassword(transaction, id, password)).willReturn(""); + given(org.isValidPassword(transaction, id, strp)).willReturn(""); //when - Result<CredDAO.Data> result = mapper.cred(transaction, createCredRequest(id, password), true); + Result<CredDAO.Data> result = mapper.cred(transaction, createCredRequest(id, strp), true); //then assertTrue(result.isOK()); @@ -939,6 +938,7 @@ public class JU_Mapper_2_0 { * */ public static class ImmutableMap { + @SuppressWarnings("unchecked") public static <T,U> Map<T,U> of(Object ... tag_value) { Map<T,U> rv = new HashMap<>(); for(int i=0;i<tag_value.length-1;i+=2) { @@ -970,7 +970,7 @@ public class JU_Mapper_2_0 { * */ public static class Lists { - @SuppressWarnings("unchecked") + @SafeVarargs public static <T> List<T> newArrayList(Collection<T> ... init ) { List<T> rv = new ArrayList<>(); for(Collection<T> o : init) { |