X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=auth%2Fauth-service%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Faaf%2Fauth%2Fservice%2FAuthzCassServiceImpl.java;h=c3e92df49135e9b5b63c938e12b804a07c9f26f0;hb=4b5a7d721d994a49057e9bfb403c7bff1b376660;hp=668d482c66d59d4003eaae168c80c0fb7a6f9731;hpb=824dc7b5fc0e1ccdf7f460479aff344727f0f01e;p=aaf%2Fauthz.git diff --git a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzCassServiceImpl.java b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzCassServiceImpl.java index 668d482c..c3e92df4 100644 --- a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzCassServiceImpl.java +++ b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzCassServiceImpl.java @@ -107,1160 +107,1160 @@ import aaf.v2_0.CredRequest; * @param * @param */ -public class AuthzCassServiceImpl - implements AuthzService { - - private Mapper mapper; - @Override - public Mapper mapper() {return mapper;} - - private static final String ASTERIX = "*"; - private static final String CACHE = "cache"; - private static final String ROOT_NS = Define.ROOT_NS(); - private static final String ROOT_COMPANY = Define.ROOT_COMPANY(); - - private final Question ques; - private final Function func; - - public AuthzCassServiceImpl(AuthzTrans trans, Mapper mapper,Question question) { - this.ques = question; - func = new Function(trans, question); - this.mapper = mapper; - - } +public class AuthzCassServiceImpl + implements AuthzService { + + private Mapper mapper; + @Override + public Mapper mapper() {return mapper;} + + private static final String ASTERIX = "*"; + private static final String CACHE = "cache"; + private static final String ROOT_NS = Define.ROOT_NS(); + private static final String ROOT_COMPANY = Define.ROOT_COMPANY(); + + private final Question ques; + private final Function func; + + public AuthzCassServiceImpl(AuthzTrans trans, Mapper mapper,Question question) { + this.ques = question; + func = new Function(trans, question); + this.mapper = mapper; + + } /*********************************** * NAMESPACE ***********************************/ - /** - * createNS - * @throws DAOException - * @see org.onap.aaf.auth.service.AuthzService#createNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String) - */ - @ApiDoc( - method = POST, - path = "/authz/ns", - params = {}, - expectedCode = 201, - errorCodes = { 403,404,406,409 }, - text = { "Namespace consists of: ", - "
  • name - What you want to call this Namespace
  • ", - "
  • responsible(s) - Person(s) who receive Notifications and approves Requests ", - "regarding this Namespace. Companies have Policies as to who may take on ", - "this Responsibility. Separate multiple identities with commas
  • ", - "
  • admin(s) - Person(s) who are allowed to make changes on the namespace, ", - "including creating Roles, Permissions and Credentials. Separate multiple ", - "identities with commas
", - "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ", - "created with parent credentials (i.e. To create com.myCompany.myApp, you must ", - "be an admin of com.myCompany or com" - } - ) - @Override - public Result createNS(final AuthzTrans trans, REQUEST from, NsType type) { - final Result rnamespace = mapper.ns(trans, from); - final ServiceValidator v = new ServiceValidator(); - if(v.ns(rnamespace).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - final Namespace namespace = rnamespace.value; - final Result parentNs = ques.deriveNs(trans,namespace.name); - if(parentNs.notOK()) { - return Result.err(parentNs); - } - - if(namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed - return func.createNS(trans, namespace, false); - } - - Result fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true, - new Mapper.Memo() { - @Override - public String get() { - return "Create Namespace [" + namespace.name + ']'; - } - }, - new MayChange() { - private Result rnd; - @Override - public Result mayChange() { - if(rnd==null) { - rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write); - } - return rnd; - } - }); - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - return func.createNS(trans, namespace, false); - default: - return Result.err(fd); - } - } - - @ApiDoc( - method = POST, - path = "/authz/ns/:ns/admin/:id", - params = { "ns|string|true", - "id|string|true" - }, - expectedCode = 201, - errorCodes = { 403,404,406,409 }, - text = { "Add an Identity :id to the list of Admins for the Namespace :ns", - "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" } - ) - @Override - public Result addAdminNS(AuthzTrans trans, String ns, String id) { - return func.addUserRole(trans, id, ns,Question.ADMIN); - } - - @ApiDoc( - method = DELETE, - path = "/authz/ns/:ns/admin/:id", - params = { "ns|string|true", - "id|string|true" - }, - expectedCode = 200, - errorCodes = { 403,404 }, - text = { "Remove an Identity :id from the list of Admins for the Namespace :ns", - "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" } - ) - @Override - public Result delAdminNS(AuthzTrans trans, String ns, String id) { - return func.delAdmin(trans,ns,id); - } - - @ApiDoc( - method = POST, - path = "/authz/ns/:ns/responsible/:id", - params = { "ns|string|true", - "id|string|true" - }, - expectedCode = 201, - errorCodes = { 403,404,406,409 }, - text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns", - "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" } - ) - @Override - public Result addResponsibleNS(AuthzTrans trans, String ns, String id) { - return func.addUserRole(trans,id,ns,Question.OWNER); - } - - @ApiDoc( - method = DELETE, - path = "/authz/ns/:ns/responsible/:id", - params = { "ns|string|true", - "id|string|true" - }, - expectedCode = 200, - errorCodes = { 403,404 }, - text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns", - "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)", - "Note: A namespace must have at least 1 responsible party" - } - ) - @Override - public Result delResponsibleNS(AuthzTrans trans, String ns, String id) { - return func.delOwner(trans,ns,id); - } - - /* (non-Javadoc) - * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) - */ - @ApiDoc( - method = POST, - path = "/authz/ns/:ns/attrib/:key/:value", - params = { "ns|string|true", - "key|string|true", - "value|string|true"}, - expectedCode = 201, - errorCodes = { 403,404,406,409 }, - text = { - "Create an attribute in the Namespace", - "You must be given direct permission for key by AAF" - } - ) - @Override - public Result createNsAttrib(AuthzTrans trans, String ns, String key, String value) { - TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB); - try { - // Check inputs - final Validator v = new ServiceValidator(); - if(v.ns(ns).err() || - v.key(key).err() || - v.value(value).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // Check if exists already - Result> rlnsd = ques.nsDAO.read(trans, ns); - if(rlnsd.notOKorIsEmpty()) { - return Result.err(rlnsd); - } - NsDAO.Data nsd = rlnsd.value.get(0); - - // Check for Existence - if(nsd.attrib.get(key)!=null) { - return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key); - } - - // Check if User may put - if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB, - ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) { - return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key); - } - - // Add Attrib - nsd.attrib.put(key, value); - ques.nsDAO.dao().attribAdd(trans,ns,key,value); - return Result.ok(); - } finally { - tt.done(); - } - } - - @ApiDoc( - method = GET, - path = "/authz/ns/attrib/:key", - params = { "key|string|true" }, - expectedCode = 200, - errorCodes = { 403,404 }, - text = { - "Read Attributes for Namespace" - } - ) - @Override - public Result readNsByAttrib(AuthzTrans trans, String key) { - // Check inputs - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Key",key).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // May Read - if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB, - ":"+trans.org().getDomain()+".*:"+key, Question.READ)) { - return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key); - } - - Result> rsd = ques.nsDAO.dao().readNsByAttrib(trans, key); - if(rsd.notOK()) { - return Result.err(rsd); - } - return mapper().keys(rsd.value); - } - - - @ApiDoc( - method = PUT, - path = "/authz/ns/:ns/attrib/:key/:value", - params = { "ns|string|true", - "key|string|true"}, - expectedCode = 200, - errorCodes = { 403,404 }, - text = { - "Update Value on an existing attribute in the Namespace", - "You must be given direct permission for key by AAF" - } - ) - @Override - public Result updateNsAttrib(AuthzTrans trans, String ns, String key, String value) { - TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB); - try { - // Check inputs - final Validator v = new ServiceValidator(); - if(v.ns(ns).err() || - v.key(key).err() || - v.value(value).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // Check if exists already (NS must exist) - Result> rlnsd = ques.nsDAO.read(trans, ns); - if(rlnsd.notOKorIsEmpty()) { - return Result.err(rlnsd); - } - NsDAO.Data nsd = rlnsd.value.get(0); - - // Check for Existence - if(nsd.attrib.get(key)==null) { - return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key); - } - - // Check if User may put - if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB, - ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) { - return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key); - } - - // Add Attrib - nsd.attrib.put(key, value); - - return ques.nsDAO.update(trans,nsd); + /** + * createNS + * @throws DAOException + * @see org.onap.aaf.auth.service.AuthzService#createNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String) + */ + @ApiDoc( + method = POST, + path = "/authz/ns", + params = {}, + expectedCode = 201, + errorCodes = { 403,404,406,409 }, + text = { "Namespace consists of: ", + "
  • name - What you want to call this Namespace
  • ", + "
  • responsible(s) - Person(s) who receive Notifications and approves Requests ", + "regarding this Namespace. Companies have Policies as to who may take on ", + "this Responsibility. Separate multiple identities with commas
  • ", + "
  • admin(s) - Person(s) who are allowed to make changes on the namespace, ", + "including creating Roles, Permissions and Credentials. Separate multiple ", + "identities with commas
", + "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ", + "created with parent credentials (i.e. To create com.myCompany.myApp, you must ", + "be an admin of com.myCompany or com" + } + ) + @Override + public Result createNS(final AuthzTrans trans, REQUEST from, NsType type) { + final Result rnamespace = mapper.ns(trans, from); + final ServiceValidator v = new ServiceValidator(); + if(v.ns(rnamespace).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + final Namespace namespace = rnamespace.value; + final Result parentNs = ques.deriveNs(trans,namespace.name); + if(parentNs.notOK()) { + return Result.err(parentNs); + } + + if(namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed + return func.createNS(trans, namespace, false); + } + + Result fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true, + new Mapper.Memo() { + @Override + public String get() { + return "Create Namespace [" + namespace.name + ']'; + } + }, + new MayChange() { + private Result rnd; + @Override + public Result mayChange() { + if(rnd==null) { + rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write); + } + return rnd; + } + }); + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + return func.createNS(trans, namespace, false); + default: + return Result.err(fd); + } + } + + @ApiDoc( + method = POST, + path = "/authz/ns/:ns/admin/:id", + params = { "ns|string|true", + "id|string|true" + }, + expectedCode = 201, + errorCodes = { 403,404,406,409 }, + text = { "Add an Identity :id to the list of Admins for the Namespace :ns", + "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" } + ) + @Override + public Result addAdminNS(AuthzTrans trans, String ns, String id) { + return func.addUserRole(trans, id, ns,Question.ADMIN); + } + + @ApiDoc( + method = DELETE, + path = "/authz/ns/:ns/admin/:id", + params = { "ns|string|true", + "id|string|true" + }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Remove an Identity :id from the list of Admins for the Namespace :ns", + "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" } + ) + @Override + public Result delAdminNS(AuthzTrans trans, String ns, String id) { + return func.delAdmin(trans,ns,id); + } + + @ApiDoc( + method = POST, + path = "/authz/ns/:ns/responsible/:id", + params = { "ns|string|true", + "id|string|true" + }, + expectedCode = 201, + errorCodes = { 403,404,406,409 }, + text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns", + "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" } + ) + @Override + public Result addResponsibleNS(AuthzTrans trans, String ns, String id) { + return func.addUserRole(trans,id,ns,Question.OWNER); + } + + @ApiDoc( + method = DELETE, + path = "/authz/ns/:ns/responsible/:id", + params = { "ns|string|true", + "id|string|true" + }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns", + "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)", + "Note: A namespace must have at least 1 responsible party" + } + ) + @Override + public Result delResponsibleNS(AuthzTrans trans, String ns, String id) { + return func.delOwner(trans,ns,id); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @ApiDoc( + method = POST, + path = "/authz/ns/:ns/attrib/:key/:value", + params = { "ns|string|true", + "key|string|true", + "value|string|true"}, + expectedCode = 201, + errorCodes = { 403,404,406,409 }, + text = { + "Create an attribute in the Namespace", + "You must be given direct permission for key by AAF" + } + ) + @Override + public Result createNsAttrib(AuthzTrans trans, String ns, String key, String value) { + TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB); + try { + // Check inputs + final Validator v = new ServiceValidator(); + if(v.ns(ns).err() || + v.key(key).err() || + v.value(value).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // Check if exists already + Result> rlnsd = ques.nsDAO.read(trans, ns); + if(rlnsd.notOKorIsEmpty()) { + return Result.err(rlnsd); + } + NsDAO.Data nsd = rlnsd.value.get(0); + + // Check for Existence + if(nsd.attrib.get(key)!=null) { + return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key); + } + + // Check if User may put + if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB, + ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) { + return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key); + } + + // Add Attrib + nsd.attrib.put(key, value); + ques.nsDAO.dao().attribAdd(trans,ns,key,value); + return Result.ok(); + } finally { + tt.done(); + } + } + + @ApiDoc( + method = GET, + path = "/authz/ns/attrib/:key", + params = { "key|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { + "Read Attributes for Namespace" + } + ) + @Override + public Result readNsByAttrib(AuthzTrans trans, String key) { + // Check inputs + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Key",key).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // May Read + if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB, + ":"+trans.org().getDomain()+".*:"+key, Question.READ)) { + return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key); + } + + Result> rsd = ques.nsDAO.dao().readNsByAttrib(trans, key); + if(rsd.notOK()) { + return Result.err(rsd); + } + return mapper().keys(rsd.value); + } + + + @ApiDoc( + method = PUT, + path = "/authz/ns/:ns/attrib/:key/:value", + params = { "ns|string|true", + "key|string|true"}, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { + "Update Value on an existing attribute in the Namespace", + "You must be given direct permission for key by AAF" + } + ) + @Override + public Result updateNsAttrib(AuthzTrans trans, String ns, String key, String value) { + TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB); + try { + // Check inputs + final Validator v = new ServiceValidator(); + if(v.ns(ns).err() || + v.key(key).err() || + v.value(value).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // Check if exists already (NS must exist) + Result> rlnsd = ques.nsDAO.read(trans, ns); + if(rlnsd.notOKorIsEmpty()) { + return Result.err(rlnsd); + } + NsDAO.Data nsd = rlnsd.value.get(0); + + // Check for Existence + if(nsd.attrib.get(key)==null) { + return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key); + } + + // Check if User may put + if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB, + ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) { + return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key); + } + + // Add Attrib + nsd.attrib.put(key, value); + + return ques.nsDAO.update(trans,nsd); - } finally { - tt.done(); - } - } - - @ApiDoc( - method = DELETE, - path = "/authz/ns/:ns/attrib/:key", - params = { "ns|string|true", - "key|string|true"}, - expectedCode = 200, - errorCodes = { 403,404 }, - text = { - "Delete an attribute in the Namespace", - "You must be given direct permission for key by AAF" - } - ) - @Override - public Result deleteNsAttrib(AuthzTrans trans, String ns, String key) { - TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB); - try { - // Check inputs - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("NS",ns).err() || - v.nullOrBlank("Key",key).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // Check if exists already - Result> rlnsd = ques.nsDAO.read(trans, ns); - if(rlnsd.notOKorIsEmpty()) { - return Result.err(rlnsd); - } - NsDAO.Data nsd = rlnsd.value.get(0); - - // Check for Existence - if(nsd.attrib.get(key)==null) { - return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key); - } - - // Check if User may del - if(!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) { - return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key); - } - - // Add Attrib - nsd.attrib.remove(key); - ques.nsDAO.dao().attribRemove(trans,ns,key); - return Result.ok(); - } finally { - tt.done(); - } - } - - @ApiDoc( - method = GET, - path = "/authz/nss/:id", - params = { "id|string|true" }, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { - "Lists the Admin(s), Responsible Party(s), Role(s), Permission(s)", - "Credential(s) and Expiration of Credential(s) in Namespace :id", - } - ) - @Override - public Result getNSbyName(AuthzTrans trans, String ns) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("NS", ns).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result> rlnd = ques.nsDAO.read(trans, ns); - if(rlnd.isOK()) { - if(rlnd.isEmpty()) { - return Result.err(Status.ERR_NotFound, "No data found for %s",ns); - } - Result rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - - - Namespace namespace = new Namespace(rnd.value); - Result> rd = func.getOwners(trans, namespace.name, false); - if(rd.isOK()) { - namespace.owner = rd.value; - } - rd = func.getAdmins(trans, namespace.name, false); - if(rd.isOK()) { - namespace.admin = rd.value; - } - - NSS nss = mapper.newInstance(API.NSS); - return mapper.nss(trans, namespace, nss); - } else { - return Result.err(rlnd); - } - } - - @ApiDoc( - method = GET, - path = "/authz/nss/admin/:id", - params = { "id|string|true" }, - expectedCode = 200, - errorCodes = { 403,404 }, - text = { "Lists all Namespaces where Identity :id is an Admin", - "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" - } - ) - @Override - public Result getNSbyAdmin(AuthzTrans trans, String user, boolean full) { - final Validator v = new ServiceValidator(); - if (v.nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData, v.errs()); - } - - Result> rn = loadNamepace(trans, user, ".admin", full); - if(rn.notOK()) { - return Result.err(rn); - } - if (rn.isEmpty()) { - return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user); - } - NSS nss = mapper.newInstance(API.NSS); - // Note: "loadNamespace" already validates view of Namespace - return mapper.nss(trans, rn.value, nss); - } - - @ApiDoc( - method = GET, - path = "/authz/nss/either/:id", - params = { "id|string|true" }, - expectedCode = 200, - errorCodes = { 403,404 }, - text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner", - "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" - } - ) - @Override - public Result getNSbyEither(AuthzTrans trans, String user, boolean full) { - final Validator v = new ServiceValidator(); - if (v.nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData, v.errs()); - } - - Result> rn = loadNamepace(trans, user, null, full); - if(rn.notOK()) { - return Result.err(rn); - } - if (rn.isEmpty()) { - return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user); - } - NSS nss = mapper.newInstance(API.NSS); - // Note: "loadNamespace" already validates view of Namespace - return mapper.nss(trans, rn.value, nss); - } - - private Result> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) { - Result> urd = ques.userRoleDAO.readByUser(trans, user); - if(urd.notOKorIsEmpty()) { - return Result.err(urd); - } - Map lm = new HashMap<>(); - Map other = full || endsWith==null?null:new TreeMap<>(); - for(UserRoleDAO.Data urdd : urd.value) { - if(full) { - if(endsWith==null || urdd.role.endsWith(endsWith)) { - RoleDAO.Data rd = RoleDAO.Data.decode(urdd); - Result nsd = ques.mayUser(trans, user, rd, Access.read); - if(nsd.isOK()) { - Namespace namespace = lm.get(nsd.value.name); - if(namespace==null) { - namespace = new Namespace(nsd.value); - lm.put(namespace.name,namespace); - } - Result> rls = func.getAdmins(trans, namespace.name, false); - if(rls.isOK()) { - namespace.admin=rls.value; - } - - rls = func.getOwners(trans, namespace.name, false); - if(rls.isOK()) { - namespace.owner=rls.value; - } - } - } - } else { // Shortened version. Only Namespace Info available from Role. - if(Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) { - RoleDAO.Data rd = RoleDAO.Data.decode(urdd); - Result nsd = ques.mayUser(trans, user, rd, Access.read); - if(nsd.isOK()) { - Namespace namespace = lm.get(nsd.value.name); - if(namespace==null) { - if(other!=null) { - namespace = other.remove(nsd.value.name); - } - if(namespace==null) { - namespace = new Namespace(nsd.value); - namespace.admin=new ArrayList<>(); - namespace.owner=new ArrayList<>(); - } - if(endsWith==null || urdd.role.endsWith(endsWith)) { - lm.put(namespace.name,namespace); - } else { - other.put(namespace.name,namespace); - } - } - if(Question.OWNER.equals(urdd.rname)) { - namespace.owner.add(urdd.user); - } else { - namespace.admin.add(urdd.user); - } - } - } - } - } - return Result.ok(lm.values()); - } - - @ApiDoc( - method = GET, - path = "/authz/nss/responsible/:id", - params = { "id|string|true" }, - expectedCode = 200, - errorCodes = { 403,404 }, - text = { "Lists all Namespaces where Identity :id is a Responsible Party", - "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" - } - ) - @Override - public Result getNSbyResponsible(AuthzTrans trans, String user, boolean full) { - final Validator v = new ServiceValidator(); - if (v.nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData, v.errs()); - } - Result> rn = loadNamepace(trans, user, ".owner",full); - if(rn.notOK()) { - return Result.err(rn); - } - if (rn.isEmpty()) { - return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user); - } - NSS nss = mapper.newInstance(API.NSS); - // Note: "loadNamespace" prevalidates - return mapper.nss(trans, rn.value, nss); - } - - @ApiDoc( - method = GET, - path = "/authz/nss/children/:id", - params = { "id|string|true" }, - expectedCode = 200, - errorCodes = { 403,404 }, - text = { "Lists all Child Namespaces of Namespace :id", - "Note: This is not a cached read" - } - ) - @Override - public Result getNSsChildren(AuthzTrans trans, String parent) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("NS", parent).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result rnd = ques.deriveNs(trans, parent); - if(rnd.notOK()) { - return Result.err(rnd); - } - rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - - Set lm = new HashSet<>(); - Result> rlnd = ques.nsDAO.dao().getChildren(trans, parent); - if(rlnd.isOK()) { - if(rlnd.isEmpty()) { - return Result.err(Status.ERR_NotFound, "No data found for %s",parent); - } - for(NsDAO.Data ndd : rlnd.value) { - Namespace namespace = new Namespace(ndd); - Result> rls = func.getAdmins(trans, namespace.name, false); - if(rls.isOK()) { - namespace.admin=rls.value; - } - - rls = func.getOwners(trans, namespace.name, false); - if(rls.isOK()) { - namespace.owner=rls.value; - } - - lm.add(namespace); - } - NSS nss = mapper.newInstance(API.NSS); - return mapper.nss(trans,lm, nss); - } else { - return Result.err(rlnd); - } - } - - - @ApiDoc( - method = PUT, - path = "/authz/ns", - params = {}, - expectedCode = 200, - errorCodes = { 403,404,406 }, - text = { "Replace the Current Description of a Namespace with a new one" - } - ) - @Override - public Result updateNsDescription(AuthzTrans trans, REQUEST from) { - final Result nsd = mapper.ns(trans, from); - final ServiceValidator v = new ServiceValidator(); - if(v.ns(nsd).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - if(v.nullOrBlank("description", nsd.value.description).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Namespace namespace = nsd.value; - Result> rlnd = ques.nsDAO.read(trans, namespace.name); - - if(rlnd.notOKorIsEmpty()) { - return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name); - } - - if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) { - return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name); - } - - Result rdr = ques.nsDAO.dao().addDescription(trans, namespace.name, namespace.description); - if(rdr.isOK()) { - return Result.ok(); - } else { - return Result.err(rdr); - } - } - - /** - * deleteNS - * @throws DAOException - * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String) - */ - @ApiDoc( - method = DELETE, - path = "/authz/ns/:ns", - params = { "ns|string|true" }, - expectedCode = 200, - errorCodes = { 403,404,424 }, - text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ", - "are still credentials associated with them, but they can be deleted by setting ", - "the \"force\" property. To do this: Add 'force=true' as a query parameter", - "

WARNING: Using force will delete all credentials attached to this namespace. Use with care.

" - + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted," - + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted " - + "at or below Application Scope" - } - ) - @Override - public Result deleteNS(AuthzTrans trans, String ns) { - return func.deleteNS(trans, ns); - } + } finally { + tt.done(); + } + } + + @ApiDoc( + method = DELETE, + path = "/authz/ns/:ns/attrib/:key", + params = { "ns|string|true", + "key|string|true"}, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { + "Delete an attribute in the Namespace", + "You must be given direct permission for key by AAF" + } + ) + @Override + public Result deleteNsAttrib(AuthzTrans trans, String ns, String key) { + TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB); + try { + // Check inputs + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS",ns).err() || + v.nullOrBlank("Key",key).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // Check if exists already + Result> rlnsd = ques.nsDAO.read(trans, ns); + if(rlnsd.notOKorIsEmpty()) { + return Result.err(rlnsd); + } + NsDAO.Data nsd = rlnsd.value.get(0); + + // Check for Existence + if(nsd.attrib.get(key)==null) { + return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key); + } + + // Check if User may del + if(!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) { + return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key); + } + + // Add Attrib + nsd.attrib.remove(key); + ques.nsDAO.dao().attribRemove(trans,ns,key); + return Result.ok(); + } finally { + tt.done(); + } + } + + @ApiDoc( + method = GET, + path = "/authz/nss/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { + "Lists the Admin(s), Responsible Party(s), Role(s), Permission(s)", + "Credential(s) and Expiration of Credential(s) in Namespace :id", + } + ) + @Override + public Result getNSbyName(AuthzTrans trans, String ns) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS", ns).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlnd = ques.nsDAO.read(trans, ns); + if(rlnd.isOK()) { + if(rlnd.isEmpty()) { + return Result.err(Status.ERR_NotFound, "No data found for %s",ns); + } + Result rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + + Namespace namespace = new Namespace(rnd.value); + Result> rd = func.getOwners(trans, namespace.name, false); + if(rd.isOK()) { + namespace.owner = rd.value; + } + rd = func.getAdmins(trans, namespace.name, false); + if(rd.isOK()) { + namespace.admin = rd.value; + } + + NSS nss = mapper.newInstance(API.NSS); + return mapper.nss(trans, namespace, nss); + } else { + return Result.err(rlnd); + } + } + + @ApiDoc( + method = GET, + path = "/authz/nss/admin/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Lists all Namespaces where Identity :id is an Admin", + "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" + } + ) + @Override + public Result getNSbyAdmin(AuthzTrans trans, String user, boolean full) { + final Validator v = new ServiceValidator(); + if (v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData, v.errs()); + } + + Result> rn = loadNamepace(trans, user, ".admin", full); + if(rn.notOK()) { + return Result.err(rn); + } + if (rn.isEmpty()) { + return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user); + } + NSS nss = mapper.newInstance(API.NSS); + // Note: "loadNamespace" already validates view of Namespace + return mapper.nss(trans, rn.value, nss); + } + + @ApiDoc( + method = GET, + path = "/authz/nss/either/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner", + "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" + } + ) + @Override + public Result getNSbyEither(AuthzTrans trans, String user, boolean full) { + final Validator v = new ServiceValidator(); + if (v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData, v.errs()); + } + + Result> rn = loadNamepace(trans, user, null, full); + if(rn.notOK()) { + return Result.err(rn); + } + if (rn.isEmpty()) { + return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user); + } + NSS nss = mapper.newInstance(API.NSS); + // Note: "loadNamespace" already validates view of Namespace + return mapper.nss(trans, rn.value, nss); + } + + private Result> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) { + Result> urd = ques.userRoleDAO.readByUser(trans, user); + if(urd.notOKorIsEmpty()) { + return Result.err(urd); + } + Map lm = new HashMap<>(); + Map other = full || endsWith==null?null:new TreeMap<>(); + for(UserRoleDAO.Data urdd : urd.value) { + if(full) { + if(endsWith==null || urdd.role.endsWith(endsWith)) { + RoleDAO.Data rd = RoleDAO.Data.decode(urdd); + Result nsd = ques.mayUser(trans, user, rd, Access.read); + if(nsd.isOK()) { + Namespace namespace = lm.get(nsd.value.name); + if(namespace==null) { + namespace = new Namespace(nsd.value); + lm.put(namespace.name,namespace); + } + Result> rls = func.getAdmins(trans, namespace.name, false); + if(rls.isOK()) { + namespace.admin=rls.value; + } + + rls = func.getOwners(trans, namespace.name, false); + if(rls.isOK()) { + namespace.owner=rls.value; + } + } + } + } else { // Shortened version. Only Namespace Info available from Role. + if(Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) { + RoleDAO.Data rd = RoleDAO.Data.decode(urdd); + Result nsd = ques.mayUser(trans, user, rd, Access.read); + if(nsd.isOK()) { + Namespace namespace = lm.get(nsd.value.name); + if(namespace==null) { + if(other!=null) { + namespace = other.remove(nsd.value.name); + } + if(namespace==null) { + namespace = new Namespace(nsd.value); + namespace.admin=new ArrayList<>(); + namespace.owner=new ArrayList<>(); + } + if(endsWith==null || urdd.role.endsWith(endsWith)) { + lm.put(namespace.name,namespace); + } else { + other.put(namespace.name,namespace); + } + } + if(Question.OWNER.equals(urdd.rname)) { + namespace.owner.add(urdd.user); + } else { + namespace.admin.add(urdd.user); + } + } + } + } + } + return Result.ok(lm.values()); + } + + @ApiDoc( + method = GET, + path = "/authz/nss/responsible/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Lists all Namespaces where Identity :id is a Responsible Party", + "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" + } + ) + @Override + public Result getNSbyResponsible(AuthzTrans trans, String user, boolean full) { + final Validator v = new ServiceValidator(); + if (v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData, v.errs()); + } + Result> rn = loadNamepace(trans, user, ".owner",full); + if(rn.notOK()) { + return Result.err(rn); + } + if (rn.isEmpty()) { + return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user); + } + NSS nss = mapper.newInstance(API.NSS); + // Note: "loadNamespace" prevalidates + return mapper.nss(trans, rn.value, nss); + } + + @ApiDoc( + method = GET, + path = "/authz/nss/children/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Lists all Child Namespaces of Namespace :id", + "Note: This is not a cached read" + } + ) + @Override + public Result getNSsChildren(AuthzTrans trans, String parent) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS", parent).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rnd = ques.deriveNs(trans, parent); + if(rnd.notOK()) { + return Result.err(rnd); + } + rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + Set lm = new HashSet<>(); + Result> rlnd = ques.nsDAO.dao().getChildren(trans, parent); + if(rlnd.isOK()) { + if(rlnd.isEmpty()) { + return Result.err(Status.ERR_NotFound, "No data found for %s",parent); + } + for(NsDAO.Data ndd : rlnd.value) { + Namespace namespace = new Namespace(ndd); + Result> rls = func.getAdmins(trans, namespace.name, false); + if(rls.isOK()) { + namespace.admin=rls.value; + } + + rls = func.getOwners(trans, namespace.name, false); + if(rls.isOK()) { + namespace.owner=rls.value; + } + + lm.add(namespace); + } + NSS nss = mapper.newInstance(API.NSS); + return mapper.nss(trans,lm, nss); + } else { + return Result.err(rlnd); + } + } + + + @ApiDoc( + method = PUT, + path = "/authz/ns", + params = {}, + expectedCode = 200, + errorCodes = { 403,404,406 }, + text = { "Replace the Current Description of a Namespace with a new one" + } + ) + @Override + public Result updateNsDescription(AuthzTrans trans, REQUEST from) { + final Result nsd = mapper.ns(trans, from); + final ServiceValidator v = new ServiceValidator(); + if(v.ns(nsd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + if(v.nullOrBlank("description", nsd.value.description).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Namespace namespace = nsd.value; + Result> rlnd = ques.nsDAO.read(trans, namespace.name); + + if(rlnd.notOKorIsEmpty()) { + return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name); + } + + if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) { + return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name); + } + + Result rdr = ques.nsDAO.dao().addDescription(trans, namespace.name, namespace.description); + if(rdr.isOK()) { + return Result.ok(); + } else { + return Result.err(rdr); + } + } + + /** + * deleteNS + * @throws DAOException + * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String) + */ + @ApiDoc( + method = DELETE, + path = "/authz/ns/:ns", + params = { "ns|string|true" }, + expectedCode = 200, + errorCodes = { 403,404,424 }, + text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ", + "are still credentials associated with them, but they can be deleted by setting ", + "the \"force\" property. To do this: Add 'force=true' as a query parameter", + "

WARNING: Using force will delete all credentials attached to this namespace. Use with care.

" + + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted," + + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted " + + "at or below Application Scope" + } + ) + @Override + public Result deleteNS(AuthzTrans trans, String ns) { + return func.deleteNS(trans, ns); + } /*********************************** * PERM ***********************************/ - /* - * (non-Javadoc) - * @see org.onap.aaf.auth.service.AuthzService#createOrUpdatePerm(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object, boolean, java.lang.String, java.lang.String, java.lang.String, java.util.List, java.util.List) - */ - @ApiDoc( - method = POST, - path = "/authz/perm", - params = {}, - expectedCode = 201, - errorCodes = {403,404,406,409}, - text = { "Permission consists of:", - "
  • type - a Namespace qualified identifier specifying what kind of resource " - + "is being protected
  • ", - "
  • instance - a key, possibly multi-dimensional, that identifies a specific " - + " instance of the type
  • ", - "
  • action - what kind of action is allowed
", - "Note: instance and action can be an *" - } - ) - @Override - public Result createPerm(final AuthzTrans trans,REQUEST rreq) { - final Result newPd = mapper.perm(trans, rreq); - final ServiceValidator v = new ServiceValidator(); - if(v.perm(newPd).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false, - new Mapper.Memo() { - @Override - public String get() { - return "Create Permission [" + - newPd.value.fullType() + '|' + - newPd.value.instance + '|' + - newPd.value.action + ']'; - } - }, - new MayChange() { - private Result nsd; - @Override - public Result mayChange() { - if(nsd==null) { - nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write); - } - return nsd; - } - }); - Result> nsr = ques.nsDAO.read(trans, newPd.value.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans,fd.value, - newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action, - trans.user(), - nsr.value.get(0), - FUTURE_OP.C); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing", - newPd.value.ns, - newPd.value.type, - newPd.value.instance, - newPd.value.action); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - return func.createPerm(trans, newPd.value, true); - default: - return Result.err(fd); - } - } - - @ApiDoc( - method = GET, - path = "/authz/perms/:type", - params = {"type|string|true"}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "List All Permissions that match the :type element of the key" } - ) - @Override - public Result getPermsByType(AuthzTrans trans, final String permType) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("PermType", permType).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result> rlpd = ques.getPermsByType(trans, permType); - if(rlpd.notOK()) { - return Result.err(rlpd); - } - -// We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper? -// Result r; -// if((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r); - - PERMS perms = mapper.newInstance(API.PERMS); - if(!rlpd.isEmpty()) { - // Note: Mapper will restrict what can be viewed - return mapper.perms(trans, rlpd.value, perms, true); - } - return Result.ok(perms); - } - - @ApiDoc( - method = GET, - path = "/authz/perms/:type/:instance/:action", - params = {"type|string|true", - "instance|string|true", - "action|string|true"}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "List Permissions that match key; :type, :instance and :action" } - ) - @Override - public Result getPermsByName(AuthzTrans trans, String type, String instance, String action) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("PermType", type).err() - || v.nullOrBlank("PermInstance", instance).err() - || v.nullOrBlank("PermAction", action).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result> rlpd = ques.getPermsByName(trans, type, instance, action); - if(rlpd.notOK()) { - return Result.err(rlpd); - } - - PERMS perms = mapper.newInstance(API.PERMS); - if(!rlpd.isEmpty()) { - // Note: Mapper will restrict what can be viewed - return mapper.perms(trans, rlpd.value, perms, true); - } - return Result.ok(perms); - } - - @ApiDoc( - method = GET, - path = "/authz/perms/user/:user", - params = {"user|string|true"}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "List All Permissions that match user :user", - "

'user' must be expressed as full identity (ex: id@full.domain.com)

"} - ) - @Override - public Result getPermsByUser(AuthzTrans trans, String user) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result> rlpd = ques.getPermsByUser(trans, user, - trans.requested(force)); - if(rlpd.notOK()) { - return Result.err(rlpd); - } - - PERMS perms = mapper.newInstance(API.PERMS); - - if(rlpd.isEmpty()) { - return Result.ok(perms); - } - // Note: Mapper will restrict what can be viewed - // if user is the same as that which is looked up, no filtering is required - return mapper.perms(trans, rlpd.value, - perms, - !user.equals(trans.user())); - } - - @ApiDoc( - method = GET, - path = "/authz/perms/user/:user/scope/:scope", - params = {"user|string|true","scope|string|true"}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "List All Permissions that match user :user, filtered by NS (Scope)", - "

'user' must be expressed as full identity (ex: id@full.domain.com)

", - "

'scope' must be expressed as NSs separated by ':'

" - } - ) - @Override - public Result getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result> rlpd = ques.getPermsByUser(trans, user, trans.requested(force)); - if(rlpd.notOK()) { - return Result.err(rlpd); - } - - PERMS perms = mapper.newInstance(API.PERMS); - - if(rlpd.isEmpty()) { - return Result.ok(perms); - } - // Note: Mapper will restrict what can be viewed - // if user is the same as that which is looked up, no filtering is required - return mapper.perms(trans, rlpd.value, - perms, - scopes, - !user.equals(trans.user())); - } - - @ApiDoc( - method = POST, - path = "/authz/perms/user/:user", - params = {"user|string|true"}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "List All Permissions that match user :user", - "

'user' must be expressed as full identity (ex: id@full.domain.com)

", - "", - "Present Queries as one or more Permissions (see ContentType Links below for format).", - "", - "If the Caller is Granted this specific Permission, and the Permission is valid", - " for the User, it will be included in response Permissions, along with", - " all the normal permissions on the 'GET' version of this call. If it is not", - " valid, or Caller does not have permission to see, it will be removed from the list", - "", - " *Note: This design allows you to make one call for all expected permissions", - " The permission to be included MUST be:", - " .access|:[:key]|", - " examples:", - " com.att.myns.access|:ns|write", - " com.att.myns.access|:role:myrole|create", - " com.att.myns.access|:perm:mytype:myinstance:myaction|read", - "" - } - ) - @Override - public Result getPermsByUser(AuthzTrans trans, PERMS _perms, String user) { - PERMS perms = _perms; - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - ////////////// - Result> rlpd = ques.getPermsByUser(trans, user,trans.requested(force)); - if(rlpd.notOK()) { - return Result.err(rlpd); - } - - /*//TODO - 1) See if allowed to query - 2) See if User is allowed - */ - Result> in = mapper.perms(trans, perms); - if(in.isOKhasData()) { - List out = rlpd.value; - boolean ok; - for(PermDAO.Data pdd : in.value) { - ok = false; - if("access".equals(pdd.type)) { - Access access = Access.valueOf(pdd.action); - String[] mdkey = Split.splitTrim(':',pdd.instance); - if(mdkey.length>1) { - String type = mdkey[1]; - if("role".equals(type)) { - if(mdkey.length>2) { - RoleDAO.Data rdd = new RoleDAO.Data(); - rdd.ns=pdd.ns; - rdd.name=mdkey[2]; - ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK(); - } - } else if("perm".equals(type)) { - if(mdkey.length>4) { // also need instance/action - PermDAO.Data p = new PermDAO.Data(); - p.ns=pdd.ns; - p.type=mdkey[2]; - p.instance=mdkey[3]; - p.action=mdkey[4]; - ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK(); - } - } else if("ns".equals(type)) { - NsDAO.Data ndd = new NsDAO.Data(); - ndd.name=pdd.ns; - ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK(); - } - } - } - if(ok) { - out.add(pdd); - } - } - } - - perms = mapper.newInstance(API.PERMS); - if(rlpd.isEmpty()) { - return Result.ok(perms); - } - // Note: Mapper will restrict what can be viewed - // if user is the same as that which is looked up, no filtering is required - return mapper.perms(trans, rlpd.value, - perms, - !user.equals(trans.user())); - } - - @ApiDoc( - method = GET, - path = "/authz/perms/role/:role", - params = {"role|string|true"}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "List All Permissions that are granted to :role" } - ) - @Override - public Result getPermsByRole(AuthzTrans trans,String role) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Role", role).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result rrdd = RoleDAO.Data.decode(trans, ques,role); - if(rrdd.notOK()) { - return Result.err(rrdd); - } - - Result r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read); - if(r.notOK()) { - return Result.err(r); - } - - PERMS perms = mapper.newInstance(API.PERMS); - - Result> rlpd = ques.getPermsByRole(trans, role, trans.requested(force)); - if(rlpd.isOKhasData()) { - // Note: Mapper will restrict what can be viewed - return mapper.perms(trans, rlpd.value, perms, true); - } - return Result.ok(perms); - } - - @ApiDoc( - method = GET, - path = "/authz/perms/ns/:ns", - params = {"ns|string|true"}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "List All Permissions that are in Namespace :ns" } - ) - @Override - public Result getPermsByNS(AuthzTrans trans,String ns) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("NS", ns).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result rnd = ques.deriveNs(trans, ns); - if(rnd.notOK()) { - return Result.err(rnd); - } - - rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - - Result> rlpd = ques.permDAO.readNS(trans, ns); - if(rlpd.notOK()) { - return Result.err(rlpd); - } - - PERMS perms = mapper.newInstance(API.PERMS); - if(!rlpd.isEmpty()) { - // Note: Mapper will restrict what can be viewed - return mapper.perms(trans, rlpd.value,perms, true); - } - return Result.ok(perms); - } - - @ApiDoc( - method = PUT, - path = "/authz/perm/:type/:instance/:action", - params = {"type|string|true", - "instance|string|true", - "action|string|true"}, - expectedCode = 200, - errorCodes = { 404,406, 409 }, - text = { "Rename the Permission referenced by :type :instance :action, and " - + "rename (copy/delete) to the Permission described in PermRequest" } - ) - @Override - public Result renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) { - final Result newPd = mapper.perm(trans, rreq); - final ServiceValidator v = new ServiceValidator(); - if(v.perm(newPd).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) { - return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]", - newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action); - } - - Result nss = ques.deriveNsSplit(trans, origType); - Result> origRlpd = ques.permDAO.read(trans, nss.value.ns, nss.value.name, origInstance, origAction); - - if(origRlpd.notOKorIsEmpty()) { - return Result.err(Status.ERR_PermissionNotFound, - "Permission [%s|%s|%s] does not exist", - origType,origInstance,origAction); - } - - PermDAO.Data origPd = origRlpd.value.get(0); - - if (!origPd.ns.equals(newPd.value.ns)) { - return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " + - " must start with [" + origPd.ns + "]"); - } - - if ( origPd.type.equals(newPd.value.type) && - origPd.action.equals(newPd.value.action) && - origPd.instance.equals(newPd.value.instance) ) { - return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission"); - } - - Set origRoles = origPd.roles(false); - if (!origRoles.isEmpty()) { - Set roles = newPd.value.roles(true); - for (String role : origPd.roles) { - roles.add(role); - } - } - - newPd.value.description = origPd.description; - - Result rv = null; - - rv = func.createPerm(trans, newPd.value, false); - if (rv.isOK()) { - rv = func.deletePerm(trans, origPd, true, false); - } - return rv; - } - - @ApiDoc( - method = PUT, - path = "/authz/perm", - params = {}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "Add Description Data to Perm" } - ) - @Override - public Result updatePermDescription(AuthzTrans trans, REQUEST from) { - final Result pd = mapper.perm(trans, from); - final ServiceValidator v = new ServiceValidator(); - if(v.perm(pd).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - if(v.nullOrBlank("description", pd.value.description).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - final PermDAO.Data perm = pd.value; - if(ques.permDAO.read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) { - return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist", - perm.ns,perm.type,perm.instance,perm.action); - } - - if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) { - return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]", - perm.ns,perm.type,perm.instance,perm.action); - } - - Result> nsr = ques.nsDAO.read(trans, pd.value.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - Result rdr = ques.permDAO.addDescription(trans, perm.ns, perm.type, perm.instance, - perm.action, perm.description); - if(rdr.isOK()) { - return Result.ok(); - } else { - return Result.err(rdr); - } - - } - + /* + * (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#createOrUpdatePerm(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object, boolean, java.lang.String, java.lang.String, java.lang.String, java.util.List, java.util.List) + */ + @ApiDoc( + method = POST, + path = "/authz/perm", + params = {}, + expectedCode = 201, + errorCodes = {403,404,406,409}, + text = { "Permission consists of:", + "
  • type - a Namespace qualified identifier specifying what kind of resource " + + "is being protected
  • ", + "
  • instance - a key, possibly multi-dimensional, that identifies a specific " + + " instance of the type
  • ", + "
  • action - what kind of action is allowed
", + "Note: instance and action can be an *" + } + ) + @Override + public Result createPerm(final AuthzTrans trans,REQUEST rreq) { + final Result newPd = mapper.perm(trans, rreq); + final ServiceValidator v = new ServiceValidator(); + if(v.perm(newPd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false, + new Mapper.Memo() { + @Override + public String get() { + return "Create Permission [" + + newPd.value.fullType() + '|' + + newPd.value.instance + '|' + + newPd.value.action + ']'; + } + }, + new MayChange() { + private Result nsd; + @Override + public Result mayChange() { + if(nsd==null) { + nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write); + } + return nsd; + } + }); + Result> nsr = ques.nsDAO.read(trans, newPd.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans,fd.value, + newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action, + trans.user(), + nsr.value.get(0), + FUTURE_OP.C); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing", + newPd.value.ns, + newPd.value.type, + newPd.value.instance, + newPd.value.action); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + return func.createPerm(trans, newPd.value, true); + default: + return Result.err(fd); + } + } + + @ApiDoc( + method = GET, + path = "/authz/perms/:type", + params = {"type|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that match the :type element of the key" } + ) + @Override + public Result getPermsByType(AuthzTrans trans, final String permType) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("PermType", permType).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlpd = ques.getPermsByType(trans, permType); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + +// We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper? +// Result r; +// if((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r); + + PERMS perms = mapper.newInstance(API.PERMS); + if(!rlpd.isEmpty()) { + // Note: Mapper will restrict what can be viewed + return mapper.perms(trans, rlpd.value, perms, true); + } + return Result.ok(perms); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/:type/:instance/:action", + params = {"type|string|true", + "instance|string|true", + "action|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List Permissions that match key; :type, :instance and :action" } + ) + @Override + public Result getPermsByName(AuthzTrans trans, String type, String instance, String action) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("PermType", type).err() + || v.nullOrBlank("PermInstance", instance).err() + || v.nullOrBlank("PermAction", action).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlpd = ques.getPermsByName(trans, type, instance, action); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + PERMS perms = mapper.newInstance(API.PERMS); + if(!rlpd.isEmpty()) { + // Note: Mapper will restrict what can be viewed + return mapper.perms(trans, rlpd.value, perms, true); + } + return Result.ok(perms); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/user/:user", + params = {"user|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that match user :user", + "

'user' must be expressed as full identity (ex: id@full.domain.com)

"} + ) + @Override + public Result getPermsByUser(AuthzTrans trans, String user) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlpd = ques.getPermsByUser(trans, user, + trans.requested(force)); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + PERMS perms = mapper.newInstance(API.PERMS); + + if(rlpd.isEmpty()) { + return Result.ok(perms); + } + // Note: Mapper will restrict what can be viewed + // if user is the same as that which is looked up, no filtering is required + return mapper.perms(trans, rlpd.value, + perms, + !user.equals(trans.user())); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/user/:user/scope/:scope", + params = {"user|string|true","scope|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that match user :user, filtered by NS (Scope)", + "

'user' must be expressed as full identity (ex: id@full.domain.com)

", + "

'scope' must be expressed as NSs separated by ':'

" + } + ) + @Override + public Result getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlpd = ques.getPermsByUser(trans, user, trans.requested(force)); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + PERMS perms = mapper.newInstance(API.PERMS); + + if(rlpd.isEmpty()) { + return Result.ok(perms); + } + // Note: Mapper will restrict what can be viewed + // if user is the same as that which is looked up, no filtering is required + return mapper.perms(trans, rlpd.value, + perms, + scopes, + !user.equals(trans.user())); + } + + @ApiDoc( + method = POST, + path = "/authz/perms/user/:user", + params = {"user|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that match user :user", + "

'user' must be expressed as full identity (ex: id@full.domain.com)

", + "", + "Present Queries as one or more Permissions (see ContentType Links below for format).", + "", + "If the Caller is Granted this specific Permission, and the Permission is valid", + " for the User, it will be included in response Permissions, along with", + " all the normal permissions on the 'GET' version of this call. If it is not", + " valid, or Caller does not have permission to see, it will be removed from the list", + "", + " *Note: This design allows you to make one call for all expected permissions", + " The permission to be included MUST be:", + " .access|:[:key]|", + " examples:", + " com.att.myns.access|:ns|write", + " com.att.myns.access|:role:myrole|create", + " com.att.myns.access|:perm:mytype:myinstance:myaction|read", + "" + } + ) + @Override + public Result getPermsByUser(AuthzTrans trans, PERMS _perms, String user) { + PERMS perms = _perms; + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + ////////////// + Result> rlpd = ques.getPermsByUser(trans, user,trans.requested(force)); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + /*//TODO + 1) See if allowed to query + 2) See if User is allowed + */ + Result> in = mapper.perms(trans, perms); + if(in.isOKhasData()) { + List out = rlpd.value; + boolean ok; + for(PermDAO.Data pdd : in.value) { + ok = false; + if("access".equals(pdd.type)) { + Access access = Access.valueOf(pdd.action); + String[] mdkey = Split.splitTrim(':',pdd.instance); + if(mdkey.length>1) { + String type = mdkey[1]; + if("role".equals(type)) { + if(mdkey.length>2) { + RoleDAO.Data rdd = new RoleDAO.Data(); + rdd.ns=pdd.ns; + rdd.name=mdkey[2]; + ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK(); + } + } else if("perm".equals(type)) { + if(mdkey.length>4) { // also need instance/action + PermDAO.Data p = new PermDAO.Data(); + p.ns=pdd.ns; + p.type=mdkey[2]; + p.instance=mdkey[3]; + p.action=mdkey[4]; + ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK(); + } + } else if("ns".equals(type)) { + NsDAO.Data ndd = new NsDAO.Data(); + ndd.name=pdd.ns; + ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK(); + } + } + } + if(ok) { + out.add(pdd); + } + } + } + + perms = mapper.newInstance(API.PERMS); + if(rlpd.isEmpty()) { + return Result.ok(perms); + } + // Note: Mapper will restrict what can be viewed + // if user is the same as that which is looked up, no filtering is required + return mapper.perms(trans, rlpd.value, + perms, + !user.equals(trans.user())); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/role/:role", + params = {"role|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that are granted to :role" } + ) + @Override + public Result getPermsByRole(AuthzTrans trans,String role) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Role", role).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rrdd = RoleDAO.Data.decode(trans, ques,role); + if(rrdd.notOK()) { + return Result.err(rrdd); + } + + Result r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read); + if(r.notOK()) { + return Result.err(r); + } + + PERMS perms = mapper.newInstance(API.PERMS); + + Result> rlpd = ques.getPermsByRole(trans, role, trans.requested(force)); + if(rlpd.isOKhasData()) { + // Note: Mapper will restrict what can be viewed + return mapper.perms(trans, rlpd.value, perms, true); + } + return Result.ok(perms); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/ns/:ns", + params = {"ns|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that are in Namespace :ns" } + ) + @Override + public Result getPermsByNS(AuthzTrans trans,String ns) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS", ns).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rnd = ques.deriveNs(trans, ns); + if(rnd.notOK()) { + return Result.err(rnd); + } + + rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + Result> rlpd = ques.permDAO.readNS(trans, ns); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + PERMS perms = mapper.newInstance(API.PERMS); + if(!rlpd.isEmpty()) { + // Note: Mapper will restrict what can be viewed + return mapper.perms(trans, rlpd.value,perms, true); + } + return Result.ok(perms); + } + + @ApiDoc( + method = PUT, + path = "/authz/perm/:type/:instance/:action", + params = {"type|string|true", + "instance|string|true", + "action|string|true"}, + expectedCode = 200, + errorCodes = { 404,406, 409 }, + text = { "Rename the Permission referenced by :type :instance :action, and " + + "rename (copy/delete) to the Permission described in PermRequest" } + ) + @Override + public Result renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) { + final Result newPd = mapper.perm(trans, rreq); + final ServiceValidator v = new ServiceValidator(); + if(v.perm(newPd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) { + return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]", + newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action); + } + + Result nss = ques.deriveNsSplit(trans, origType); + Result> origRlpd = ques.permDAO.read(trans, nss.value.ns, nss.value.name, origInstance, origAction); + + if(origRlpd.notOKorIsEmpty()) { + return Result.err(Status.ERR_PermissionNotFound, + "Permission [%s|%s|%s] does not exist", + origType,origInstance,origAction); + } + + PermDAO.Data origPd = origRlpd.value.get(0); + + if (!origPd.ns.equals(newPd.value.ns)) { + return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " + + " must start with [" + origPd.ns + "]"); + } + + if ( origPd.type.equals(newPd.value.type) && + origPd.action.equals(newPd.value.action) && + origPd.instance.equals(newPd.value.instance) ) { + return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission"); + } + + Set origRoles = origPd.roles(false); + if (!origRoles.isEmpty()) { + Set roles = newPd.value.roles(true); + for (String role : origPd.roles) { + roles.add(role); + } + } + + newPd.value.description = origPd.description; + + Result rv = null; + + rv = func.createPerm(trans, newPd.value, false); + if (rv.isOK()) { + rv = func.deletePerm(trans, origPd, true, false); + } + return rv; + } + + @ApiDoc( + method = PUT, + path = "/authz/perm", + params = {}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "Add Description Data to Perm" } + ) + @Override + public Result updatePermDescription(AuthzTrans trans, REQUEST from) { + final Result pd = mapper.perm(trans, from); + final ServiceValidator v = new ServiceValidator(); + if(v.perm(pd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + if(v.nullOrBlank("description", pd.value.description).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + final PermDAO.Data perm = pd.value; + if(ques.permDAO.read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) { + return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist", + perm.ns,perm.type,perm.instance,perm.action); + } + + if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) { + return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]", + perm.ns,perm.type,perm.instance,perm.action); + } + + Result> nsr = ques.nsDAO.read(trans, pd.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + Result rdr = ques.permDAO.addDescription(trans, perm.ns, perm.type, perm.instance, + perm.action, perm.description); + if(rdr.isOK()) { + return Result.ok(); + } else { + return Result.err(rdr); + } + + } + @ApiDoc( method = PUT, path = "/authz/role/perm", @@ -1270,192 +1270,192 @@ public class AuthzCassServiceImpl resetPermRoles(final AuthzTrans trans, REQUEST rreq) { - final Result updt = mapper.permFromRPRequest(trans, rreq); - if(updt.notOKorIsEmpty()) { - return Result.err(updt); - } - - final ServiceValidator v = new ServiceValidator(); - if(v.perm(updt).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write); - if (nsd.notOK()) { - return Result.err(nsd); - } - - // Read full set to get CURRENT values - Result> rcurr = ques.permDAO.read(trans, - updt.value.ns, - updt.value.type, - updt.value.instance, - updt.value.action); - - if(rcurr.notOKorIsEmpty()) { - return Result.err(Status.ERR_PermissionNotFound, - "Permission [%s.%s|%s|%s] does not exist", - updt.value.ns,updt.value.type,updt.value.instance,updt.value.action); - } - - // Create a set of Update Roles, which are in Internal Format - Set updtRoles = new HashSet<>(); - Result nss; - for(String role : updt.value.roles(false)) { - nss = ques.deriveNsSplit(trans, role); - if(nss.isOK()) { - updtRoles.add(nss.value.ns + '|' + nss.value.name); - } else { - trans.error().log(nss.errorString()); - } - } - - Result rv = null; - - for(PermDAO.Data curr : rcurr.value) { - Set currRoles = curr.roles(false); - // must add roles to this perm, and add this perm to each role - // in the update, but not in the current - for (String role : updtRoles) { - if (!currRoles.contains(role)) { - Result key = RoleDAO.Data.decode(trans, ques, role); - if(key.isOKhasData()) { - Result> rrd = ques.roleDAO.read(trans, key.value); - if(rrd.isOKhasData()) { - for(RoleDAO.Data r : rrd.value) { - rv = func.addPermToRole(trans, r, curr, false); - if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) { - return Result.err(rv); - } - } - } else { - return Result.err(rrd); - } - } - } - } - // similarly, must delete roles from this perm, and delete this perm from each role - // in the update, but not in the current - for (String role : currRoles) { - if (!updtRoles.contains(role)) { - Result key = RoleDAO.Data.decode(trans, ques, role); - if(key.isOKhasData()) { - Result> rdd = ques.roleDAO.read(trans, key.value); - if(rdd.isOKhasData()) { - for(RoleDAO.Data r : rdd.value) { - rv = func.delPermFromRole(trans, r, curr, true); - if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) { - return Result.err(rv); - } - } - } - } - } - } - } - return rv==null?Result.ok():rv; - } - - @ApiDoc( - method = DELETE, - path = "/authz/perm", - params = {}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "Delete the Permission referenced by PermKey.", - "You cannot normally delete a permission which is still granted to roles,", - "however the \"force\" property allows you to do just that. To do this: Add", - "'force=true' as a query parameter.", - "

WARNING: Using force will ungrant this permission from all roles. Use with care.

" } - ) - @Override - public Result deletePerm(final AuthzTrans trans, REQUEST from) { - Result pd = mapper.perm(trans, from); - if(pd.notOK()) { - return Result.err(pd); - } - final ServiceValidator v = new ServiceValidator(); - if(v.nullOrBlank(pd.value).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - final PermDAO.Data perm = pd.value; - if (ques.permDAO.read(trans, perm).notOKorIsEmpty()) { - return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist", - perm.ns,perm.type,perm.instance,perm.action ); - } - - Result fd = mapper.future(trans,PermDAO.TABLE,from,perm,false, - new Mapper.Memo() { - @Override - public String get() { - return "Delete Permission [" + perm.fullPerm() + ']'; - } - }, - new MayChange() { - private Result nsd; - @Override - public Result mayChange() { - if(nsd==null) { - nsd = ques.mayUser(trans, trans.user(), perm, Access.write); - } - return nsd; - } - }); - - switch(fd.status) { - case OK: - Result> nsr = ques.nsDAO.read(trans, perm.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - Result rfc = func.createFuture(trans, fd.value, - perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode()); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - return func.deletePerm(trans,perm,trans.requested(force), false); - default: - return Result.err(fd); - } - } - - @ApiDoc( - method = DELETE, - path = "/authz/perm/:name/:type/:action", - params = {"type|string|true", - "instance|string|true", - "action|string|true"}, - expectedCode = 200, - errorCodes = { 404,406 }, - text = { "Delete the Permission referenced by :type :instance :action", - "You cannot normally delete a permission which is still granted to roles,", - "however the \"force\" property allows you to do just that. To do this: Add", - "'force=true' as a query parameter", - "

WARNING: Using force will ungrant this permission from all roles. Use with care.

"} - ) - @Override - public Result deletePerm(AuthzTrans trans, String type, String instance, String action) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Type",type) - .nullOrBlank("Instance",instance) - .nullOrBlank("Action",action) - .err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result pd = ques.permFrom(trans, type, instance, action); - if(pd.isOK()) { - return func.deletePerm(trans, pd.value, trans.requested(force), false); - } else { - return Result.err(pd); - } - } + @Override + public Result resetPermRoles(final AuthzTrans trans, REQUEST rreq) { + final Result updt = mapper.permFromRPRequest(trans, rreq); + if(updt.notOKorIsEmpty()) { + return Result.err(updt); + } + + final ServiceValidator v = new ServiceValidator(); + if(v.perm(updt).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write); + if (nsd.notOK()) { + return Result.err(nsd); + } + + // Read full set to get CURRENT values + Result> rcurr = ques.permDAO.read(trans, + updt.value.ns, + updt.value.type, + updt.value.instance, + updt.value.action); + + if(rcurr.notOKorIsEmpty()) { + return Result.err(Status.ERR_PermissionNotFound, + "Permission [%s.%s|%s|%s] does not exist", + updt.value.ns,updt.value.type,updt.value.instance,updt.value.action); + } + + // Create a set of Update Roles, which are in Internal Format + Set updtRoles = new HashSet<>(); + Result nss; + for(String role : updt.value.roles(false)) { + nss = ques.deriveNsSplit(trans, role); + if(nss.isOK()) { + updtRoles.add(nss.value.ns + '|' + nss.value.name); + } else { + trans.error().log(nss.errorString()); + } + } + + Result rv = null; + + for(PermDAO.Data curr : rcurr.value) { + Set currRoles = curr.roles(false); + // must add roles to this perm, and add this perm to each role + // in the update, but not in the current + for (String role : updtRoles) { + if (!currRoles.contains(role)) { + Result key = RoleDAO.Data.decode(trans, ques, role); + if(key.isOKhasData()) { + Result> rrd = ques.roleDAO.read(trans, key.value); + if(rrd.isOKhasData()) { + for(RoleDAO.Data r : rrd.value) { + rv = func.addPermToRole(trans, r, curr, false); + if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) { + return Result.err(rv); + } + } + } else { + return Result.err(rrd); + } + } + } + } + // similarly, must delete roles from this perm, and delete this perm from each role + // in the update, but not in the current + for (String role : currRoles) { + if (!updtRoles.contains(role)) { + Result key = RoleDAO.Data.decode(trans, ques, role); + if(key.isOKhasData()) { + Result> rdd = ques.roleDAO.read(trans, key.value); + if(rdd.isOKhasData()) { + for(RoleDAO.Data r : rdd.value) { + rv = func.delPermFromRole(trans, r, curr, true); + if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) { + return Result.err(rv); + } + } + } + } + } + } + } + return rv==null?Result.ok():rv; + } + + @ApiDoc( + method = DELETE, + path = "/authz/perm", + params = {}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "Delete the Permission referenced by PermKey.", + "You cannot normally delete a permission which is still granted to roles,", + "however the \"force\" property allows you to do just that. To do this: Add", + "'force=true' as a query parameter.", + "

WARNING: Using force will ungrant this permission from all roles. Use with care.

" } + ) + @Override + public Result deletePerm(final AuthzTrans trans, REQUEST from) { + Result pd = mapper.perm(trans, from); + if(pd.notOK()) { + return Result.err(pd); + } + final ServiceValidator v = new ServiceValidator(); + if(v.nullOrBlank(pd.value).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + final PermDAO.Data perm = pd.value; + if (ques.permDAO.read(trans, perm).notOKorIsEmpty()) { + return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist", + perm.ns,perm.type,perm.instance,perm.action ); + } + + Result fd = mapper.future(trans,PermDAO.TABLE,from,perm,false, + new Mapper.Memo() { + @Override + public String get() { + return "Delete Permission [" + perm.fullPerm() + ']'; + } + }, + new MayChange() { + private Result nsd; + @Override + public Result mayChange() { + if(nsd==null) { + nsd = ques.mayUser(trans, trans.user(), perm, Access.write); + } + return nsd; + } + }); + + switch(fd.status) { + case OK: + Result> nsr = ques.nsDAO.read(trans, perm.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + Result rfc = func.createFuture(trans, fd.value, + perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode()); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + return func.deletePerm(trans,perm,trans.requested(force), false); + default: + return Result.err(fd); + } + } + + @ApiDoc( + method = DELETE, + path = "/authz/perm/:name/:type/:action", + params = {"type|string|true", + "instance|string|true", + "action|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "Delete the Permission referenced by :type :instance :action", + "You cannot normally delete a permission which is still granted to roles,", + "however the \"force\" property allows you to do just that. To do this: Add", + "'force=true' as a query parameter", + "

WARNING: Using force will ungrant this permission from all roles. Use with care.

"} + ) + @Override + public Result deletePerm(AuthzTrans trans, String type, String instance, String action) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Type",type) + .nullOrBlank("Instance",instance) + .nullOrBlank("Action",action) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result pd = ques.permFrom(trans, type, instance, action); + if(pd.isOK()) { + return func.deletePerm(trans, pd.value, trans.requested(force), false); + } else { + return Result.err(pd); + } + } /*********************************** * ROLE @@ -1481,69 +1481,69 @@ public class AuthzCassServiceImpl 'Does this person perform this Job Function?'" } ) - @Override - public Result createRole(final AuthzTrans trans, REQUEST from) { - final Result rd = mapper.role(trans, from); - final ServiceValidator v = new ServiceValidator(); - if(v.role(rd).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - final RoleDAO.Data role = rd.value; - if(ques.roleDAO.read(trans, role.ns, role.name).isOKhasData()) { - return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists"); - } - - Result fd = mapper.future(trans,RoleDAO.TABLE,from,role,false, - new Mapper.Memo() { - @Override - public String get() { - return "Create Role [" + - rd.value.fullName() + - ']'; - } - }, - new MayChange() { - private Result nsd; - @Override - public Result mayChange() { - if(nsd==null) { - nsd = ques.mayUser(trans, trans.user(), role, Access.write); - } - return nsd; - } - }); - - Result> nsr = ques.nsDAO.read(trans, rd.value.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans, fd.value, - role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.C); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing", - rd.value.ns, - rd.value.name); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - Result rdr = ques.roleDAO.create(trans, role); - if(rdr.isOK()) { - return Result.ok(); - } else { - return Result.err(rdr); - } - default: - return Result.err(fd); - } - } - - /* (non-Javadoc) - * @see org.onap.aaf.auth.service.AuthzService#getRolesByName(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) - */ + @Override + public Result createRole(final AuthzTrans trans, REQUEST from) { + final Result rd = mapper.role(trans, from); + final ServiceValidator v = new ServiceValidator(); + if(v.role(rd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + final RoleDAO.Data role = rd.value; + if(ques.roleDAO.read(trans, role.ns, role.name).isOKhasData()) { + return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists"); + } + + Result fd = mapper.future(trans,RoleDAO.TABLE,from,role,false, + new Mapper.Memo() { + @Override + public String get() { + return "Create Role [" + + rd.value.fullName() + + ']'; + } + }, + new MayChange() { + private Result nsd; + @Override + public Result mayChange() { + if(nsd==null) { + nsd = ques.mayUser(trans, trans.user(), role, Access.write); + } + return nsd; + } + }); + + Result> nsr = ques.nsDAO.read(trans, rd.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans, fd.value, + role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.C); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing", + rd.value.ns, + rd.value.name); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + Result rdr = ques.roleDAO.create(trans, role); + if(rdr.isOK()) { + return Result.ok(); + } else { + return Result.err(rdr); + } + default: + return Result.err(fd); + } + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#getRolesByName(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) + */ @ApiDoc( method = GET, path = "/authz/roles/:role", @@ -1551,42 +1551,42 @@ public class AuthzCassServiceImpl getRolesByName(AuthzTrans trans, String role) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Role", role).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // Determine if User can ask this question - Result rrdd = RoleDAO.Data.decode(trans, ques, role); - if(rrdd.isOKhasData()) { - Result r; - if((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) { - return Result.err(r); - } - } else { - return Result.err(rrdd); - } - - // Look up data - int query = role.indexOf('?'); - Result> rlrd = ques.getRolesByName(trans, query<0?role:role.substring(0, query)); - if(rlrd.isOK()) { - // Note: Mapper will restrict what can be viewed - ROLES roles = mapper.newInstance(API.ROLES); - return mapper.roles(trans, rlrd.value, roles, true); - } else { - return Result.err(rlrd); - } - } - - /* (non-Javadoc) - * @see org.onap.aaf.auth.service.AuthzService#getRolesByUser(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) - */ + @Override + public Result getRolesByName(AuthzTrans trans, String role) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Role", role).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // Determine if User can ask this question + Result rrdd = RoleDAO.Data.decode(trans, ques, role); + if(rrdd.isOKhasData()) { + Result r; + if((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) { + return Result.err(r); + } + } else { + return Result.err(rrdd); + } + + // Look up data + int query = role.indexOf('?'); + Result> rlrd = ques.getRolesByName(trans, query<0?role:role.substring(0, query)); + if(rlrd.isOK()) { + // Note: Mapper will restrict what can be viewed + ROLES roles = mapper.newInstance(API.ROLES); + return mapper.roles(trans, rlrd.value, roles, true); + } else { + return Result.err(rlrd); + } + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#getRolesByUser(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) + */ @ApiDoc( method = GET, path = "/authz/roles/user/:name", @@ -1594,39 +1594,39 @@ public class AuthzCassServiceImpl getRolesByUser(AuthzTrans trans, String user) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - ROLES roles = mapper.newInstance(API.ROLES); - // Get list of roles per user, then add to Roles as we go - Result> rlrd; - Result> rlurd = ques.userRoleDAO.readByUser(trans, user); - if(rlurd.isOKhasData()) { - for(UserRoleDAO.Data urd : rlurd.value ) { - rlrd = ques.roleDAO.read(trans, urd.ns,urd.rname); - // Note: Mapper will restrict what can be viewed - // if user is the same as that which is looked up, no filtering is required - if(rlrd.isOKhasData()) { - mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user())); - } - } - } - return Result.ok(roles); - } - - /* - * (non-Javadoc) - * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) - */ + @Override + public Result getRolesByUser(AuthzTrans trans, String user) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + ROLES roles = mapper.newInstance(API.ROLES); + // Get list of roles per user, then add to Roles as we go + Result> rlrd; + Result> rlurd = ques.userRoleDAO.readByUser(trans, user); + if(rlurd.isOKhasData()) { + for(UserRoleDAO.Data urd : rlurd.value ) { + rlrd = ques.roleDAO.read(trans, urd.ns,urd.rname); + // Note: Mapper will restrict what can be viewed + // if user is the same as that which is looked up, no filtering is required + if(rlrd.isOKhasData()) { + mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user())); + } + } + } + return Result.ok(roles); + } + + /* + * (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) + */ @ApiDoc( method = GET, path = "/authz/roles/ns/:ns", @@ -1634,50 +1634,50 @@ public class AuthzCassServiceImpl getRolesByNS(AuthzTrans trans, String ns) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("NS", ns).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // check if user is allowed to view NS - Result rnsd = ques.deriveNs(trans, ns); - if(rnsd.notOK()) { - return Result.err(rnsd); - } - rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read); - if(rnsd.notOK()) { - return Result.err(rnsd); - } - - TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB); - try { - ROLES roles = mapper.newInstance(API.ROLES); - // Get list of roles per user, then add to Roles as we go - Result> rlrd = ques.roleDAO.readNS(trans, ns); - if(rlrd.isOK()) { - if(!rlrd.isEmpty()) { - // Note: Mapper doesn't need to restrict what can be viewed, because we did it already. - mapper.roles(trans,rlrd.value,roles,false); - } - return Result.ok(roles); - } else { - return Result.err(rlrd); - } - } finally { - tt.done(); - } - } - - /* - * (non-Javadoc) - * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) - */ + @Override + public Result getRolesByNS(AuthzTrans trans, String ns) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS", ns).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // check if user is allowed to view NS + Result rnsd = ques.deriveNs(trans, ns); + if(rnsd.notOK()) { + return Result.err(rnsd); + } + rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read); + if(rnsd.notOK()) { + return Result.err(rnsd); + } + + TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB); + try { + ROLES roles = mapper.newInstance(API.ROLES); + // Get list of roles per user, then add to Roles as we go + Result> rlrd = ques.roleDAO.readNS(trans, ns); + if(rlrd.isOK()) { + if(!rlrd.isEmpty()) { + // Note: Mapper doesn't need to restrict what can be viewed, because we did it already. + mapper.roles(trans,rlrd.value,roles,false); + } + return Result.ok(roles); + } else { + return Result.err(rlrd); + } + } finally { + tt.done(); + } + } + + /* + * (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) + */ @ApiDoc( method = GET, path = "/authz/roles/name/:name", @@ -1685,36 +1685,36 @@ public class AuthzCassServiceImpl getRolesByNameOnly(AuthzTrans trans, String name) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Name", name).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // User Mapper to make sure user is allowed to view NS - - TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB); - try { - ROLES roles = mapper.newInstance(API.ROLES); - // Get list of roles per user, then add to Roles as we go - Result> rlrd = ques.roleDAO.readName(trans, name); - if(rlrd.isOK()) { - if(!rlrd.isEmpty()) { - // Note: Mapper will restrict what can be viewed - mapper.roles(trans,rlrd.value,roles,true); - } - return Result.ok(roles); - } else { - return Result.err(rlrd); - } - } finally { - tt.done(); - } - } + @Override + public Result getRolesByNameOnly(AuthzTrans trans, String name) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Name", name).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // User Mapper to make sure user is allowed to view NS + + TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB); + try { + ROLES roles = mapper.newInstance(API.ROLES); + // Get list of roles per user, then add to Roles as we go + Result> rlrd = ques.roleDAO.readName(trans, name); + if(rlrd.isOK()) { + if(!rlrd.isEmpty()) { + // Note: Mapper will restrict what can be viewed + mapper.roles(trans,rlrd.value,roles,true); + } + return Result.ok(roles); + } else { + return Result.err(rlrd); + } + } finally { + tt.done(); + } + } @ApiDoc( method = GET, @@ -1732,52 +1732,52 @@ public class AuthzCassServiceImpl ", "
  • action - what kind of action is allowed
  • ", "Notes: instance and action can be an *", - " You must have permission to see any given role" + " You must have permission to see any given role" } ) - @Override - public Result getRolesByPerm(AuthzTrans trans, String type, String instance, String action) { - final Validator v = new ServiceValidator(); - if(v.permType(type) - .permInstance(instance) - .permAction(action) - .err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB); - try { - ROLES roles = mapper.newInstance(API.ROLES); - // Get list of roles per user, then add to Roles as we go - Result nsSplit = ques.deriveNsSplit(trans, type); - if(nsSplit.isOK()) { - PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action); - Result res; - if((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) { - return Result.err(res); - } - - Result> pdlr = ques.permDAO.read(trans, pdd); - if(pdlr.isOK())for(PermDAO.Data pd : pdlr.value) { - Result> rlrd; - for(String r : pd.roles) { - Result rs = RoleDAO.Data.decodeToArray(trans, ques, r); - if(rs.isOK()) { - rlrd = ques.roleDAO.read(trans, rs.value[0],rs.value[1]); - // Note: Mapper will restrict what can be viewed - if(rlrd.isOKhasData()) { - mapper.roles(trans,rlrd.value,roles,true); - } - } - } - } - } - return Result.ok(roles); - } finally { - tt.done(); - } - } + @Override + public Result getRolesByPerm(AuthzTrans trans, String type, String instance, String action) { + final Validator v = new ServiceValidator(); + if(v.permType(type) + .permInstance(instance) + .permAction(action) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB); + try { + ROLES roles = mapper.newInstance(API.ROLES); + // Get list of roles per user, then add to Roles as we go + Result nsSplit = ques.deriveNsSplit(trans, type); + if(nsSplit.isOK()) { + PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action); + Result res; + if((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) { + return Result.err(res); + } + + Result> pdlr = ques.permDAO.read(trans, pdd); + if(pdlr.isOK())for(PermDAO.Data pd : pdlr.value) { + Result> rlrd; + for(String r : pd.roles) { + Result rs = RoleDAO.Data.decodeToArray(trans, ques, r); + if(rs.isOK()) { + rlrd = ques.roleDAO.read(trans, rs.value[0],rs.value[1]); + // Note: Mapper will restrict what can be viewed + if(rlrd.isOKhasData()) { + mapper.roles(trans,rlrd.value,roles,true); + } + } + } + } + } + return Result.ok(roles); + } finally { + tt.done(); + } + } @ApiDoc( method = PUT, @@ -1788,40 +1788,40 @@ public class AuthzCassServiceImpl updateRoleDescription(AuthzTrans trans, REQUEST from) { - final Result rd = mapper.role(trans, from); - final ServiceValidator v = new ServiceValidator(); - if(v.role(rd).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } { - if(v.nullOrBlank("description", rd.value.description).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - } - final RoleDAO.Data role = rd.value; - if(ques.roleDAO.read(trans, role.ns, role.name).notOKorIsEmpty()) { - return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist"); - } - - if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) { - return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName()); - } - - Result> nsr = ques.nsDAO.read(trans, rd.value.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - Result rdr = ques.roleDAO.addDescription(trans, role.ns, role.name, role.description); - if(rdr.isOK()) { - return Result.ok(); - } else { - return Result.err(rdr); - } - - } - + @Override + public Result updateRoleDescription(AuthzTrans trans, REQUEST from) { + final Result rd = mapper.role(trans, from); + final ServiceValidator v = new ServiceValidator(); + if(v.role(rd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } { + if(v.nullOrBlank("description", rd.value.description).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + } + final RoleDAO.Data role = rd.value; + if(ques.roleDAO.read(trans, role.ns, role.name).notOKorIsEmpty()) { + return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist"); + } + + if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) { + return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName()); + } + + Result> nsr = ques.nsDAO.read(trans, rd.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + Result rdr = ques.roleDAO.addDescription(trans, role.ns, role.name, role.description); + if(rdr.isOK()) { + return Result.ok(); + } else { + return Result.err(rdr); + } + + } + @ApiDoc( method = POST, path = "/authz/role/perm", @@ -1839,117 +1839,117 @@ public class AuthzCassServiceImpl addPermToRole(final AuthzTrans trans, REQUEST rreq) { - // Translate Request into Perm and Role Objects - final Result rpd = mapper.permFromRPRequest(trans, rreq); - if(rpd.notOKorIsEmpty()) { - return Result.err(rpd); - } - final Result rrd = mapper.roleFromRPRequest(trans, rreq); - if(rrd.notOKorIsEmpty()) { - return Result.err(rrd); - } - - // Validate Role and Perm values - final ServiceValidator v = new ServiceValidator(); - if(v.perm(rpd.value) - .role(rrd.value) - .err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result> rlrd = ques.roleDAO.read(trans, rrd.value.ns, rrd.value.name); - if(rlrd.notOKorIsEmpty()) { - return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName()); - } - - // Check Status of Data in DB (does it exist) - Result> rlpd = ques.permDAO.read(trans, rpd.value.ns, - rpd.value.type, rpd.value.instance, rpd.value.action); - PermDAO.Data createPerm = null; // if not null, create first - if(rlpd.notOKorIsEmpty()) { // Permission doesn't exist - if(trans.requested(force)) { - // Remove roles from perm data object so we just create the perm here - createPerm = rpd.value; - createPerm.roles.clear(); - } else { - return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist", - rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action); - } - } else { - if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) { - return Result.err(Status.ERR_ConflictAlreadyExists, - "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]", - rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action, - rrd.value.ns,rrd.value.name - ); - } - } - - - Result fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals - new Mapper.Memo() { - @Override - public String get() { - return "Grant Permission [" + rpd.value.fullPerm() + ']' + - " to Role [" + rrd.value.fullName() + "]"; - } - }, - new MayChange() { - private Result nsd; - @Override - public Result mayChange() { - if(nsd==null) { - nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write); - } - return nsd; - } - }); - Result> nsr = ques.nsDAO.read(trans, rpd.value.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans,fd.value, - rpd.value.fullPerm(), - trans.user(), - nsr.value.get(0), - FUTURE_OP.G); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing", - rpd.value.ns, - rpd.value.type, - rpd.value.instance, - rpd.value.action); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - Result rv = null; - if(createPerm!=null) {// has been validated for creating - rv = func.createPerm(trans, createPerm, false); - } - if(rv==null || rv.isOK()) { - rv = func.addPermToRole(trans, rrd.value, rpd.value, false); - } - return rv; - default: - return Result.err(fd); - } - - } - - /** - * Delete Perms from Roles (UnGrant) - * @param trans - * @param roleFullName - * @return - */ + @Override + public Result addPermToRole(final AuthzTrans trans, REQUEST rreq) { + // Translate Request into Perm and Role Objects + final Result rpd = mapper.permFromRPRequest(trans, rreq); + if(rpd.notOKorIsEmpty()) { + return Result.err(rpd); + } + final Result rrd = mapper.roleFromRPRequest(trans, rreq); + if(rrd.notOKorIsEmpty()) { + return Result.err(rrd); + } + + // Validate Role and Perm values + final ServiceValidator v = new ServiceValidator(); + if(v.perm(rpd.value) + .role(rrd.value) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlrd = ques.roleDAO.read(trans, rrd.value.ns, rrd.value.name); + if(rlrd.notOKorIsEmpty()) { + return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName()); + } + + // Check Status of Data in DB (does it exist) + Result> rlpd = ques.permDAO.read(trans, rpd.value.ns, + rpd.value.type, rpd.value.instance, rpd.value.action); + PermDAO.Data createPerm = null; // if not null, create first + if(rlpd.notOKorIsEmpty()) { // Permission doesn't exist + if(trans.requested(force)) { + // Remove roles from perm data object so we just create the perm here + createPerm = rpd.value; + createPerm.roles.clear(); + } else { + return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist", + rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action); + } + } else { + if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) { + return Result.err(Status.ERR_ConflictAlreadyExists, + "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]", + rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action, + rrd.value.ns,rrd.value.name + ); + } + } + + + Result fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals + new Mapper.Memo() { + @Override + public String get() { + return "Grant Permission [" + rpd.value.fullPerm() + ']' + + " to Role [" + rrd.value.fullName() + "]"; + } + }, + new MayChange() { + private Result nsd; + @Override + public Result mayChange() { + if(nsd==null) { + nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write); + } + return nsd; + } + }); + Result> nsr = ques.nsDAO.read(trans, rpd.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans,fd.value, + rpd.value.fullPerm(), + trans.user(), + nsr.value.get(0), + FUTURE_OP.G); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing", + rpd.value.ns, + rpd.value.type, + rpd.value.instance, + rpd.value.action); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + Result rv = null; + if(createPerm!=null) {// has been validated for creating + rv = func.createPerm(trans, createPerm, false); + } + if(rv==null || rv.isOK()) { + rv = func.addPermToRole(trans, rrd.value, rpd.value, false); + } + return rv; + default: + return Result.err(fd); + } + + } + + /** + * Delete Perms from Roles (UnGrant) + * @param trans + * @param roleFullName + * @return + */ @ApiDoc( method = DELETE, path = "/authz/role/:role/perm", @@ -1959,132 +1959,132 @@ public class AuthzCassServiceImpl delPermFromRole(final AuthzTrans trans, REQUEST rreq) { - final Result updt = mapper.permFromRPRequest(trans, rreq); - if(updt.notOKorIsEmpty()) { - return Result.err(updt); - } - final Result rrd = mapper.roleFromRPRequest(trans, rreq); - if(rrd.notOKorIsEmpty()) { - return Result.err(rrd); - } - - final ServiceValidator v = new ServiceValidator(); - if(v.nullOrBlank(updt.value) - .nullOrBlank(rrd.value) - .err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - return delPermFromRole(trans, updt.value,rrd.value, rreq); + @Override + public Result delPermFromRole(final AuthzTrans trans, REQUEST rreq) { + final Result updt = mapper.permFromRPRequest(trans, rreq); + if(updt.notOKorIsEmpty()) { + return Result.err(updt); + } + final Result rrd = mapper.roleFromRPRequest(trans, rreq); + if(rrd.notOKorIsEmpty()) { + return Result.err(rrd); + } + + final ServiceValidator v = new ServiceValidator(); + if(v.nullOrBlank(updt.value) + .nullOrBlank(rrd.value) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + return delPermFromRole(trans, updt.value,rrd.value, rreq); + } + + private Result delPermFromRole(final AuthzTrans trans, PermDAO.Data pdd, RoleDAO.Data rdd, REQUEST rreq) { + Result> rlpd = ques.permDAO.read(trans, pdd.ns, pdd.type, + pdd.instance, pdd.action); + + if(rlpd.notOKorIsEmpty()) { + return Result.err(Status.ERR_PermissionNotFound, + "Permission [%s.%s|%s|%s] does not exist", + pdd.ns,pdd.type,pdd.instance,pdd.action); + } + + Result fd = mapper.future(trans, PermDAO.TABLE, rreq, pdd,true, // allow ungrants requests + new Mapper.Memo() { + @Override + public String get() { + return "Ungrant Permission [" + pdd.fullPerm() + ']' + + " from Role [" + rdd.fullName() + "]"; + } + }, + new MayChange() { + private Result nsd; + @Override + public Result mayChange() { + if(nsd==null) { + nsd = ques.mayUser(trans, trans.user(), pdd, Access.write); + } + return nsd; + } + }); + Result> nsr = ques.nsDAO.read(trans, pdd.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans,fd.value, + pdd.fullPerm(), + trans.user(), + nsr.value.get(0), + FUTURE_OP.UG + ); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing", + pdd.ns, + pdd.type, + pdd.instance, + pdd.action); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + return func.delPermFromRole(trans, rdd, pdd, false); + default: + return Result.err(fd); + } } - - private Result delPermFromRole(final AuthzTrans trans, PermDAO.Data pdd, RoleDAO.Data rdd, REQUEST rreq) { - Result> rlpd = ques.permDAO.read(trans, pdd.ns, pdd.type, - pdd.instance, pdd.action); - - if(rlpd.notOKorIsEmpty()) { - return Result.err(Status.ERR_PermissionNotFound, - "Permission [%s.%s|%s|%s] does not exist", - pdd.ns,pdd.type,pdd.instance,pdd.action); - } - - Result fd = mapper.future(trans, PermDAO.TABLE, rreq, pdd,true, // allow ungrants requests - new Mapper.Memo() { - @Override - public String get() { - return "Ungrant Permission [" + pdd.fullPerm() + ']' + - " from Role [" + rdd.fullName() + "]"; - } - }, - new MayChange() { - private Result nsd; - @Override - public Result mayChange() { - if(nsd==null) { - nsd = ques.mayUser(trans, trans.user(), pdd, Access.write); - } - return nsd; - } - }); - Result> nsr = ques.nsDAO.read(trans, pdd.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans,fd.value, - pdd.fullPerm(), - trans.user(), - nsr.value.get(0), - FUTURE_OP.UG - ); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing", - pdd.ns, - pdd.type, - pdd.instance, - pdd.action); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - return func.delPermFromRole(trans, rdd, pdd, false); - default: - return Result.err(fd); - } - } /* @ApiDoc( method = DELETE, path = "/authz/role/:role/perm/:type/:instance/:action", params = {"role|string|true", - "perm type|string|true", - "perm instance|string|true", - "perm action|string|true" - }, + "perm type|string|true", + "perm instance|string|true", + "perm action|string|true" + }, expectedCode = 200, errorCodes = {404,406}, text = { "Ungrant a single permission from Role :role with direct key" } ) */ - @Override + @Override public Result delPermFromRole(AuthzTrans trans, String role, String type, String instance, String action) { - Result rpns = ques.deriveNs(trans, type); - if(rpns.notOKorIsEmpty()) { - return Result.err(rpns); - } - - final Validator v = new ServiceValidator(); - if(v.role(role) - .permType(rpns.value.name,rpns.value.parent) - .permInstance(instance) - .permAction(action) - .err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result rrns = ques.deriveNs(trans, role); - if(rrns.notOKorIsEmpty()) { - return Result.err(rrns); - } - - final Result> rrd = ques.roleDAO.read(trans, rrns.value.parent, rrns.value.name); - if(rrd.notOKorIsEmpty()) { - return Result.err(rrd); - } - - final Result> rpd = ques.permDAO.read(trans, rpns.value.parent, rpns.value.name, instance, action); - if(rpd.notOKorIsEmpty()) { - return Result.err(rpd); - } - - - return delPermFromRole(trans,rpd.value.get(0), rrd.value.get(0), mapper.ungrantRequest(trans, role, type, instance, action)); - } - + Result rpns = ques.deriveNs(trans, type); + if(rpns.notOKorIsEmpty()) { + return Result.err(rpns); + } + + final Validator v = new ServiceValidator(); + if(v.role(role) + .permType(rpns.value.name,rpns.value.parent) + .permInstance(instance) + .permAction(action) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rrns = ques.deriveNs(trans, role); + if(rrns.notOKorIsEmpty()) { + return Result.err(rrns); + } + + final Result> rrd = ques.roleDAO.read(trans, rrns.value.parent, rrns.value.name); + if(rrd.notOKorIsEmpty()) { + return Result.err(rrd); + } + + final Result> rpd = ques.permDAO.read(trans, rpns.value.parent, rpns.value.name, instance, action); + if(rpd.notOKorIsEmpty()) { + return Result.err(rpd); + } + + + return delPermFromRole(trans,rpd.value.get(0), rrd.value.get(0), mapper.ungrantRequest(trans, role, type, instance, action)); + } + @ApiDoc( method = DELETE, path = "/authz/role/:role", @@ -2094,19 +2094,19 @@ public class AuthzCassServiceImpl deleteRole(AuthzTrans trans, String role) { - Result rrdd = RoleDAO.Data.decode(trans,ques,role); - if(rrdd.isOKhasData()) { - final ServiceValidator v = new ServiceValidator(); - if(v.nullOrBlank(rrdd.value).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - return func.deleteRole(trans, rrdd.value, false, false); - } else { - return Result.err(rrdd); - } - } + @Override + public Result deleteRole(AuthzTrans trans, String role) { + Result rrdd = RoleDAO.Data.decode(trans,ques,role); + if(rrdd.isOKhasData()) { + final ServiceValidator v = new ServiceValidator(); + if(v.nullOrBlank(rrdd.value).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + return func.deleteRole(trans, rrdd.value, false, false); + } else { + return Result.err(rrdd); + } + } @ApiDoc( method = DELETE, @@ -2115,2134 +2115,2134 @@ public class AuthzCassServiceImpl WARNING: Using force will remove all users and permission from this role. Use with care.

    "} + "You cannot normally delete a role which still has permissions granted or users assigned to it,", + "however the \"force\" property allows you to do just that. To do this: Add 'force=true'", + "as a query parameter.", + "

    WARNING: Using force will remove all users and permission from this role. Use with care.

    "} ) - @Override - public Result deleteRole(final AuthzTrans trans, REQUEST from) { - final Result rd = mapper.role(trans, from); - final ServiceValidator v = new ServiceValidator(); - if(rd==null) { - return Result.err(Status.ERR_BadData,"Request does not contain Role"); - } - if(v.nullOrBlank(rd.value).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - final RoleDAO.Data role = rd.value; - if(ques.roleDAO.read(trans, role).notOKorIsEmpty() && !trans.requested(force)) { - return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist"); - } - - Result fd = mapper.future(trans,RoleDAO.TABLE,from,role,false, - new Mapper.Memo() { - @Override - public String get() { - return "Delete Role [" + role.fullName() + ']' - + " and all attached user roles"; - } - }, - new MayChange() { - private Result nsd; - @Override - public Result mayChange() { - if(nsd==null) { - nsd = ques.mayUser(trans, trans.user(), role, Access.write); - } - return nsd; - } - }); - - switch(fd.status) { - case OK: - Result> nsr = ques.nsDAO.read(trans, rd.value.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - Result rfc = func.createFuture(trans, fd.value, - role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing", - rd.value.ns, - rd.value.name); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - return func.deleteRole(trans,role,trans.requested(force), true /*preapproved*/); - default: - return Result.err(fd); - } - - } + @Override + public Result deleteRole(final AuthzTrans trans, REQUEST from) { + final Result rd = mapper.role(trans, from); + final ServiceValidator v = new ServiceValidator(); + if(rd==null) { + return Result.err(Status.ERR_BadData,"Request does not contain Role"); + } + if(v.nullOrBlank(rd.value).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + final RoleDAO.Data role = rd.value; + if(ques.roleDAO.read(trans, role).notOKorIsEmpty() && !trans.requested(force)) { + return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist"); + } + + Result fd = mapper.future(trans,RoleDAO.TABLE,from,role,false, + new Mapper.Memo() { + @Override + public String get() { + return "Delete Role [" + role.fullName() + ']' + + " and all attached user roles"; + } + }, + new MayChange() { + private Result nsd; + @Override + public Result mayChange() { + if(nsd==null) { + nsd = ques.mayUser(trans, trans.user(), role, Access.write); + } + return nsd; + } + }); + + switch(fd.status) { + case OK: + Result> nsr = ques.nsDAO.read(trans, rd.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + Result rfc = func.createFuture(trans, fd.value, + role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing", + rd.value.ns, + rd.value.name); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + return func.deleteRole(trans,role,trans.requested(force), true /*preapproved*/); + default: + return Result.err(fd); + } + + } /*********************************** * CRED ***********************************/ - private class MayCreateCred implements MayChange { - private Result nsd; - private AuthzTrans trans; - private CredDAO.Data cred; - private Executor exec; - - public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) { - this.trans = trans; - this.cred = cred; - this.exec = exec; - } - - @Override - public Result mayChange() { - if(nsd==null) { - nsd = ques.validNSOfDomain(trans, cred.id); - } - // is Ns of CredID valid? - if(nsd.isOK()) { - try { - // Check Org Policy - if(trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) { - return Result.ok(); - } else { - Result rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write); - if(rmc.isOKhasData()) { - return rmc; - } - } - } catch (Exception e) { - trans.warn().log(e); - } - } else { - trans.warn().log(nsd.errorString()); - } - return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns); - } - } - - private class MayChangeCred implements MayChange { - - private Result nsd; - private AuthzTrans trans; - private CredDAO.Data cred; - public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) { - this.trans = trans; - this.cred = cred; - } - - @Override - public Result mayChange() { - // User can change himself (but not create) - if(trans.user().equals(cred.id)) { - return Result.ok(); - } - if(nsd==null) { - nsd = ques.validNSOfDomain(trans, cred.id); - } - // Get the Namespace - if(nsd.isOK()) { - if(ques.mayUser(trans, trans.user(), nsd.value,Access.write).isOK()) { - return Result.ok(); - } - String user[] = Split.split('.',trans.user()); - if(user.length>2) { - String company = user[user.length-1] + '.' + user[user.length-2]; - if(ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,"reset")) { - return Result.ok(); - } - } - } - return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns); - } - - } - - private final long DAY_IN_MILLIS = 24*3600*1000L; - - @ApiDoc( - method = POST, - path = "/authn/cred", - params = {}, - expectedCode = 201, - errorCodes = {403,404,406,409}, - text = { "A credential consists of:", - "
    • id - the ID to create within AAF. The domain is in reverse", - "order of Namespace (i.e. Users of Namespace com.att.myapp would be", - "AB1234@myapp.att.com
    • ", - "
    • password - Company Policy Compliant Password
    ", - "Note: AAF does support multiple credentials with the same ID.", - "Check with your organization if you have this implemented." - } - ) - @Override - public Result createUserCred(final AuthzTrans trans, REQUEST from) { - final String cmdDescription = ("Create User Credential"); - TimeTaken tt = trans.start(cmdDescription, Env.SUB); - - try { - Result rcred = mapper.cred(trans, from, true); - if(rcred.isOKhasData()) { - byte[] rawCred = rcred.value.cred.array(); - rcred = ques.userCredSetup(trans, rcred.value); - - final ServiceValidator v = new ServiceValidator(); - - if(v.cred(trans, trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations - return Result.err(Status.ERR_BadData,v.errs()); - } - - - // 2016-4 Jonathan, New Behavior - If MechID is not registered with Org, deny creation - Identity mechID = null; - Organization org = trans.org(); - try { - mechID = org.getIdentity(trans, rcred.value.id); - } catch (Exception e1) { - trans.error().log(e1,rcred.value.id,"cannot be validated at this time"); - } - if(mechID==null || !mechID.isFound()) { - return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName()); - } - - Result> nsr = ques.nsDAO.read(trans, rcred.value.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns); - } - - - boolean firstID = false; - MayChange mc; - - CassExecutor exec = new CassExecutor(trans, func); - Result> rlcd = ques.credDAO.readID(trans, rcred.value.id); - if (rlcd.isOKhasData()) { - if (!org.canHaveMultipleCreds(rcred.value.id)) { - return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists"); - } - Result rb; - for (CredDAO.Data curr : rlcd.value) { - // May not use the same password in the list - // Note: ASPR specifies character differences, but we don't actually store the - // password to validate char differences. - - rb = ques.userCredCheck(trans, curr, rawCred); - if(rb.notOK()) { - return Result.err(rb); - } else if(rb.value){ - return Result.err(Status.ERR_Policy, "Credential content cannot be reused."); - } else if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) { - return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'"); - } - } - } else { - try { - // 2016-04-12 Jonathan If Caller is the Sponsor and is also an Owner of NS, allow without special Perm - String theMechID = rcred.value.id; - Boolean otherMechIDs = false; - // find out if this is the only mechID. other MechIDs mean special handling (not automated) - for(CredDAO.Data cd : ques.credDAO.readNS(trans,nsr.value.get(0).name).value) { - if(!cd.id.equals(theMechID)) { - otherMechIDs = true; - break; - } - } - String reason; - // We can say "ID does not exist" here - if((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) { - return Result.err(Status.ERR_Denied, reason); - } - firstID=true; - } catch (Exception e) { - return Result.err(e); - } - } - - mc = new MayCreateCred(trans, rcred.value, exec); - - final CredDAO.Data cdd = rcred.value; - Result fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future. - new Mapper.Memo() { - @Override - public String get() { - return cmdDescription + " [" + - cdd.id + '|' - + cdd.type + '|' - + cdd.expires + ']'; - } - }, - mc); - - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans, fd.value, - rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires, - trans.user(), nsr.value.get(0), FUTURE_OP.C); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing", - rcred.value.id, - Integer.toString(rcred.value.type), - rcred.value.expires.toString()); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - try { - if(firstID) { - // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) { - Result> admins = func.getAdmins(trans, nsr.value.get(0).name, false); - // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length - // Note, we only do this on First time, because of possibility of - // prematurely expiring a production id - if(admins.isOKhasData() && !admins.value.contains(trans.user())) { - rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime(); - } - } - } catch (Exception e) { - trans.error().log(e, "While setting expiration to TempPassword"); - } - Resultudr = ques.credDAO.create(trans, rcred.value); - if(udr.isOK()) { - return Result.ok(); - } - return Result.err(udr); - default: - return Result.err(fd); - } - - } else { - return Result.err(rcred); - } - } finally { - tt.done(); - } - } - - @ApiDoc( - method = GET, - path = "/authn/creds/ns/:ns", - params = {"ns|string|true"}, - expectedCode = 200, - errorCodes = {403,404,406}, - text = { "Return all IDs in Namespace :ns" - } - ) - @Override - public Result getCredsByNS(AuthzTrans trans, String ns) { - final Validator v = new ServiceValidator(); - if(v.ns(ns).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // check if user is allowed to view NS - Result rnd = ques.deriveNs(trans,ns); - if(rnd.notOK()) { - return Result.err(rnd); - } - rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - - TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB); - try { - USERS users = mapper.newInstance(API.USERS); - Result> rlcd = ques.credDAO.readNS(trans, ns); - - if(rlcd.isOK()) { - if(!rlcd.isEmpty()) { - return mapper.cred(rlcd.value, users); - } - return Result.ok(users); - } else { - return Result.err(rlcd); - } - } finally { - tt.done(); - } - - } - - @ApiDoc( - method = GET, - path = "/authn/creds/id/:ns", - params = {"id|string|true"}, - expectedCode = 200, - errorCodes = {403,404,406}, - text = { "Return all IDs in for ID" - ,"(because IDs are multiple, due to multiple Expiration Dates)" - } - ) - @Override - public Result getCredsByID(AuthzTrans trans, String id) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("ID",id).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - String ns = Question.domain2ns(id); - // check if user is allowed to view NS - Result rnd = ques.deriveNs(trans,ns); - if(rnd.notOK()) { - return Result.err(rnd); - } - rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - - TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB); - try { - USERS users = mapper.newInstance(API.USERS); - Result> rlcd = ques.credDAO.readID(trans, id); - - if(rlcd.isOK()) { - if(!rlcd.isEmpty()) { - return mapper.cred(rlcd.value, users); - } - return Result.ok(users); - } else { - return Result.err(rlcd); - } - } finally { - tt.done(); - } - - } - - @ApiDoc( - method = GET, - path = "/authn/certs/id/:id", - params = {"id|string|true"}, - expectedCode = 200, - errorCodes = {403,404,406}, - text = { "Return Cert Info for ID" - } - ) - @Override - public Result getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) { - TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB); - try { - CERTS certs = mapper.newInstance(API.CERTS); - Result> rlcd = ques.certDAO.readID(trans, id); - - if(rlcd.isOK()) { - if(!rlcd.isEmpty()) { - return mapper.cert(rlcd.value, certs); - } - return Result.ok(certs); - } else { - return Result.err(rlcd); - } - } finally { - tt.done(); - } - - } - - @ApiDoc( - method = PUT, - path = "/authn/cred", - params = {}, - expectedCode = 200, - errorCodes = {300,403,404,406}, - text = { "Reset a Credential Password. If multiple credentials exist for this", - "ID, you will need to specify which entry you are resetting in the", - "CredRequest object" - } - ) - @Override - public Result changeUserCred(final AuthzTrans trans, REQUEST from) { - final String cmdDescription = "Update User Credential"; - TimeTaken tt = trans.start(cmdDescription, Env.SUB); - try { - Result rcred = mapper.cred(trans, from, true); - if(rcred.isOKhasData()) { - rcred = ques.userCredSetup(trans, rcred.value); - - final ServiceValidator v = new ServiceValidator(); - - if(v.cred(trans, trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations - return Result.err(Status.ERR_BadData,v.errs()); - } - Result> rlcd = ques.credDAO.readID(trans, rcred.value.id); - if(rlcd.notOKorIsEmpty()) { - return Result.err(Status.ERR_UserNotFound, "Credential does not exist"); - } - - MayChange mc = new MayChangeCred(trans, rcred.value); - Result rmc = mc.mayChange(); - if (rmc.notOK()) { - return Result.err(rmc); - } - - Result ri = selectEntryIfMultiple((CredRequest)from, rlcd.value); - if(ri.notOK()) { - return Result.err(ri); - } - int entry = ri.value; - - - final CredDAO.Data cred = rcred.value; - - Result fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, - new Mapper.Memo() { - @Override - public String get() { - return cmdDescription + " [" + - cred.id + '|' - + cred.type + '|' - + cred.expires + ']'; - } - }, - mc); - - Result> nsr = ques.nsDAO.read(trans, rcred.value.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans, fd.value, - rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires, - trans.user(), nsr.value.get(0), FUTURE_OP.U); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]", - rcred.value.id, - Integer.toString(rcred.value.type), - rcred.value.expires.toString()); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - Resultudr = null; - // If we are Resetting Password on behalf of someone else (am not the Admin) - // use TempPassword Expiration time. - Expiration exp; - if(ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) { - exp = Expiration.Password; - } else { - exp = Expiration.TempPassword; - } - - Organization org = trans.org(); - CredDAO.Data current = rlcd.value.get(entry); - // If user resets password in same day, we will have a primary key conflict, so subtract 1 day - if (current.expires.equals(rcred.value.expires) - && rlcd.value.get(entry).type==rcred.value.type) { - GregorianCalendar gc = org.expiration(null, exp,rcred.value.id); - gc = Chrono.firstMomentOfDay(gc); - gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay()); - rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS); - } else { - rcred.value.expires = org.expiration(null,exp).getTime(); - } - // Copy in other fields 10/21/2016 - rcred.value.notes=current.notes; - - udr = ques.credDAO.create(trans, rcred.value); - if(udr.isOK()) { - udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false); - } - if (udr.isOK()) { - return Result.ok(); - } - - return Result.err(udr); - default: - return Result.err(fd); - } - } else { - return Result.err(rcred); - } - } finally { - tt.done(); - } - } - - /* - * Codify the way to get Either Choice Needed or actual Integer from Credit Request - */ - private Result selectEntryIfMultiple(final CredRequest cr, List lcd) { - int entry = 0; - if (lcd.size() > 1) { - String inputOption = cr.getEntry(); - if (inputOption == null) { - String message = selectCredFromList(lcd, false); - String[] variables = buildVariables(lcd); - return Result.err(Status.ERR_ChoiceNeeded, message, variables); - } else { - entry = Integer.parseInt(inputOption) - 1; - } - if (entry < 0 || entry >= lcd.size()) { - return Result.err(Status.ERR_BadData, "User chose invalid credential selection"); - } - } - return Result.ok(entry); - } - - @ApiDoc( - method = PUT, - path = "/authn/cred/:days", - params = {"days|string|true"}, - expectedCode = 200, - errorCodes = {300,403,404,406}, - text = { "Extend a Credential Expiration Date. The intention of this API is", - "to avoid an outage in PROD due to a Credential expiring before it", - "can be configured correctly. Measures are being put in place ", - "so that this is not abused." - } - ) - @Override - public Result extendUserCred(final AuthzTrans trans, REQUEST from, String days) { - TimeTaken tt = trans.start("Extend User Credential", Env.SUB); - try { - Result cred = mapper.cred(trans, from, false); - Organization org = trans.org(); - final ServiceValidator v = new ServiceValidator(); - if(v.notOK(cred).err() || - v.nullOrBlank(cred.value.id, "Invalid ID").err() || - v.user(org,cred.value.id).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - try { - String reason; - if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) { - return Result.err(Status.ERR_Policy,reason); - } - } catch (Exception e) { - String msg; - trans.error().log(e, msg="Could not contact Organization for User Validation"); - return Result.err(Status.ERR_Denied, msg); - } - - // Get the list of Cred Entries - Result> rlcd = ques.credDAO.readID(trans, cred.value.id); - if(rlcd.notOKorIsEmpty()) { - return Result.err(Status.ERR_UserNotFound, "Credential does not exist"); - } - - //Need to do the "Pick Entry" mechanism - Result ri = selectEntryIfMultiple((CredRequest)from, rlcd.value); - if(ri.notOK()) { - return Result.err(ri); - } - - CredDAO.Data found = rlcd.value.get(ri.value); - CredDAO.Data cd = cred.value; - // Copy over the cred - cd.id = found.id; - cd.cred = found.cred; - cd.other = found.other; - cd.type = found.type; - cd.notes = found.notes; - cd.ns = found.ns; - cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime(); - - cred = ques.credDAO.create(trans, cd); - if(cred.isOK()) { - return Result.ok(); - } - return Result.err(cred); - } finally { - tt.done(); - } - } - - private String[] buildVariables(List value) { - // ensure credentials are sorted so we can fully automate Cred regression test - Collections.sort(value, new Comparator() { - @Override - public int compare(CredDAO.Data cred1, CredDAO.Data cred2) { - return cred1.expires.compareTo(cred2.expires); - } - }); - String [] vars = new String[value.size()+1]; - vars[0]="Choice"; - for (int i = 0; i < value.size(); i++) { - vars[i+1] = value.get(i).id + " " + value.get(i).type - + " |" + value.get(i).expires; - } - return vars; - } - - private String selectCredFromList(List value, boolean isDelete) { - StringBuilder errMessage = new StringBuilder(); - String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:"; - int numSpaces = value.get(0).id.length() - "Id".length(); - - errMessage.append(userPrompt + '\n'); - errMessage.append(" Id"); - for (int i = 0; i < numSpaces; i++) { - errMessage.append(' '); - } - errMessage.append(" Type Expires" + '\n'); - for(int i=0;i deleteUserCred(AuthzTrans trans, REQUEST from) { - final Result cred = mapper.cred(trans, from, false); - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("cred", cred.value.id).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result> rlcd = ques.credDAO.readID(trans, cred.value.id); - if(rlcd.notOKorIsEmpty()) { - // Empty Creds should have no user_roles. - Result> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id); - if(rlurd.isOK()) { - for(UserRoleDAO.Data data : rlurd.value) { - ques.userRoleDAO.delete(trans, data, false); - } - } - return Result.err(Status.ERR_UserNotFound, "Credential does not exist"); - } - boolean isLastCred = rlcd.value.size()==1; - - MayChange mc = new MayChangeCred(trans,cred.value); - Result rmc = mc.mayChange(); - if (rmc.notOK()) { - return Result.err(rmc); - } - - int entry = 0; - if(!trans.requested(force)) { - if (rlcd.value.size() > 1) { - CredRequest cr = (CredRequest)from; - String inputOption = cr.getEntry(); - if (inputOption == null) { - String message = selectCredFromList(rlcd.value, true); - String[] variables = buildVariables(rlcd.value); - return Result.err(Status.ERR_ChoiceNeeded, message, variables); - } else { - try { - if(inputOption.length()>5) { // should be a date - Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime(); - entry = 0; - for(CredDAO.Data cd : rlcd.value) { - if(cd.type.equals(cr.getType()) && cd.expires.equals(d)) { - break; - } - ++entry; - } - } else { - entry = Integer.parseInt(inputOption) - 1; - } - } catch(NullPointerException e) { - return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry"); - } catch(NumberFormatException e) { - return Result.err(Status.ERR_BadData, "User chose invalid credential selection"); - } - } - isLastCred = (entry==-1)?true:false; - } else { - isLastCred = true; - } - if (entry < -1 || entry >= rlcd.value.size()) { - return Result.err(Status.ERR_BadData, "User chose invalid credential selection"); - } - } - - Result fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false, - new Mapper.Memo() { - @Override - public String get() { - return "Delete Credential [" + - cred.value.id + - ']'; - } - }, - mc); - - Result> nsr = ques.nsDAO.read(trans, cred.value.ns); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans, fd.value, cred.value.id, - trans.user(), nsr.value.get(0), FUTURE_OP.D); - - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - Resultudr = null; - if (!trans.requested(force)) { - if(entry<0 || entry >= rlcd.value.size()) { - return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id); - } - udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false); - } else { - for (CredDAO.Data curr : rlcd.value) { - udr = ques.credDAO.delete(trans, curr, false); - if (udr.notOK()) { - return Result.err(udr); - } - } - } - if(isLastCred) { - Result> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id); - if(rlurd.isOK()) { - for(UserRoleDAO.Data data : rlurd.value) { - ques.userRoleDAO.delete(trans, data, false); - } - } - } - if(udr==null) { - return Result.err(Result.ERR_NotFound,"No User Data found"); - } - if (udr.isOK()) { - return Result.ok(); - } - return Result.err(udr); - default: - return Result.err(fd); - } - - } - - - @Override - public Result doesCredentialMatch(AuthzTrans trans, REQUEST credReq) { - TimeTaken tt = trans.start("Does Credential Match", Env.SUB); - try { - // Note: Mapper assigns RAW type - Result data = mapper.cred(trans, credReq,false); - if(data.notOKorIsEmpty()) { - return Result.err(data); - } - CredDAO.Data cred = data.value; // of the Mapped Cred - if(cred.cred==null) { - return Result.err(Result.ERR_BadData,"No Password"); - } else { - return ques.doesUserCredMatch(trans, cred.id, cred.cred.array()); - } - - } catch (DAOException e) { - trans.error().log(e,"Error looking up cred"); - return Result.err(Status.ERR_Denied,"Credential does not match"); - } finally { - tt.done(); - } - } - - @ApiDoc( - method = GET, - path = "/authn/basicAuth", - params = {}, - expectedCode = 200, - errorCodes = { 403 }, - text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n" - + "Use /authn/validate instead\n" - + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast" - + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth " - + "security, and 403 if it does not." } - ) - private void basicAuth() { - // This is a place holder for Documentation. The real BasicAuth API does not call Service. - } - - @ApiDoc( - method = POST, - path = "/authn/validate", - params = {}, - expectedCode = 200, - errorCodes = { 403 }, - text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can " - + "do more than BasicAuth as Credential types exp" } - ) - @Override - public Result validateBasicAuth(AuthzTrans trans, String basicAuth) { - //TODO how to make sure people don't use this in browsers? Do we care? - TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB); - try { - BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm()); - Result rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred()); - // Note: Only want to log problem, don't want to send back to end user - if(rq.isOK()) { - return rq; - } else { - trans.audit().log(rq.errorString()); - } - } catch (Exception e) { - trans.warn().log(e); - } finally { - tt.done(); - } - return Result.err(Status.ERR_Denied,"Bad Basic Auth"); - } + private class MayCreateCred implements MayChange { + private Result nsd; + private AuthzTrans trans; + private CredDAO.Data cred; + private Executor exec; + + public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) { + this.trans = trans; + this.cred = cred; + this.exec = exec; + } + + @Override + public Result mayChange() { + if(nsd==null) { + nsd = ques.validNSOfDomain(trans, cred.id); + } + // is Ns of CredID valid? + if(nsd.isOK()) { + try { + // Check Org Policy + if(trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) { + return Result.ok(); + } else { + Result rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write); + if(rmc.isOKhasData()) { + return rmc; + } + } + } catch (Exception e) { + trans.warn().log(e); + } + } else { + trans.warn().log(nsd.errorString()); + } + return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns); + } + } + + private class MayChangeCred implements MayChange { + + private Result nsd; + private AuthzTrans trans; + private CredDAO.Data cred; + public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) { + this.trans = trans; + this.cred = cred; + } + + @Override + public Result mayChange() { + // User can change himself (but not create) + if(trans.user().equals(cred.id)) { + return Result.ok(); + } + if(nsd==null) { + nsd = ques.validNSOfDomain(trans, cred.id); + } + // Get the Namespace + if(nsd.isOK()) { + if(ques.mayUser(trans, trans.user(), nsd.value,Access.write).isOK()) { + return Result.ok(); + } + String user[] = Split.split('.',trans.user()); + if(user.length>2) { + String company = user[user.length-1] + '.' + user[user.length-2]; + if(ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,"reset")) { + return Result.ok(); + } + } + } + return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns); + } + + } + + private final long DAY_IN_MILLIS = 24*3600*1000L; + + @ApiDoc( + method = POST, + path = "/authn/cred", + params = {}, + expectedCode = 201, + errorCodes = {403,404,406,409}, + text = { "A credential consists of:", + "
    • id - the ID to create within AAF. The domain is in reverse", + "order of Namespace (i.e. Users of Namespace com.att.myapp would be", + "AB1234@myapp.att.com
    • ", + "
    • password - Company Policy Compliant Password
    ", + "Note: AAF does support multiple credentials with the same ID.", + "Check with your organization if you have this implemented." + } + ) + @Override + public Result createUserCred(final AuthzTrans trans, REQUEST from) { + final String cmdDescription = ("Create User Credential"); + TimeTaken tt = trans.start(cmdDescription, Env.SUB); + + try { + Result rcred = mapper.cred(trans, from, true); + if(rcred.isOKhasData()) { + byte[] rawCred = rcred.value.cred.array(); + rcred = ques.userCredSetup(trans, rcred.value); + + final ServiceValidator v = new ServiceValidator(); + + if(v.cred(trans, trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations + return Result.err(Status.ERR_BadData,v.errs()); + } + + + // 2016-4 Jonathan, New Behavior - If MechID is not registered with Org, deny creation + Identity mechID = null; + Organization org = trans.org(); + try { + mechID = org.getIdentity(trans, rcred.value.id); + } catch (Exception e1) { + trans.error().log(e1,rcred.value.id,"cannot be validated at this time"); + } + if(mechID==null || !mechID.isFound()) { + return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName()); + } + + Result> nsr = ques.nsDAO.read(trans, rcred.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns); + } + + + boolean firstID = false; + MayChange mc; + + CassExecutor exec = new CassExecutor(trans, func); + Result> rlcd = ques.credDAO.readID(trans, rcred.value.id); + if (rlcd.isOKhasData()) { + if (!org.canHaveMultipleCreds(rcred.value.id)) { + return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists"); + } + Result rb; + for (CredDAO.Data curr : rlcd.value) { + // May not use the same password in the list + // Note: ASPR specifies character differences, but we don't actually store the + // password to validate char differences. + + rb = ques.userCredCheck(trans, curr, rawCred); + if(rb.notOK()) { + return Result.err(rb); + } else if(rb.value){ + return Result.err(Status.ERR_Policy, "Credential content cannot be reused."); + } else if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) { + return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'"); + } + } + } else { + try { + // 2016-04-12 Jonathan If Caller is the Sponsor and is also an Owner of NS, allow without special Perm + String theMechID = rcred.value.id; + Boolean otherMechIDs = false; + // find out if this is the only mechID. other MechIDs mean special handling (not automated) + for(CredDAO.Data cd : ques.credDAO.readNS(trans,nsr.value.get(0).name).value) { + if(!cd.id.equals(theMechID)) { + otherMechIDs = true; + break; + } + } + String reason; + // We can say "ID does not exist" here + if((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) { + return Result.err(Status.ERR_Denied, reason); + } + firstID=true; + } catch (Exception e) { + return Result.err(e); + } + } + + mc = new MayCreateCred(trans, rcred.value, exec); + + final CredDAO.Data cdd = rcred.value; + Result fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future. + new Mapper.Memo() { + @Override + public String get() { + return cmdDescription + " [" + + cdd.id + '|' + + cdd.type + '|' + + cdd.expires + ']'; + } + }, + mc); + + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans, fd.value, + rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires, + trans.user(), nsr.value.get(0), FUTURE_OP.C); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing", + rcred.value.id, + Integer.toString(rcred.value.type), + rcred.value.expires.toString()); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + try { + if(firstID) { + // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) { + Result> admins = func.getAdmins(trans, nsr.value.get(0).name, false); + // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length + // Note, we only do this on First time, because of possibility of + // prematurely expiring a production id + if(admins.isOKhasData() && !admins.value.contains(trans.user())) { + rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime(); + } + } + } catch (Exception e) { + trans.error().log(e, "While setting expiration to TempPassword"); + } + Resultudr = ques.credDAO.create(trans, rcred.value); + if(udr.isOK()) { + return Result.ok(); + } + return Result.err(udr); + default: + return Result.err(fd); + } + + } else { + return Result.err(rcred); + } + } finally { + tt.done(); + } + } + + @ApiDoc( + method = GET, + path = "/authn/creds/ns/:ns", + params = {"ns|string|true"}, + expectedCode = 200, + errorCodes = {403,404,406}, + text = { "Return all IDs in Namespace :ns" + } + ) + @Override + public Result getCredsByNS(AuthzTrans trans, String ns) { + final Validator v = new ServiceValidator(); + if(v.ns(ns).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // check if user is allowed to view NS + Result rnd = ques.deriveNs(trans,ns); + if(rnd.notOK()) { + return Result.err(rnd); + } + rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB); + try { + USERS users = mapper.newInstance(API.USERS); + Result> rlcd = ques.credDAO.readNS(trans, ns); + + if(rlcd.isOK()) { + if(!rlcd.isEmpty()) { + return mapper.cred(rlcd.value, users); + } + return Result.ok(users); + } else { + return Result.err(rlcd); + } + } finally { + tt.done(); + } + + } + + @ApiDoc( + method = GET, + path = "/authn/creds/id/:ns", + params = {"id|string|true"}, + expectedCode = 200, + errorCodes = {403,404,406}, + text = { "Return all IDs in for ID" + ,"(because IDs are multiple, due to multiple Expiration Dates)" + } + ) + @Override + public Result getCredsByID(AuthzTrans trans, String id) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("ID",id).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + String ns = Question.domain2ns(id); + // check if user is allowed to view NS + Result rnd = ques.deriveNs(trans,ns); + if(rnd.notOK()) { + return Result.err(rnd); + } + rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB); + try { + USERS users = mapper.newInstance(API.USERS); + Result> rlcd = ques.credDAO.readID(trans, id); + + if(rlcd.isOK()) { + if(!rlcd.isEmpty()) { + return mapper.cred(rlcd.value, users); + } + return Result.ok(users); + } else { + return Result.err(rlcd); + } + } finally { + tt.done(); + } + + } + + @ApiDoc( + method = GET, + path = "/authn/certs/id/:id", + params = {"id|string|true"}, + expectedCode = 200, + errorCodes = {403,404,406}, + text = { "Return Cert Info for ID" + } + ) + @Override + public Result getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) { + TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB); + try { + CERTS certs = mapper.newInstance(API.CERTS); + Result> rlcd = ques.certDAO.readID(trans, id); + + if(rlcd.isOK()) { + if(!rlcd.isEmpty()) { + return mapper.cert(rlcd.value, certs); + } + return Result.ok(certs); + } else { + return Result.err(rlcd); + } + } finally { + tt.done(); + } + + } + + @ApiDoc( + method = PUT, + path = "/authn/cred", + params = {}, + expectedCode = 200, + errorCodes = {300,403,404,406}, + text = { "Reset a Credential Password. If multiple credentials exist for this", + "ID, you will need to specify which entry you are resetting in the", + "CredRequest object" + } + ) + @Override + public Result changeUserCred(final AuthzTrans trans, REQUEST from) { + final String cmdDescription = "Update User Credential"; + TimeTaken tt = trans.start(cmdDescription, Env.SUB); + try { + Result rcred = mapper.cred(trans, from, true); + if(rcred.isOKhasData()) { + rcred = ques.userCredSetup(trans, rcred.value); + + final ServiceValidator v = new ServiceValidator(); + + if(v.cred(trans, trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations + return Result.err(Status.ERR_BadData,v.errs()); + } + Result> rlcd = ques.credDAO.readID(trans, rcred.value.id); + if(rlcd.notOKorIsEmpty()) { + return Result.err(Status.ERR_UserNotFound, "Credential does not exist"); + } + + MayChange mc = new MayChangeCred(trans, rcred.value); + Result rmc = mc.mayChange(); + if (rmc.notOK()) { + return Result.err(rmc); + } + + Result ri = selectEntryIfMultiple((CredRequest)from, rlcd.value); + if(ri.notOK()) { + return Result.err(ri); + } + int entry = ri.value; + + + final CredDAO.Data cred = rcred.value; + + Result fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, + new Mapper.Memo() { + @Override + public String get() { + return cmdDescription + " [" + + cred.id + '|' + + cred.type + '|' + + cred.expires + ']'; + } + }, + mc); + + Result> nsr = ques.nsDAO.read(trans, rcred.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans, fd.value, + rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires, + trans.user(), nsr.value.get(0), FUTURE_OP.U); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]", + rcred.value.id, + Integer.toString(rcred.value.type), + rcred.value.expires.toString()); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + Resultudr = null; + // If we are Resetting Password on behalf of someone else (am not the Admin) + // use TempPassword Expiration time. + Expiration exp; + if(ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) { + exp = Expiration.Password; + } else { + exp = Expiration.TempPassword; + } + + Organization org = trans.org(); + CredDAO.Data current = rlcd.value.get(entry); + // If user resets password in same day, we will have a primary key conflict, so subtract 1 day + if (current.expires.equals(rcred.value.expires) + && rlcd.value.get(entry).type==rcred.value.type) { + GregorianCalendar gc = org.expiration(null, exp,rcred.value.id); + gc = Chrono.firstMomentOfDay(gc); + gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay()); + rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS); + } else { + rcred.value.expires = org.expiration(null,exp).getTime(); + } + // Copy in other fields 10/21/2016 + rcred.value.notes=current.notes; + + udr = ques.credDAO.create(trans, rcred.value); + if(udr.isOK()) { + udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false); + } + if (udr.isOK()) { + return Result.ok(); + } + + return Result.err(udr); + default: + return Result.err(fd); + } + } else { + return Result.err(rcred); + } + } finally { + tt.done(); + } + } + + /* + * Codify the way to get Either Choice Needed or actual Integer from Credit Request + */ + private Result selectEntryIfMultiple(final CredRequest cr, List lcd) { + int entry = 0; + if (lcd.size() > 1) { + String inputOption = cr.getEntry(); + if (inputOption == null) { + String message = selectCredFromList(lcd, false); + String[] variables = buildVariables(lcd); + return Result.err(Status.ERR_ChoiceNeeded, message, variables); + } else { + entry = Integer.parseInt(inputOption) - 1; + } + if (entry < 0 || entry >= lcd.size()) { + return Result.err(Status.ERR_BadData, "User chose invalid credential selection"); + } + } + return Result.ok(entry); + } + + @ApiDoc( + method = PUT, + path = "/authn/cred/:days", + params = {"days|string|true"}, + expectedCode = 200, + errorCodes = {300,403,404,406}, + text = { "Extend a Credential Expiration Date. The intention of this API is", + "to avoid an outage in PROD due to a Credential expiring before it", + "can be configured correctly. Measures are being put in place ", + "so that this is not abused." + } + ) + @Override + public Result extendUserCred(final AuthzTrans trans, REQUEST from, String days) { + TimeTaken tt = trans.start("Extend User Credential", Env.SUB); + try { + Result cred = mapper.cred(trans, from, false); + Organization org = trans.org(); + final ServiceValidator v = new ServiceValidator(); + if(v.notOK(cred).err() || + v.nullOrBlank(cred.value.id, "Invalid ID").err() || + v.user(org,cred.value.id).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + try { + String reason; + if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) { + return Result.err(Status.ERR_Policy,reason); + } + } catch (Exception e) { + String msg; + trans.error().log(e, msg="Could not contact Organization for User Validation"); + return Result.err(Status.ERR_Denied, msg); + } + + // Get the list of Cred Entries + Result> rlcd = ques.credDAO.readID(trans, cred.value.id); + if(rlcd.notOKorIsEmpty()) { + return Result.err(Status.ERR_UserNotFound, "Credential does not exist"); + } + + //Need to do the "Pick Entry" mechanism + Result ri = selectEntryIfMultiple((CredRequest)from, rlcd.value); + if(ri.notOK()) { + return Result.err(ri); + } + + CredDAO.Data found = rlcd.value.get(ri.value); + CredDAO.Data cd = cred.value; + // Copy over the cred + cd.id = found.id; + cd.cred = found.cred; + cd.other = found.other; + cd.type = found.type; + cd.notes = found.notes; + cd.ns = found.ns; + cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime(); + + cred = ques.credDAO.create(trans, cd); + if(cred.isOK()) { + return Result.ok(); + } + return Result.err(cred); + } finally { + tt.done(); + } + } + + private String[] buildVariables(List value) { + // ensure credentials are sorted so we can fully automate Cred regression test + Collections.sort(value, new Comparator() { + @Override + public int compare(CredDAO.Data cred1, CredDAO.Data cred2) { + return cred1.expires.compareTo(cred2.expires); + } + }); + String [] vars = new String[value.size()+1]; + vars[0]="Choice"; + for (int i = 0; i < value.size(); i++) { + vars[i+1] = value.get(i).id + " " + value.get(i).type + + " |" + value.get(i).expires; + } + return vars; + } + + private String selectCredFromList(List value, boolean isDelete) { + StringBuilder errMessage = new StringBuilder(); + String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:"; + int numSpaces = value.get(0).id.length() - "Id".length(); + + errMessage.append(userPrompt + '\n'); + errMessage.append(" Id"); + for (int i = 0; i < numSpaces; i++) { + errMessage.append(' '); + } + errMessage.append(" Type Expires" + '\n'); + for(int i=0;i deleteUserCred(AuthzTrans trans, REQUEST from) { + final Result cred = mapper.cred(trans, from, false); + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("cred", cred.value.id).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlcd = ques.credDAO.readID(trans, cred.value.id); + if(rlcd.notOKorIsEmpty()) { + // Empty Creds should have no user_roles. + Result> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id); + if(rlurd.isOK()) { + for(UserRoleDAO.Data data : rlurd.value) { + ques.userRoleDAO.delete(trans, data, false); + } + } + return Result.err(Status.ERR_UserNotFound, "Credential does not exist"); + } + boolean isLastCred = rlcd.value.size()==1; + + MayChange mc = new MayChangeCred(trans,cred.value); + Result rmc = mc.mayChange(); + if (rmc.notOK()) { + return Result.err(rmc); + } + + int entry = 0; + if(!trans.requested(force)) { + if (rlcd.value.size() > 1) { + CredRequest cr = (CredRequest)from; + String inputOption = cr.getEntry(); + if (inputOption == null) { + String message = selectCredFromList(rlcd.value, true); + String[] variables = buildVariables(rlcd.value); + return Result.err(Status.ERR_ChoiceNeeded, message, variables); + } else { + try { + if(inputOption.length()>5) { // should be a date + Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime(); + entry = 0; + for(CredDAO.Data cd : rlcd.value) { + if(cd.type.equals(cr.getType()) && cd.expires.equals(d)) { + break; + } + ++entry; + } + } else { + entry = Integer.parseInt(inputOption) - 1; + } + } catch(NullPointerException e) { + return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry"); + } catch(NumberFormatException e) { + return Result.err(Status.ERR_BadData, "User chose invalid credential selection"); + } + } + isLastCred = (entry==-1)?true:false; + } else { + isLastCred = true; + } + if (entry < -1 || entry >= rlcd.value.size()) { + return Result.err(Status.ERR_BadData, "User chose invalid credential selection"); + } + } + + Result fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false, + new Mapper.Memo() { + @Override + public String get() { + return "Delete Credential [" + + cred.value.id + + ']'; + } + }, + mc); + + Result> nsr = ques.nsDAO.read(trans, cred.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans, fd.value, cred.value.id, + trans.user(), nsr.value.get(0), FUTURE_OP.D); + + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + Resultudr = null; + if (!trans.requested(force)) { + if(entry<0 || entry >= rlcd.value.size()) { + return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id); + } + udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false); + } else { + for (CredDAO.Data curr : rlcd.value) { + udr = ques.credDAO.delete(trans, curr, false); + if (udr.notOK()) { + return Result.err(udr); + } + } + } + if(isLastCred) { + Result> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id); + if(rlurd.isOK()) { + for(UserRoleDAO.Data data : rlurd.value) { + ques.userRoleDAO.delete(trans, data, false); + } + } + } + if(udr==null) { + return Result.err(Result.ERR_NotFound,"No User Data found"); + } + if (udr.isOK()) { + return Result.ok(); + } + return Result.err(udr); + default: + return Result.err(fd); + } + + } + + + @Override + public Result doesCredentialMatch(AuthzTrans trans, REQUEST credReq) { + TimeTaken tt = trans.start("Does Credential Match", Env.SUB); + try { + // Note: Mapper assigns RAW type + Result data = mapper.cred(trans, credReq,false); + if(data.notOKorIsEmpty()) { + return Result.err(data); + } + CredDAO.Data cred = data.value; // of the Mapped Cred + if(cred.cred==null) { + return Result.err(Result.ERR_BadData,"No Password"); + } else { + return ques.doesUserCredMatch(trans, cred.id, cred.cred.array()); + } + + } catch (DAOException e) { + trans.error().log(e,"Error looking up cred"); + return Result.err(Status.ERR_Denied,"Credential does not match"); + } finally { + tt.done(); + } + } + + @ApiDoc( + method = GET, + path = "/authn/basicAuth", + params = {}, + expectedCode = 200, + errorCodes = { 403 }, + text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n" + + "Use /authn/validate instead\n" + + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast" + + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth " + + "security, and 403 if it does not." } + ) + private void basicAuth() { + // This is a place holder for Documentation. The real BasicAuth API does not call Service. + } + + @ApiDoc( + method = POST, + path = "/authn/validate", + params = {}, + expectedCode = 200, + errorCodes = { 403 }, + text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can " + + "do more than BasicAuth as Credential types exp" } + ) + @Override + public Result validateBasicAuth(AuthzTrans trans, String basicAuth) { + //TODO how to make sure people don't use this in browsers? Do we care? + TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB); + try { + BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm()); + Result rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred()); + // Note: Only want to log problem, don't want to send back to end user + if(rq.isOK()) { + return rq; + } else { + trans.audit().log(rq.errorString()); + } + } catch (Exception e) { + trans.warn().log(e); + } finally { + tt.done(); + } + return Result.err(Status.ERR_Denied,"Bad Basic Auth"); + } /*********************************** * USER-ROLE ***********************************/ - @ApiDoc( - method = POST, - path = "/authz/userRole", - params = {}, - expectedCode = 201, - errorCodes = {403,404,406,409}, - text = { "Create a UserRole relationship (add User to Role)", - "A UserRole is an object Representation of membership of a Role for limited time.", - "If a shorter amount of time for Role ownership is required, use the 'End' field.", - "** Note: Owners of Namespaces will be required to revalidate users in these roles ", - "before Expirations expire. Namespace owners will be notified by email." - } - ) - @Override - public Result createUserRole(final AuthzTrans trans, REQUEST from) { - TimeTaken tt = trans.start("Create UserRole", Env.SUB); - try { - Result urr = mapper.userRole(trans, from); - if(urr.notOKorIsEmpty()) { - return Result.err(urr); - } - final UserRoleDAO.Data userRole = urr.value; - - final ServiceValidator v = new ServiceValidator(); - if(v.user_role(userRole).err() || - v.user(trans.org(), userRole.user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - - - // Check if user can change first - Result fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals - new Mapper.Memo() { - @Override - public String get() { - return "Add User [" + userRole.user + "] to Role [" + - userRole.role + - ']'; - } - }, - new MayChange() { - private Result nsd; - @Override - public Result mayChange() { - if(nsd==null) { - RoleDAO.Data r = RoleDAO.Data.decode(userRole); - nsd = ques.mayUser(trans, trans.user(), r, Access.write); - } - return nsd; - } - }); - Result nsr = ques.deriveNs(trans, userRole.role); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname, - userRole.user, nsr.value, FUTURE_OP.C); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing", - userRole.user, - userRole.ns, - userRole.rname); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - return func.addUserRole(trans, userRole); - default: - return Result.err(fd); - } - } finally { - tt.done(); - } - } - - /** - * getUserRolesByRole - */ - @ApiDoc( - method = GET, - path = "/authz/userRoles/role/:role", - params = {"role|string|true"}, - expectedCode = 200, - errorCodes = {404,406}, - text = { "List all Users that are attached to Role specified in :role", - } - ) - @Override - public Result getUserRolesByRole(AuthzTrans trans, String role) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Role",role).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result rrdd; - rrdd = RoleDAO.Data.decode(trans,ques,role); - if(rrdd.notOK()) { - return Result.err(rrdd); - } - // May Requester see result? - Result ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read); - if (ns.notOK()) { - return Result.err(ns); - } - - // boolean filter = true; - // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user())) - // filter = false; - - // Get list of roles per user, then add to Roles as we go - HashSet userSet = new HashSet<>(); - Result> rlurd = ques.userRoleDAO.readByRole(trans, role); - if(rlurd.isOK()) { - for(UserRoleDAO.Data data : rlurd.value) { - userSet.add(data); - } - } - - @SuppressWarnings("unchecked") - USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES); - // Checked for permission - mapper.userRoles(trans, userSet, users); - return Result.ok(users); - } - /** - * getUserRolesByRole - */ - @ApiDoc( - method = GET, - path = "/authz/userRoles/user/:user", - params = {"role|string|true"}, - expectedCode = 200, - errorCodes = {404,406}, - text = { "List all UserRoles for :user", - } - ) - @Override - public Result getUserRolesByUser(AuthzTrans trans, String user) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("User",user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // Get list of roles per user, then add to Roles as we go - Result> rlurd = ques.userRoleDAO.readByUser(trans, user); - if(rlurd.notOK()) { - return Result.err(rlurd); - } - - /* Check for - * 1) is User - * 2) is User's Supervisor - * 3) Has special global access =read permission - * - * If none of the 3, then filter results to NSs in which Calling User has Ns.access * read - */ - boolean mustFilter; - String callingUser = trans.getUserPrincipal().getName(); - NsDAO.Data ndd = new NsDAO.Data(); - - if(user.equals(callingUser)) { - mustFilter = false; - } else { - Organization org = trans.org(); - try { - Identity orgID = org.getIdentity(trans, user); - Identity manager = orgID==null?null:orgID.responsibleTo(); - if(orgID!=null && (manager!=null && callingUser.equals(manager.fullID()))) { - mustFilter = false; - } else if(ques.isGranted(trans, callingUser, ROOT_NS, Question.ACCESS, "*", Access.read.name())) { - mustFilter=false; - } else { - mustFilter = true; - } - } catch (OrganizationException e) { - trans.env().log(e); - mustFilter = true; - } - } - - List content; - if(mustFilter) { - content = new ArrayList<>(rlurd.value.size()); // avoid multi-memory redos - - for(UserRoleDAO.Data data : rlurd.value) { - ndd.name=data.ns; - Result mur = ques.mayUser(trans, callingUser, ndd, Access.read); - if(mur.isOK()){ - content.add(data); - } - } - - } else { - content = rlurd.value; - } - - - @SuppressWarnings("unchecked") - USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES); - // Checked for permission - mapper.userRoles(trans, content, users); - return Result.ok(users); - } - - - @ApiDoc( - method = PUT, - path = "/authz/userRole/user", - params = {}, - expectedCode = 200, - errorCodes = {403,404,406}, - text = { "Set a User's roles to the roles specified in the UserRoleRequest object.", - "WARNING: Roles supplied will be the ONLY roles attached to this user", - "If no roles are supplied, user's roles are reset." - } - ) - @Override - public Result resetRolesForUser(AuthzTrans trans, REQUEST rreq) { - Result rurdd = mapper.userRole(trans, rreq); - final ServiceValidator v = new ServiceValidator(); - if(rurdd.notOKorIsEmpty()) { - return Result.err(rurdd); - } - if (v.user(trans.org(), rurdd.value.user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Set currRoles = new HashSet<>(); - Result> rlurd = ques.userRoleDAO.readByUser(trans, rurdd.value.user); - if(rlurd.isOK()) { - for(UserRoleDAO.Data data : rlurd.value) { - currRoles.add(data.role); - } - } - - Result rv = null; - String[] roles; - if(rurdd.value.role==null) { - roles = new String[0]; - } else { - roles = rurdd.value.role.split(","); - } - - for (String role : roles) { - if (v.role(role).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - Result rrdd = RoleDAO.Data.decode(trans, ques, role); - if(rrdd.notOK()) { - return Result.err(rrdd); - } - - rurdd.value.role(rrdd.value); - - Result nsd = ques.mayUser(trans, trans.user(), rrdd.value,Access.write); - if (nsd.notOK()) { - return Result.err(nsd); - } - Result nsr = ques.deriveNs(trans, role); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - if(currRoles.contains(role)) { - currRoles.remove(role); - } else { - rv = func.addUserRole(trans, rurdd.value); - if (rv.notOK()) { - return rv; - } - } - } - - for (String role : currRoles) { - rurdd.value.role(trans,ques,role); - rv = ques.userRoleDAO.delete(trans, rurdd.value, false); - if(rv.notOK()) { - trans.info().log(rurdd.value.user,"/",rurdd.value.role, "expected to be deleted, but does not exist"); - // return rv; // if it doesn't exist, don't error out - } - - } - - return Result.ok(); - - } - - @ApiDoc( - method = PUT, - path = "/authz/userRole/role", - params = {}, - expectedCode = 200, - errorCodes = {403,404,406}, - text = { "Set a Role's users to the users specified in the UserRoleRequest object.", - "WARNING: Users supplied will be the ONLY users attached to this role", - "If no users are supplied, role's users are reset." - } - ) - @Override - public Result resetUsersForRole(AuthzTrans trans, REQUEST rreq) { - Result rurdd = mapper.userRole(trans, rreq); - if(rurdd.notOKorIsEmpty()) { - return Result.err(rurdd); - } - final ServiceValidator v = new ServiceValidator(); - if (v.user_role(rurdd.value).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - RoleDAO.Data rd = RoleDAO.Data.decode(rurdd.value); - - Result nsd = ques.mayUser(trans, trans.user(), rd, Access.write); - if (nsd.notOK()) { - return Result.err(nsd); - } - - Result nsr = ques.deriveNs(trans, rurdd.value.role); - if(nsr.notOKorIsEmpty()) { - return Result.err(nsr); - } - - Set currUsers = new HashSet<>(); - Result> rlurd = ques.userRoleDAO.readByRole(trans, rurdd.value.role); - if(rlurd.isOK()) { - for(UserRoleDAO.Data data : rlurd.value) { - currUsers.add(data.user); - } - } - - // found when connected remotely to DEVL, can't replicate locally - // inconsistent errors with cmd: role user setTo [nothing] - // deleteUserRole --> read --> get --> cacheIdx(?) - // sometimes returns idx for last added user instead of user passed in - // cache bug? - - - Result rv = null; - String[] users = {}; - if (rurdd.value.user != null) { - users = rurdd.value.user.split(","); - } - - for (String user : users) { - if (v.user(trans.org(), user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - rurdd.value.user = user; - - if(currUsers.contains(user)) { - currUsers.remove(user); - } else { - rv = func.addUserRole(trans, rurdd.value); - if (rv.notOK()) { - return rv; - } - } - } - - for (String user : currUsers) { - rurdd.value.user = user; - rv = ques.userRoleDAO.delete(trans, rurdd.value, false); - if(rv.notOK()) { - trans.info().log(rurdd.value, "expected to be deleted, but not exists"); - return rv; - } - } - - return Result.ok(); - } - - @ApiDoc( - method = GET, - path = "/authz/userRole/extend/:user/:role", - params = { "user|string|true", - "role|string|true" - }, - expectedCode = 200, - errorCodes = {403,404,406}, - text = { "Extend the Expiration of this User Role by the amount set by Organization", - "Requestor must be allowed to modify the role" - } - ) - @Override - public Result extendUserRole(AuthzTrans trans, String user, String role) { - Organization org = trans.org(); - final ServiceValidator v = new ServiceValidator(); - if(v.user(org, user) - .role(role) - .err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result rrdd = RoleDAO.Data.decode(trans,ques,role); - if(rrdd.notOK()) { - return Result.err(rrdd); - } - - Result rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write); - boolean mayNotChange; - if((mayNotChange = rcr.notOK()) && !trans.requested(future)) { - return Result.err(rcr); - } - - Result> rr = ques.userRoleDAO.read(trans, user,role); - if(rr.notOK()) { - return Result.err(rr); - } - for(UserRoleDAO.Data userRole : rr.value) { - if(mayNotChange) { // Function exited earlier if !trans.futureRequested - FutureDAO.Data fto = new FutureDAO.Data(); - fto.target=UserRoleDAO.TABLE; - fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]"; - GregorianCalendar now = new GregorianCalendar(); - fto.start = now.getTime(); - fto.expires = org.expiration(now, Expiration.Future).getTime(); - try { - fto.construct = userRole.bytify(); - } catch (IOException e) { - trans.error().log(e, "Error while bytifying UserRole for Future"); - return Result.err(e); - } - - Result rfc = func.createFuture(trans, fto, - userRole.user+'|'+userRole.role, userRole.user, rcr.value, FUTURE_OP.U); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing", - userRole.user, - userRole.role); - } else { - return Result.err(rfc); - } - } else { - return func.extendUserRole(trans, userRole, false); - } - } - return Result.err(Result.ERR_NotFound,"This user and role doesn't exist"); - } - - @ApiDoc( - method = DELETE, - path = "/authz/userRole/:user/:role", - params = { "user|string|true", - "role|string|true" - }, - expectedCode = 200, - errorCodes = {403,404,406}, - text = { "Remove Role :role from User :user." - } - ) - @Override - public Result deleteUserRole(AuthzTrans trans, String usr, String role) { - Validator val = new ServiceValidator(); - if(val.nullOrBlank("User", usr) - .nullOrBlank("Role", role).err()) { - return Result.err(Status.ERR_BadData, val.errs()); - } - - boolean mayNotChange; - Result rrdd = RoleDAO.Data.decode(trans,ques,role); - if(rrdd.notOK()) { - return Result.err(rrdd); - } - - RoleDAO.Data rdd = rrdd.value; - Result rns = ques.mayUser(trans, trans.user(), rdd, Access.write); - - // Make sure we don't delete the last owner of valid NS - if(rns.isOKhasData() && Question.OWNER.equals(rdd.name) && ques.countOwner(trans,rdd.ns)<=1) { - return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns ); - } - - if(mayNotChange=rns.notOK()) { - if(!trans.requested(future)) { - return Result.err(rns); - } - } - - Result> rulr; - if((rulr=ques.userRoleDAO.read(trans, usr, role)).notOKorIsEmpty()) { - return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not " - + "Assigned to the Role [ " + role + " ]"); - } - - UserRoleDAO.Data userRole = rulr.value.get(0); - if(mayNotChange) { // Function exited earlier if !trans.futureRequested - FutureDAO.Data fto = new FutureDAO.Data(); - fto.target=UserRoleDAO.TABLE; - fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]"; - GregorianCalendar now = new GregorianCalendar(); - fto.start = now.getTime(); - fto.expires = trans.org().expiration(now, Expiration.Future).getTime(); - - Result rfc = func.createFuture(trans, fto, - userRole.user+'|'+userRole.role, userRole.user, rns.value, FUTURE_OP.D); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing", - userRole.user, - userRole.role); - } else { - return Result.err(rfc); - } - } else { - return ques.userRoleDAO.delete(trans, rulr.value.get(0), false); - } - } - - @ApiDoc( - method = GET, - path = "/authz/userRole/:user/:role", - params = {"user|string|true", - "role|string|true"}, - expectedCode = 200, - errorCodes = {403,404,406}, - text = { "Returns the User (with Expiration date from listed User/Role) if it exists" - } - ) - @Override - public Result getUserInRole(AuthzTrans trans, String user, String role) { - final Validator v = new ServiceValidator(); - if(v.role(role).nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - -// Result ns = ques.deriveNs(trans, role); -// if (ns.notOK()) return Result.err(ns); -// -// Result rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write); - // May calling user see by virtue of the Role - Result rrdd = RoleDAO.Data.decode(trans, ques, role); - if(rrdd.notOK()) { - return Result.err(rrdd); - } - Result rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - - HashSet userSet = new HashSet<>(); - Result> rlurd = ques.userRoleDAO.readUserInRole(trans, user, role); - if(rlurd.isOK()) { - for(UserRoleDAO.Data data : rlurd.value) { - userSet.add(data); - } - } - - @SuppressWarnings("unchecked") - USERS users = (USERS) mapper.newInstance(API.USERS); - mapper.users(trans, userSet, users); - return Result.ok(users); - } - - @ApiDoc( - method = GET, - path = "/authz/users/role/:role", - params = {"user|string|true", - "role|string|true"}, - expectedCode = 200, - errorCodes = {403,404,406}, - text = { "Returns the User (with Expiration date from listed User/Role) if it exists" - } - ) - @Override - public Result getUsersByRole(AuthzTrans trans, String role) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Role",role).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - -// Result ns = ques.deriveNs(trans, role); -// if (ns.notOK()) return Result.err(ns); -// -// Result rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write); - // May calling user see by virtue of the Role - Result rrdd = RoleDAO.Data.decode(trans, ques, role); - if(rrdd.notOK()) { - return Result.err(rrdd); - } - - boolean contactOnly = false; - // Allow the request of any valid user to find the contact of the NS (Owner) - Result rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read); - if(rnd.notOK()) { - if(Question.OWNER.equals(rrdd.value.name)) { - contactOnly = true; - } else { - return Result.err(rnd); - } - } - - HashSet userSet = new HashSet<>(); - Result> rlurd = ques.userRoleDAO.readByRole(trans, role); - if(rlurd.isOK()) { - for(UserRoleDAO.Data data : rlurd.value) { - if(contactOnly) { //scrub data - // Can't change actual object, or will mess up the cache. - UserRoleDAO.Data scrub = new UserRoleDAO.Data(); - scrub.ns = data.ns; - scrub.rname = data.rname; - scrub.role = data.role; - scrub.user = data.user; - userSet.add(scrub); - } else { - userSet.add(data); - } - } - } - - @SuppressWarnings("unchecked") - USERS users = (USERS) mapper.newInstance(API.USERS); - mapper.users(trans, userSet, users); - return Result.ok(users); - } - - /** - * getUsersByPermission - */ + @ApiDoc( + method = POST, + path = "/authz/userRole", + params = {}, + expectedCode = 201, + errorCodes = {403,404,406,409}, + text = { "Create a UserRole relationship (add User to Role)", + "A UserRole is an object Representation of membership of a Role for limited time.", + "If a shorter amount of time for Role ownership is required, use the 'End' field.", + "** Note: Owners of Namespaces will be required to revalidate users in these roles ", + "before Expirations expire. Namespace owners will be notified by email." + } + ) + @Override + public Result createUserRole(final AuthzTrans trans, REQUEST from) { + TimeTaken tt = trans.start("Create UserRole", Env.SUB); + try { + Result urr = mapper.userRole(trans, from); + if(urr.notOKorIsEmpty()) { + return Result.err(urr); + } + final UserRoleDAO.Data userRole = urr.value; + + final ServiceValidator v = new ServiceValidator(); + if(v.user_role(userRole).err() || + v.user(trans.org(), userRole.user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + + + // Check if user can change first + Result fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals + new Mapper.Memo() { + @Override + public String get() { + return "Add User [" + userRole.user + "] to Role [" + + userRole.role + + ']'; + } + }, + new MayChange() { + private Result nsd; + @Override + public Result mayChange() { + if(nsd==null) { + RoleDAO.Data r = RoleDAO.Data.decode(userRole); + nsd = ques.mayUser(trans, trans.user(), r, Access.write); + } + return nsd; + } + }); + Result nsr = ques.deriveNs(trans, userRole.role); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname, + userRole.user, nsr.value, FUTURE_OP.C); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing", + userRole.user, + userRole.ns, + userRole.rname); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + return func.addUserRole(trans, userRole); + default: + return Result.err(fd); + } + } finally { + tt.done(); + } + } + + /** + * getUserRolesByRole + */ + @ApiDoc( + method = GET, + path = "/authz/userRoles/role/:role", + params = {"role|string|true"}, + expectedCode = 200, + errorCodes = {404,406}, + text = { "List all Users that are attached to Role specified in :role", + } + ) + @Override + public Result getUserRolesByRole(AuthzTrans trans, String role) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Role",role).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rrdd; + rrdd = RoleDAO.Data.decode(trans,ques,role); + if(rrdd.notOK()) { + return Result.err(rrdd); + } + // May Requester see result? + Result ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read); + if (ns.notOK()) { + return Result.err(ns); + } + + // boolean filter = true; + // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user())) + // filter = false; + + // Get list of roles per user, then add to Roles as we go + HashSet userSet = new HashSet<>(); + Result> rlurd = ques.userRoleDAO.readByRole(trans, role); + if(rlurd.isOK()) { + for(UserRoleDAO.Data data : rlurd.value) { + userSet.add(data); + } + } + + @SuppressWarnings("unchecked") + USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES); + // Checked for permission + mapper.userRoles(trans, userSet, users); + return Result.ok(users); + } + /** + * getUserRolesByRole + */ + @ApiDoc( + method = GET, + path = "/authz/userRoles/user/:user", + params = {"role|string|true"}, + expectedCode = 200, + errorCodes = {404,406}, + text = { "List all UserRoles for :user", + } + ) + @Override + public Result getUserRolesByUser(AuthzTrans trans, String user) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User",user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // Get list of roles per user, then add to Roles as we go + Result> rlurd = ques.userRoleDAO.readByUser(trans, user); + if(rlurd.notOK()) { + return Result.err(rlurd); + } + + /* Check for + * 1) is User + * 2) is User's Supervisor + * 3) Has special global access =read permission + * + * If none of the 3, then filter results to NSs in which Calling User has Ns.access * read + */ + boolean mustFilter; + String callingUser = trans.getUserPrincipal().getName(); + NsDAO.Data ndd = new NsDAO.Data(); + + if(user.equals(callingUser)) { + mustFilter = false; + } else { + Organization org = trans.org(); + try { + Identity orgID = org.getIdentity(trans, user); + Identity manager = orgID==null?null:orgID.responsibleTo(); + if(orgID!=null && (manager!=null && callingUser.equals(manager.fullID()))) { + mustFilter = false; + } else if(ques.isGranted(trans, callingUser, ROOT_NS, Question.ACCESS, "*", Access.read.name())) { + mustFilter=false; + } else { + mustFilter = true; + } + } catch (OrganizationException e) { + trans.env().log(e); + mustFilter = true; + } + } + + List content; + if(mustFilter) { + content = new ArrayList<>(rlurd.value.size()); // avoid multi-memory redos + + for(UserRoleDAO.Data data : rlurd.value) { + ndd.name=data.ns; + Result mur = ques.mayUser(trans, callingUser, ndd, Access.read); + if(mur.isOK()){ + content.add(data); + } + } + + } else { + content = rlurd.value; + } + + + @SuppressWarnings("unchecked") + USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES); + // Checked for permission + mapper.userRoles(trans, content, users); + return Result.ok(users); + } + + + @ApiDoc( + method = PUT, + path = "/authz/userRole/user", + params = {}, + expectedCode = 200, + errorCodes = {403,404,406}, + text = { "Set a User's roles to the roles specified in the UserRoleRequest object.", + "WARNING: Roles supplied will be the ONLY roles attached to this user", + "If no roles are supplied, user's roles are reset." + } + ) + @Override + public Result resetRolesForUser(AuthzTrans trans, REQUEST rreq) { + Result rurdd = mapper.userRole(trans, rreq); + final ServiceValidator v = new ServiceValidator(); + if(rurdd.notOKorIsEmpty()) { + return Result.err(rurdd); + } + if (v.user(trans.org(), rurdd.value.user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Set currRoles = new HashSet<>(); + Result> rlurd = ques.userRoleDAO.readByUser(trans, rurdd.value.user); + if(rlurd.isOK()) { + for(UserRoleDAO.Data data : rlurd.value) { + currRoles.add(data.role); + } + } + + Result rv = null; + String[] roles; + if(rurdd.value.role==null) { + roles = new String[0]; + } else { + roles = rurdd.value.role.split(","); + } + + for (String role : roles) { + if (v.role(role).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + Result rrdd = RoleDAO.Data.decode(trans, ques, role); + if(rrdd.notOK()) { + return Result.err(rrdd); + } + + rurdd.value.role(rrdd.value); + + Result nsd = ques.mayUser(trans, trans.user(), rrdd.value,Access.write); + if (nsd.notOK()) { + return Result.err(nsd); + } + Result nsr = ques.deriveNs(trans, role); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + if(currRoles.contains(role)) { + currRoles.remove(role); + } else { + rv = func.addUserRole(trans, rurdd.value); + if (rv.notOK()) { + return rv; + } + } + } + + for (String role : currRoles) { + rurdd.value.role(trans,ques,role); + rv = ques.userRoleDAO.delete(trans, rurdd.value, false); + if(rv.notOK()) { + trans.info().log(rurdd.value.user,"/",rurdd.value.role, "expected to be deleted, but does not exist"); + // return rv; // if it doesn't exist, don't error out + } + + } + + return Result.ok(); + + } + + @ApiDoc( + method = PUT, + path = "/authz/userRole/role", + params = {}, + expectedCode = 200, + errorCodes = {403,404,406}, + text = { "Set a Role's users to the users specified in the UserRoleRequest object.", + "WARNING: Users supplied will be the ONLY users attached to this role", + "If no users are supplied, role's users are reset." + } + ) + @Override + public Result resetUsersForRole(AuthzTrans trans, REQUEST rreq) { + Result rurdd = mapper.userRole(trans, rreq); + if(rurdd.notOKorIsEmpty()) { + return Result.err(rurdd); + } + final ServiceValidator v = new ServiceValidator(); + if (v.user_role(rurdd.value).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + RoleDAO.Data rd = RoleDAO.Data.decode(rurdd.value); + + Result nsd = ques.mayUser(trans, trans.user(), rd, Access.write); + if (nsd.notOK()) { + return Result.err(nsd); + } + + Result nsr = ques.deriveNs(trans, rurdd.value.role); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + Set currUsers = new HashSet<>(); + Result> rlurd = ques.userRoleDAO.readByRole(trans, rurdd.value.role); + if(rlurd.isOK()) { + for(UserRoleDAO.Data data : rlurd.value) { + currUsers.add(data.user); + } + } + + // found when connected remotely to DEVL, can't replicate locally + // inconsistent errors with cmd: role user setTo [nothing] + // deleteUserRole --> read --> get --> cacheIdx(?) + // sometimes returns idx for last added user instead of user passed in + // cache bug? + + + Result rv = null; + String[] users = {}; + if (rurdd.value.user != null) { + users = rurdd.value.user.split(","); + } + + for (String user : users) { + if (v.user(trans.org(), user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + rurdd.value.user = user; + + if(currUsers.contains(user)) { + currUsers.remove(user); + } else { + rv = func.addUserRole(trans, rurdd.value); + if (rv.notOK()) { + return rv; + } + } + } + + for (String user : currUsers) { + rurdd.value.user = user; + rv = ques.userRoleDAO.delete(trans, rurdd.value, false); + if(rv.notOK()) { + trans.info().log(rurdd.value, "expected to be deleted, but not exists"); + return rv; + } + } + + return Result.ok(); + } + + @ApiDoc( + method = GET, + path = "/authz/userRole/extend/:user/:role", + params = { "user|string|true", + "role|string|true" + }, + expectedCode = 200, + errorCodes = {403,404,406}, + text = { "Extend the Expiration of this User Role by the amount set by Organization", + "Requestor must be allowed to modify the role" + } + ) + @Override + public Result extendUserRole(AuthzTrans trans, String user, String role) { + Organization org = trans.org(); + final ServiceValidator v = new ServiceValidator(); + if(v.user(org, user) + .role(role) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rrdd = RoleDAO.Data.decode(trans,ques,role); + if(rrdd.notOK()) { + return Result.err(rrdd); + } + + Result rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write); + boolean mayNotChange; + if((mayNotChange = rcr.notOK()) && !trans.requested(future)) { + return Result.err(rcr); + } + + Result> rr = ques.userRoleDAO.read(trans, user,role); + if(rr.notOK()) { + return Result.err(rr); + } + for(UserRoleDAO.Data userRole : rr.value) { + if(mayNotChange) { // Function exited earlier if !trans.futureRequested + FutureDAO.Data fto = new FutureDAO.Data(); + fto.target=UserRoleDAO.TABLE; + fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]"; + GregorianCalendar now = new GregorianCalendar(); + fto.start = now.getTime(); + fto.expires = org.expiration(now, Expiration.Future).getTime(); + try { + fto.construct = userRole.bytify(); + } catch (IOException e) { + trans.error().log(e, "Error while bytifying UserRole for Future"); + return Result.err(e); + } + + Result rfc = func.createFuture(trans, fto, + userRole.user+'|'+userRole.role, userRole.user, rcr.value, FUTURE_OP.U); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing", + userRole.user, + userRole.role); + } else { + return Result.err(rfc); + } + } else { + return func.extendUserRole(trans, userRole, false); + } + } + return Result.err(Result.ERR_NotFound,"This user and role doesn't exist"); + } + + @ApiDoc( + method = DELETE, + path = "/authz/userRole/:user/:role", + params = { "user|string|true", + "role|string|true" + }, + expectedCode = 200, + errorCodes = {403,404,406}, + text = { "Remove Role :role from User :user." + } + ) + @Override + public Result deleteUserRole(AuthzTrans trans, String usr, String role) { + Validator val = new ServiceValidator(); + if(val.nullOrBlank("User", usr) + .nullOrBlank("Role", role).err()) { + return Result.err(Status.ERR_BadData, val.errs()); + } + + boolean mayNotChange; + Result rrdd = RoleDAO.Data.decode(trans,ques,role); + if(rrdd.notOK()) { + return Result.err(rrdd); + } + + RoleDAO.Data rdd = rrdd.value; + Result rns = ques.mayUser(trans, trans.user(), rdd, Access.write); + + // Make sure we don't delete the last owner of valid NS + if(rns.isOKhasData() && Question.OWNER.equals(rdd.name) && ques.countOwner(trans,rdd.ns)<=1) { + return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns ); + } + + if(mayNotChange=rns.notOK()) { + if(!trans.requested(future)) { + return Result.err(rns); + } + } + + Result> rulr; + if((rulr=ques.userRoleDAO.read(trans, usr, role)).notOKorIsEmpty()) { + return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not " + + "Assigned to the Role [ " + role + " ]"); + } + + UserRoleDAO.Data userRole = rulr.value.get(0); + if(mayNotChange) { // Function exited earlier if !trans.futureRequested + FutureDAO.Data fto = new FutureDAO.Data(); + fto.target=UserRoleDAO.TABLE; + fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]"; + GregorianCalendar now = new GregorianCalendar(); + fto.start = now.getTime(); + fto.expires = trans.org().expiration(now, Expiration.Future).getTime(); + + Result rfc = func.createFuture(trans, fto, + userRole.user+'|'+userRole.role, userRole.user, rns.value, FUTURE_OP.D); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing", + userRole.user, + userRole.role); + } else { + return Result.err(rfc); + } + } else { + return ques.userRoleDAO.delete(trans, rulr.value.get(0), false); + } + } + + @ApiDoc( + method = GET, + path = "/authz/userRole/:user/:role", + params = {"user|string|true", + "role|string|true"}, + expectedCode = 200, + errorCodes = {403,404,406}, + text = { "Returns the User (with Expiration date from listed User/Role) if it exists" + } + ) + @Override + public Result getUserInRole(AuthzTrans trans, String user, String role) { + final Validator v = new ServiceValidator(); + if(v.role(role).nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + +// Result ns = ques.deriveNs(trans, role); +// if (ns.notOK()) return Result.err(ns); +// +// Result rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write); + // May calling user see by virtue of the Role + Result rrdd = RoleDAO.Data.decode(trans, ques, role); + if(rrdd.notOK()) { + return Result.err(rrdd); + } + Result rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + HashSet userSet = new HashSet<>(); + Result> rlurd = ques.userRoleDAO.readUserInRole(trans, user, role); + if(rlurd.isOK()) { + for(UserRoleDAO.Data data : rlurd.value) { + userSet.add(data); + } + } + + @SuppressWarnings("unchecked") + USERS users = (USERS) mapper.newInstance(API.USERS); + mapper.users(trans, userSet, users); + return Result.ok(users); + } + + @ApiDoc( + method = GET, + path = "/authz/users/role/:role", + params = {"user|string|true", + "role|string|true"}, + expectedCode = 200, + errorCodes = {403,404,406}, + text = { "Returns the User (with Expiration date from listed User/Role) if it exists" + } + ) + @Override + public Result getUsersByRole(AuthzTrans trans, String role) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Role",role).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + +// Result ns = ques.deriveNs(trans, role); +// if (ns.notOK()) return Result.err(ns); +// +// Result rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write); + // May calling user see by virtue of the Role + Result rrdd = RoleDAO.Data.decode(trans, ques, role); + if(rrdd.notOK()) { + return Result.err(rrdd); + } + + boolean contactOnly = false; + // Allow the request of any valid user to find the contact of the NS (Owner) + Result rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read); + if(rnd.notOK()) { + if(Question.OWNER.equals(rrdd.value.name)) { + contactOnly = true; + } else { + return Result.err(rnd); + } + } + + HashSet userSet = new HashSet<>(); + Result> rlurd = ques.userRoleDAO.readByRole(trans, role); + if(rlurd.isOK()) { + for(UserRoleDAO.Data data : rlurd.value) { + if(contactOnly) { //scrub data + // Can't change actual object, or will mess up the cache. + UserRoleDAO.Data scrub = new UserRoleDAO.Data(); + scrub.ns = data.ns; + scrub.rname = data.rname; + scrub.role = data.role; + scrub.user = data.user; + userSet.add(scrub); + } else { + userSet.add(data); + } + } + } + + @SuppressWarnings("unchecked") + USERS users = (USERS) mapper.newInstance(API.USERS); + mapper.users(trans, userSet, users); + return Result.ok(users); + } + + /** + * getUsersByPermission + */ @ApiDoc( method = GET, path = "/authz/users/perm/:type/:instance/:action", - params = { "type|string|true", - "instance|string|true", - "action|string|true" - }, + params = { "type|string|true", + "instance|string|true", + "action|string|true" + }, expectedCode = 200, errorCodes = {404,406}, text = { "List all Users that have Permission specified by :type :instance :action", - } + } ) - @Override - public Result getUsersByPermission(AuthzTrans trans, String type, String instance, String action) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Type",type) - .nullOrBlank("Instance",instance) - .nullOrBlank("Action",action) - .err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result nss = ques.deriveNsSplit(trans, type); - if(nss.notOK()) { - return Result.err(nss); - } - - Result> nsd = ques.nsDAO.read(trans, nss.value.ns); - if (nsd.notOK()) { - return Result.err(nsd); - } - - boolean allInstance = ASTERIX.equals(instance); - boolean allAction = ASTERIX.equals(action); - // Get list of roles per Permission, - // Then loop through Roles to get Users - // Note: Use Sets to avoid processing or responding with Duplicates - Set roleUsed = new HashSet<>(); - Set userSet = new HashSet<>(); - - if(!nss.isEmpty()) { - Result> rlp = ques.permDAO.readByType(trans, nss.value.ns, nss.value.name); - if(rlp.isOKhasData()) { - for(PermDAO.Data pd : rlp.value) { - if((allInstance || pd.instance.equals(instance)) && - (allAction || pd.action.equals(action))) { - if(ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) { - for(String role : pd.roles) { - if(!roleUsed.contains(role)) { // avoid evaluating Role many times - roleUsed.add(role); - Result> rlurd = ques.userRoleDAO.readByRole(trans, role.replace('|', '.')); - if(rlurd.isOKhasData()) { - for(UserRoleDAO.Data urd : rlurd.value) { - userSet.add(urd); - } - } - } - } - } - } - } - } - } - @SuppressWarnings("unchecked") - USERS users = (USERS) mapper.newInstance(API.USERS); - mapper.users(trans, userSet, users); - return Result.ok(users); - } + @Override + public Result getUsersByPermission(AuthzTrans trans, String type, String instance, String action) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Type",type) + .nullOrBlank("Instance",instance) + .nullOrBlank("Action",action) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result nss = ques.deriveNsSplit(trans, type); + if(nss.notOK()) { + return Result.err(nss); + } + + Result> nsd = ques.nsDAO.read(trans, nss.value.ns); + if (nsd.notOK()) { + return Result.err(nsd); + } + + boolean allInstance = ASTERIX.equals(instance); + boolean allAction = ASTERIX.equals(action); + // Get list of roles per Permission, + // Then loop through Roles to get Users + // Note: Use Sets to avoid processing or responding with Duplicates + Set roleUsed = new HashSet<>(); + Set userSet = new HashSet<>(); + + if(!nss.isEmpty()) { + Result> rlp = ques.permDAO.readByType(trans, nss.value.ns, nss.value.name); + if(rlp.isOKhasData()) { + for(PermDAO.Data pd : rlp.value) { + if((allInstance || pd.instance.equals(instance)) && + (allAction || pd.action.equals(action))) { + if(ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) { + for(String role : pd.roles) { + if(!roleUsed.contains(role)) { // avoid evaluating Role many times + roleUsed.add(role); + Result> rlurd = ques.userRoleDAO.readByRole(trans, role.replace('|', '.')); + if(rlurd.isOKhasData()) { + for(UserRoleDAO.Data urd : rlurd.value) { + userSet.add(urd); + } + } + } + } + } + } + } + } + } + @SuppressWarnings("unchecked") + USERS users = (USERS) mapper.newInstance(API.USERS); + mapper.users(trans, userSet, users); + return Result.ok(users); + } /*********************************** * HISTORY - ***********************************/ - @Override - public Result getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("User",user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result rnd; - // Users may look at their own data - if(trans.user().equals(user)) { - // Users may look at their own data - } else { - int at = user.indexOf('@'); - if(at>=0 && trans.org().getRealm().equals(user.substring(at+1))) { - NsDAO.Data nsd = new NsDAO.Data(); - nsd.name = Question.domain2ns(user); - rnd = ques.mayUser(trans, trans.user(), nsd, Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - } else { - rnd = ques.validNSOfDomain(trans, user); - if(rnd.notOK()) { - return Result.err(rnd); - } - - rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - } - } - Result> resp = ques.historyDAO.readByUser(trans, user, yyyymm); - if(resp.notOK()) { - return Result.err(resp); - } - return mapper.history(trans, resp.value,sort); - } - - @Override - public Result getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Role",role).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result rrdd = RoleDAO.Data.decode(trans, ques, role); - if(rrdd.notOK()) { - return Result.err(rrdd); - } - - Result rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - Result> resp = ques.historyDAO.readBySubject(trans, role, "role", yyyymm); - if(resp.notOK()) { - return Result.err(resp); - } - return mapper.history(trans, resp.value,sort); - } - - @Override - public Result getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Type",type) - .err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of") - Result rnd = ques.deriveNs(trans,type); - if(rnd.notOK()) { - return Result.err(rnd); - } - - rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - Result> resp = ques.historyDAO.readBySubject(trans, type, "perm", yyyymm); - if(resp.notOK()) { - return Result.err(resp); - } - return mapper.history(trans, resp.value,sort); - } - - @Override - public Result getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("NS",ns) - .err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result rnd = ques.deriveNs(trans,ns); - if(rnd.notOK()) { - return Result.err(rnd); - } - rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); - if(rnd.notOK()) { - return Result.err(rnd); - } - - Result> resp = ques.historyDAO.readBySubject(trans, ns, "ns", yyyymm); - if(resp.notOK()) { - return Result.err(resp); - } - return mapper.history(trans, resp.value,sort); - } + ***********************************/ + @Override + public Result getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User",user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rnd; + // Users may look at their own data + if(trans.user().equals(user)) { + // Users may look at their own data + } else { + int at = user.indexOf('@'); + if(at>=0 && trans.org().getRealm().equals(user.substring(at+1))) { + NsDAO.Data nsd = new NsDAO.Data(); + nsd.name = Question.domain2ns(user); + rnd = ques.mayUser(trans, trans.user(), nsd, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + } else { + rnd = ques.validNSOfDomain(trans, user); + if(rnd.notOK()) { + return Result.err(rnd); + } + + rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + } + } + Result> resp = ques.historyDAO.readByUser(trans, user, yyyymm); + if(resp.notOK()) { + return Result.err(resp); + } + return mapper.history(trans, resp.value,sort); + } + + @Override + public Result getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Role",role).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rrdd = RoleDAO.Data.decode(trans, ques, role); + if(rrdd.notOK()) { + return Result.err(rrdd); + } + + Result rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + Result> resp = ques.historyDAO.readBySubject(trans, role, "role", yyyymm); + if(resp.notOK()) { + return Result.err(resp); + } + return mapper.history(trans, resp.value,sort); + } + + @Override + public Result getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Type",type) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of") + Result rnd = ques.deriveNs(trans,type); + if(rnd.notOK()) { + return Result.err(rnd); + } + + rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + Result> resp = ques.historyDAO.readBySubject(trans, type, "perm", yyyymm); + if(resp.notOK()) { + return Result.err(resp); + } + return mapper.history(trans, resp.value,sort); + } + + @Override + public Result getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS",ns) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rnd = ques.deriveNs(trans,ns); + if(rnd.notOK()) { + return Result.err(rnd); + } + rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + Result> resp = ques.historyDAO.readBySubject(trans, ns, "ns", yyyymm); + if(resp.notOK()) { + return Result.err(resp); + } + return mapper.history(trans, resp.value,sort); + } /*********************************** * DELEGATE ***********************************/ - @Override - public Result createDelegate(final AuthzTrans trans, REQUEST base) { - return createOrUpdateDelegate(trans, base, Question.Access.create); - } - - @Override - public Result updateDelegate(AuthzTrans trans, REQUEST base) { - return createOrUpdateDelegate(trans, base, Question.Access.write); - } - - - private Result createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) { - final Result rd = mapper.delegate(trans, base); - final ServiceValidator v = new ServiceValidator(); - if(v.delegate(trans.org(),rd).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - final DelegateDAO.Data dd = rd.value; - - Result> ddr = ques.delegateDAO.read(trans, dd); - if(access==Access.create && ddr.isOKhasData()) { - return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate); - } else if(access!=Access.create && ddr.notOKorIsEmpty()) { - return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name()); - } - Result rv = ques.mayUser(trans, dd, access); - if(rv.notOK()) { - return rv; - } - - Result fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false, - new Mapper.Memo() { - @Override - public String get() { - StringBuilder sb = new StringBuilder(); - sb.append(access.name()); - sb.setCharAt(0, Character.toUpperCase(sb.charAt(0))); - sb.append("Delegate "); - sb.append(access==Access.create?"[":"to ["); - sb.append(rd.value.delegate); - sb.append("] for ["); - sb.append(rd.value.user); - sb.append(']'); - return sb.toString(); - } - }, - new MayChange() { - @Override - public Result mayChange() { - return Result.ok(); // Validate in code above - } - }); - - switch(fd.status) { - case OK: - Result rfc = func.createFuture(trans, fd.value, - dd.user, trans.user(),null, access==Access.create?FUTURE_OP.C:FUTURE_OP.U); - if(rfc.isOK()) { - return Result.err(Status.ACC_Future, "Delegate for [%s]", - dd.user); - } else { - return Result.err(rfc); - } - case Status.ACC_Now: - if(access==Access.create) { - Result rdr = ques.delegateDAO.create(trans, dd); - if(rdr.isOK()) { - return Result.ok(); - } else { - return Result.err(rdr); - } - } else { - return ques.delegateDAO.update(trans, dd); - } - default: - return Result.err(fd); - } - } - - @Override - public Result deleteDelegate(AuthzTrans trans, REQUEST base) { - final Result rd = mapper.delegate(trans, base); - final Validator v = new ServiceValidator(); - if(v.notOK(rd).nullOrBlank("User", rd.value.user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result> ddl; - if((ddl=ques.delegateDAO.read(trans, rd.value)).notOKorIsEmpty()) { - return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate"); - } - final DelegateDAO.Data dd = ddl.value.get(0); - Result rv = ques.mayUser(trans, dd, Access.write); - if(rv.notOK()) { - return rv; - } - - return ques.delegateDAO.delete(trans, dd, false); - } - - @Override - public Result deleteDelegate(AuthzTrans trans, String userName) { - DelegateDAO.Data dd = new DelegateDAO.Data(); - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("User", userName).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - dd.user = userName; - Result> ddl; - if((ddl=ques.delegateDAO.read(trans, dd)).notOKorIsEmpty()) { - return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate"); - } - dd = ddl.value.get(0); - Result rv = ques.mayUser(trans, dd, Access.write); - if(rv.notOK()) { - return rv; - } - - return ques.delegateDAO.delete(trans, dd, false); - } - - @Override - public Result getDelegatesByUser(AuthzTrans trans, String user) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - DelegateDAO.Data ddd = new DelegateDAO.Data(); - ddd.user = user; - ddd.delegate = null; - Result rv = ques.mayUser(trans, ddd, Access.read); - if(rv.notOK()) { - return Result.err(rv); - } - - TimeTaken tt = trans.start("Get delegates for a user", Env.SUB); - - Result> dbDelgs = ques.delegateDAO.read(trans, user); - try { - if (dbDelgs.isOKhasData()) { - return mapper.delegate(dbDelgs.value); - } else { - return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user); - } - } finally { - tt.done(); - } - } - - @Override - public Result getDelegatesByDelegate(AuthzTrans trans, String delegate) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Delegate", delegate).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - DelegateDAO.Data ddd = new DelegateDAO.Data(); - ddd.user = delegate; - Result rv = ques.mayUser(trans, ddd, Access.read); - if(rv.notOK()) { - return Result.err(rv); - } - - TimeTaken tt = trans.start("Get users for a delegate", Env.SUB); - - Result> dbDelgs = ques.delegateDAO.readByDelegate(trans, delegate); - try { - if (dbDelgs.isOKhasData()) { - return mapper.delegate(dbDelgs.value); - } else { - return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate); - } - } finally { - tt.done(); - } - } + @Override + public Result createDelegate(final AuthzTrans trans, REQUEST base) { + return createOrUpdateDelegate(trans, base, Question.Access.create); + } + + @Override + public Result updateDelegate(AuthzTrans trans, REQUEST base) { + return createOrUpdateDelegate(trans, base, Question.Access.write); + } + + + private Result createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) { + final Result rd = mapper.delegate(trans, base); + final ServiceValidator v = new ServiceValidator(); + if(v.delegate(trans.org(),rd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + final DelegateDAO.Data dd = rd.value; + + Result> ddr = ques.delegateDAO.read(trans, dd); + if(access==Access.create && ddr.isOKhasData()) { + return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate); + } else if(access!=Access.create && ddr.notOKorIsEmpty()) { + return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name()); + } + Result rv = ques.mayUser(trans, dd, access); + if(rv.notOK()) { + return rv; + } + + Result fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false, + new Mapper.Memo() { + @Override + public String get() { + StringBuilder sb = new StringBuilder(); + sb.append(access.name()); + sb.setCharAt(0, Character.toUpperCase(sb.charAt(0))); + sb.append("Delegate "); + sb.append(access==Access.create?"[":"to ["); + sb.append(rd.value.delegate); + sb.append("] for ["); + sb.append(rd.value.user); + sb.append(']'); + return sb.toString(); + } + }, + new MayChange() { + @Override + public Result mayChange() { + return Result.ok(); // Validate in code above + } + }); + + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans, fd.value, + dd.user, trans.user(),null, access==Access.create?FUTURE_OP.C:FUTURE_OP.U); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Delegate for [%s]", + dd.user); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + if(access==Access.create) { + Result rdr = ques.delegateDAO.create(trans, dd); + if(rdr.isOK()) { + return Result.ok(); + } else { + return Result.err(rdr); + } + } else { + return ques.delegateDAO.update(trans, dd); + } + default: + return Result.err(fd); + } + } + + @Override + public Result deleteDelegate(AuthzTrans trans, REQUEST base) { + final Result rd = mapper.delegate(trans, base); + final Validator v = new ServiceValidator(); + if(v.notOK(rd).nullOrBlank("User", rd.value.user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> ddl; + if((ddl=ques.delegateDAO.read(trans, rd.value)).notOKorIsEmpty()) { + return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate"); + } + final DelegateDAO.Data dd = ddl.value.get(0); + Result rv = ques.mayUser(trans, dd, Access.write); + if(rv.notOK()) { + return rv; + } + + return ques.delegateDAO.delete(trans, dd, false); + } + + @Override + public Result deleteDelegate(AuthzTrans trans, String userName) { + DelegateDAO.Data dd = new DelegateDAO.Data(); + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", userName).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + dd.user = userName; + Result> ddl; + if((ddl=ques.delegateDAO.read(trans, dd)).notOKorIsEmpty()) { + return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate"); + } + dd = ddl.value.get(0); + Result rv = ques.mayUser(trans, dd, Access.write); + if(rv.notOK()) { + return rv; + } + + return ques.delegateDAO.delete(trans, dd, false); + } + + @Override + public Result getDelegatesByUser(AuthzTrans trans, String user) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + DelegateDAO.Data ddd = new DelegateDAO.Data(); + ddd.user = user; + ddd.delegate = null; + Result rv = ques.mayUser(trans, ddd, Access.read); + if(rv.notOK()) { + return Result.err(rv); + } + + TimeTaken tt = trans.start("Get delegates for a user", Env.SUB); + + Result> dbDelgs = ques.delegateDAO.read(trans, user); + try { + if (dbDelgs.isOKhasData()) { + return mapper.delegate(dbDelgs.value); + } else { + return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user); + } + } finally { + tt.done(); + } + } + + @Override + public Result getDelegatesByDelegate(AuthzTrans trans, String delegate) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Delegate", delegate).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + DelegateDAO.Data ddd = new DelegateDAO.Data(); + ddd.user = delegate; + Result rv = ques.mayUser(trans, ddd, Access.read); + if(rv.notOK()) { + return Result.err(rv); + } + + TimeTaken tt = trans.start("Get users for a delegate", Env.SUB); + + Result> dbDelgs = ques.delegateDAO.readByDelegate(trans, delegate); + try { + if (dbDelgs.isOKhasData()) { + return mapper.delegate(dbDelgs.value); + } else { + return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate); + } + } finally { + tt.done(); + } + } /*********************************** * APPROVAL ***********************************/ - private static final String APPR_FMT = "actor=%s, action=%s, operation=\"%s\", requestor=%s, delegator=%s"; - @Override - public Result updateApproval(AuthzTrans trans, APPROVALS approvals) { - Result> rlad = mapper.approvals(approvals); - if(rlad.notOK()) { - return Result.err(rlad); - } - int numApprs = rlad.value.size(); - if(numApprs<1) { - return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating"); - } - int numProcessed = 0; - String user = trans.user(); - - Result> curr; - Lookup> apprByTicket=null; - for(ApprovalDAO.Data updt : rlad.value) { - if(updt.ticket!=null) { - curr = ques.approvalDAO.readByTicket(trans, updt.ticket); - if(curr.isOKhasData()) { - final List add = curr.value; - apprByTicket = new Lookup>() { // Store a Pre-Lookup - @Override - public List get(AuthzTrans trans, Object ... noop) { - return add; - } - }; - } - } else if(updt.id!=null) { - curr = ques.approvalDAO.read(trans, updt); - } else if(updt.approver!=null) { - curr = ques.approvalDAO.readByApprover(trans, updt.approver); - } else { - return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update"); - } - - if(curr.isOKhasData()) { - Map>> delegateCache = new HashMap<>(); - Map futureCache = new HashMap<>(); - FutureDAO.Data hasDeleted = new FutureDAO.Data(); - - for(ApprovalDAO.Data cd : curr.value) { - if("pending".equals(cd.status)) { - // Check for right record. Need ID, or (Ticket&Trans.User==Appr) - // If Default ID - boolean delegatedAction = ques.isDelegated(trans, user, cd.approver, delegateCache); - String delegator = cd.approver; - if(updt.id!=null || - (updt.ticket!=null && user.equals(cd.approver)) || - (updt.ticket!=null && delegatedAction)) { - if(updt.ticket.equals(cd.ticket)) { - Changed ch = new Changed(); - cd.id = ch.changed(cd.id,updt.id); -// cd.ticket = changed(cd.ticket,updt.ticket); - cd.user = ch.changed(cd.user,updt.user); - cd.approver = ch.changed(cd.approver,updt.approver); - cd.type = ch.changed(cd.type,updt.type); - cd.status = ch.changed(cd.status,updt.status); - cd.memo = ch.changed(cd.memo,updt.memo); - cd.operation = ch.changed(cd.operation,updt.operation); - cd.updated = ch.changed(cd.updated,updt.updated==null?new Date():updt.updated); - if(updt.status.equals("denied")) { - cd.last_notified = null; - } - if(cd.ticket!=null) { - FutureDAO.Data fdd = futureCache.get(cd.ticket); - if(fdd==null) { // haven't processed ticket yet - Result rfdd = ques.futureDAO.readPrimKey(trans, cd.ticket); - if(rfdd.isOK()) { - fdd = rfdd.value; // null is ok - } else { - fdd = hasDeleted; - } - futureCache.put(cd.ticket, fdd); // processed this Ticket... don't do others on this ticket - } - if(fdd==hasDeleted) { // YES, by Object - cd.ticket = null; - cd.status = "ticketDeleted"; - ch.hasChanged(true); - } else { - FUTURE_OP fop = FUTURE_OP.toFO(cd.operation); - if(fop==null) { - trans.info().printf("Approval Status %s is not actionable",cd.status); - } else if(apprByTicket!=null) { - Result rv = func.performFutureOp(trans, fop, fdd, apprByTicket,func.urDBLookup); - if (rv.isOK()) { - switch(rv.value) { - case E: - if (delegatedAction) { - trans.audit().printf(APPR_FMT,user,updt.status,cd.memo,cd.user,delegator); - } - futureCache.put(cd.ticket, hasDeleted); - break; - case D: - case L: - ch.hasChanged(true); - trans.audit().printf(APPR_FMT,user,rv.value.desc(),cd.memo,cd.user,delegator); - futureCache.put(cd.ticket, hasDeleted); - break; - default: - } - } else { - trans.info().log(rv.toString()); - } - } - - } - ++numProcessed; - } - if(ch.hasChanged()) { - ques.approvalDAO.update(trans, cd, true); - } - } - } - } - } - } - } - - if(numApprs==numProcessed) { - return Result.ok(); - } - return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed"); - - } - - private static class Changed { - private boolean hasChanged = false; - - public T changed(T src, T proposed) { - if(proposed==null || (src!=null && src.equals(proposed))) { - return src; - } - hasChanged=true; - return proposed; - } - - public void hasChanged(boolean b) { - hasChanged=b; - } - - public boolean hasChanged() { - return hasChanged; - } - } - - @Override - public Result getApprovalsByUser(AuthzTrans trans, String user) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("User", user).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - Result> rapd = ques.approvalDAO.readByUser(trans, user); - if(rapd.isOK()) { - return mapper.approvals(rapd.value); - } else { - return Result.err(rapd); - } + private static final String APPR_FMT = "actor=%s, action=%s, operation=\"%s\", requestor=%s, delegator=%s"; + @Override + public Result updateApproval(AuthzTrans trans, APPROVALS approvals) { + Result> rlad = mapper.approvals(approvals); + if(rlad.notOK()) { + return Result.err(rlad); + } + int numApprs = rlad.value.size(); + if(numApprs<1) { + return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating"); + } + int numProcessed = 0; + String user = trans.user(); + + Result> curr; + Lookup> apprByTicket=null; + for(ApprovalDAO.Data updt : rlad.value) { + if(updt.ticket!=null) { + curr = ques.approvalDAO.readByTicket(trans, updt.ticket); + if(curr.isOKhasData()) { + final List add = curr.value; + apprByTicket = new Lookup>() { // Store a Pre-Lookup + @Override + public List get(AuthzTrans trans, Object ... noop) { + return add; + } + }; + } + } else if(updt.id!=null) { + curr = ques.approvalDAO.read(trans, updt); + } else if(updt.approver!=null) { + curr = ques.approvalDAO.readByApprover(trans, updt.approver); + } else { + return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update"); + } + + if(curr.isOKhasData()) { + Map>> delegateCache = new HashMap<>(); + Map futureCache = new HashMap<>(); + FutureDAO.Data hasDeleted = new FutureDAO.Data(); + + for(ApprovalDAO.Data cd : curr.value) { + if("pending".equals(cd.status)) { + // Check for right record. Need ID, or (Ticket&Trans.User==Appr) + // If Default ID + boolean delegatedAction = ques.isDelegated(trans, user, cd.approver, delegateCache); + String delegator = cd.approver; + if(updt.id!=null || + (updt.ticket!=null && user.equals(cd.approver)) || + (updt.ticket!=null && delegatedAction)) { + if(updt.ticket.equals(cd.ticket)) { + Changed ch = new Changed(); + cd.id = ch.changed(cd.id,updt.id); +// cd.ticket = changed(cd.ticket,updt.ticket); + cd.user = ch.changed(cd.user,updt.user); + cd.approver = ch.changed(cd.approver,updt.approver); + cd.type = ch.changed(cd.type,updt.type); + cd.status = ch.changed(cd.status,updt.status); + cd.memo = ch.changed(cd.memo,updt.memo); + cd.operation = ch.changed(cd.operation,updt.operation); + cd.updated = ch.changed(cd.updated,updt.updated==null?new Date():updt.updated); + if(updt.status.equals("denied")) { + cd.last_notified = null; + } + if(cd.ticket!=null) { + FutureDAO.Data fdd = futureCache.get(cd.ticket); + if(fdd==null) { // haven't processed ticket yet + Result rfdd = ques.futureDAO.readPrimKey(trans, cd.ticket); + if(rfdd.isOK()) { + fdd = rfdd.value; // null is ok + } else { + fdd = hasDeleted; + } + futureCache.put(cd.ticket, fdd); // processed this Ticket... don't do others on this ticket + } + if(fdd==hasDeleted) { // YES, by Object + cd.ticket = null; + cd.status = "ticketDeleted"; + ch.hasChanged(true); + } else { + FUTURE_OP fop = FUTURE_OP.toFO(cd.operation); + if(fop==null) { + trans.info().printf("Approval Status %s is not actionable",cd.status); + } else if(apprByTicket!=null) { + Result rv = func.performFutureOp(trans, fop, fdd, apprByTicket,func.urDBLookup); + if (rv.isOK()) { + switch(rv.value) { + case E: + if (delegatedAction) { + trans.audit().printf(APPR_FMT,user,updt.status,cd.memo,cd.user,delegator); + } + futureCache.put(cd.ticket, hasDeleted); + break; + case D: + case L: + ch.hasChanged(true); + trans.audit().printf(APPR_FMT,user,rv.value.desc(),cd.memo,cd.user,delegator); + futureCache.put(cd.ticket, hasDeleted); + break; + default: + } + } else { + trans.info().log(rv.toString()); + } + } + + } + ++numProcessed; + } + if(ch.hasChanged()) { + ques.approvalDAO.update(trans, cd, true); + } + } + } + } + } + } + } + + if(numApprs==numProcessed) { + return Result.ok(); + } + return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed"); + + } + + private static class Changed { + private boolean hasChanged = false; + + public T changed(T src, T proposed) { + if(proposed==null || (src!=null && src.equals(proposed))) { + return src; + } + hasChanged=true; + return proposed; + } + + public void hasChanged(boolean b) { + hasChanged=b; + } + + public boolean hasChanged() { + return hasChanged; + } + } + + @Override + public Result getApprovalsByUser(AuthzTrans trans, String user) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rapd = ques.approvalDAO.readByUser(trans, user); + if(rapd.isOK()) { + return mapper.approvals(rapd.value); + } else { + return Result.err(rapd); + } } - @Override - public Result getApprovalsByTicket(AuthzTrans trans, String ticket) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Ticket", ticket).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - UUID uuid; - try { - uuid = UUID.fromString(ticket); - } catch (IllegalArgumentException e) { - return Result.err(Status.ERR_BadData,e.getMessage()); - } - - Result> rapd = ques.approvalDAO.readByTicket(trans, uuid); - if(rapd.isOK()) { - return mapper.approvals(rapd.value); - } else { - return Result.err(rapd); - } - } - - @Override - public Result getApprovalsByApprover(AuthzTrans trans, String approver) { - final Validator v = new ServiceValidator(); - if(v.nullOrBlank("Approver", approver).err()) { - return Result.err(Status.ERR_BadData,v.errs()); - } - - List listRapds = new ArrayList<>(); - - Result> myRapd = ques.approvalDAO.readByApprover(trans, approver); - if(myRapd.notOK()) { - return Result.err(myRapd); - } - - listRapds.addAll(myRapd.value); - - Result> delegatedFor = ques.delegateDAO.readByDelegate(trans, approver); - if (delegatedFor.isOK()) { - for (DelegateDAO.Data dd : delegatedFor.value) { - if (dd.expires.after(new Date())) { - String delegator = dd.user; - Result> rapd = ques.approvalDAO.readByApprover(trans, delegator); - if (rapd.isOK()) { - for (ApprovalDAO.Data d : rapd.value) { - if (!d.user.equals(trans.user())) { - listRapds.add(d); - } - } - } - } - } - } - - return mapper.approvals(listRapds); - } - - /* (non-Javadoc) - * @see org.onap.aaf.auth.service.AuthzService#clearCache(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) - */ - @Override - public Result cacheClear(AuthzTrans trans, String cname) { - if(ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) { - return ques.clearCache(trans,cname); - } - return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear", - trans.user(),ROOT_NS,CACHE,cname); - } - - /* (non-Javadoc) - * @see org.onap.aaf.auth.service.AuthzService#cacheClear(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.Integer) - */ - @Override - public Result cacheClear(AuthzTrans trans, String cname, int[] segment) { - if(ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) { - Result v=null; - for(int i: segment) { - v=ques.cacheClear(trans,cname,i); - } - if(v!=null) { - return v; - } - } - return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear", - trans.user(),ROOT_NS,CACHE,cname); - } - - /* (non-Javadoc) - * @see org.onap.aaf.auth.service.AuthzService#dbReset(org.onap.aaf.auth.env.test.AuthzTrans) - */ - @Override - public void dbReset(AuthzTrans trans) { - ques.historyDAO.reportPerhapsReset(trans, null); - } + @Override + public Result getApprovalsByTicket(AuthzTrans trans, String ticket) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Ticket", ticket).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + UUID uuid; + try { + uuid = UUID.fromString(ticket); + } catch (IllegalArgumentException e) { + return Result.err(Status.ERR_BadData,e.getMessage()); + } + + Result> rapd = ques.approvalDAO.readByTicket(trans, uuid); + if(rapd.isOK()) { + return mapper.approvals(rapd.value); + } else { + return Result.err(rapd); + } + } + + @Override + public Result getApprovalsByApprover(AuthzTrans trans, String approver) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Approver", approver).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + List listRapds = new ArrayList<>(); + + Result> myRapd = ques.approvalDAO.readByApprover(trans, approver); + if(myRapd.notOK()) { + return Result.err(myRapd); + } + + listRapds.addAll(myRapd.value); + + Result> delegatedFor = ques.delegateDAO.readByDelegate(trans, approver); + if (delegatedFor.isOK()) { + for (DelegateDAO.Data dd : delegatedFor.value) { + if (dd.expires.after(new Date())) { + String delegator = dd.user; + Result> rapd = ques.approvalDAO.readByApprover(trans, delegator); + if (rapd.isOK()) { + for (ApprovalDAO.Data d : rapd.value) { + if (!d.user.equals(trans.user())) { + listRapds.add(d); + } + } + } + } + } + } + + return mapper.approvals(listRapds); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#clearCache(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) + */ + @Override + public Result cacheClear(AuthzTrans trans, String cname) { + if(ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) { + return ques.clearCache(trans,cname); + } + return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear", + trans.user(),ROOT_NS,CACHE,cname); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#cacheClear(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.Integer) + */ + @Override + public Result cacheClear(AuthzTrans trans, String cname, int[] segment) { + if(ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) { + Result v=null; + for(int i: segment) { + v=ques.cacheClear(trans,cname,i); + } + if(v!=null) { + return v; + } + } + return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear", + trans.user(),ROOT_NS,CACHE,cname); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#dbReset(org.onap.aaf.auth.env.test.AuthzTrans) + */ + @Override + public void dbReset(AuthzTrans trans) { + ques.historyDAO.reportPerhapsReset(trans, null); + } }