[AAF-21] Initial code import
[aaf/authz.git] / authz-cass / src / main / java / com / att / dao / aaf / hl / Function.java
diff --git a/authz-cass/src/main/java/com/att/dao/aaf/hl/Function.java b/authz-cass/src/main/java/com/att/dao/aaf/hl/Function.java
new file mode 100644 (file)
index 0000000..d1db39d
--- /dev/null
@@ -0,0 +1,1575 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aai\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * Copyright © 2017 Amdocs\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package com.att.dao.aaf.hl;\r
+\r
+import static com.att.authz.layer.Result.OK;\r
+\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
+import java.util.UUID;\r
+\r
+import com.att.authz.common.Define;\r
+import com.att.authz.env.AuthzTrans;\r
+import com.att.authz.layer.Result;\r
+import com.att.authz.org.Executor;\r
+import com.att.authz.org.Organization;\r
+import com.att.authz.org.Organization.Expiration;\r
+import com.att.authz.org.Organization.Policy;\r
+import com.att.authz.org.Organization.Identity;\r
+import com.att.dao.DAOException;\r
+import com.att.dao.aaf.cass.ApprovalDAO;\r
+import com.att.dao.aaf.cass.CredDAO;\r
+import com.att.dao.aaf.cass.DelegateDAO;\r
+import com.att.dao.aaf.cass.FutureDAO;\r
+import com.att.dao.aaf.cass.Namespace;\r
+import com.att.dao.aaf.cass.NsDAO;\r
+import com.att.dao.aaf.cass.NsDAO.Data;\r
+import com.att.dao.aaf.cass.NsSplit;\r
+import com.att.dao.aaf.cass.NsType;\r
+import com.att.dao.aaf.cass.PermDAO;\r
+import com.att.dao.aaf.cass.RoleDAO;\r
+import com.att.dao.aaf.cass.Status;\r
+import com.att.dao.aaf.cass.UserRoleDAO;\r
+import com.att.dao.aaf.hl.Question.Access;\r
+\r
+public class Function {\r
+\r
+       public static final String FOP_CRED = "cred";\r
+       public static final String FOP_DELEGATE = "delegate";\r
+       public static final String FOP_NS = "ns";\r
+       public static final String FOP_PERM = "perm";\r
+       public static final String FOP_ROLE = "role";\r
+       public static final String FOP_USER_ROLE = "user_role";\r
+       // First Action should ALWAYS be "write", see "CreateRole"\r
+       public final Question q;\r
+\r
+       public Function(AuthzTrans trans, Question question) {\r
+               q = question;\r
+       }\r
+\r
+       private class ErrBuilder {\r
+               private StringBuilder sb;\r
+               private List<String> ao;\r
+\r
+               public void log(Result<?> result) {\r
+                       if (result.notOK()) {\r
+                               if (sb == null) {\r
+                                       sb = new StringBuilder();\r
+                                       ao = new ArrayList<String>();\r
+                               }\r
+                               sb.append(result.details);\r
+                               sb.append('\n');\r
+                               for (String s : result.variables) {\r
+                                       ao.add(s);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               public String[] vars() {\r
+                       String[] rv = new String[ao.size()];\r
+                       ao.toArray(rv);\r
+                       return rv;\r
+               }\r
+\r
+               public boolean hasErr() {\r
+                       return sb != null;\r
+               }\r
+\r
+               @Override\r
+               public String toString() {\r
+                       return sb == null ? "" : String.format(sb.toString(), ao);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * createNS\r
+        * \r
+        * Create Namespace\r
+        * \r
+        * @param trans\r
+        * @param org\r
+        * @param ns\r
+        * @param user\r
+        * @return\r
+        * @throws DAOException\r
+        * \r
+        *             To create an NS, you need to: 1) validate permission to\r
+        *             modify parent NS 2) Does NS exist already? 3) Create NS with\r
+        *             a) "user" as owner. NOTE: Per 10-15 request for AAF 1.0 4)\r
+        *             Loop through Roles with Parent NS, and map any that start\r
+        *             with this NS into this one 5) Loop through Perms with Parent\r
+        *             NS, and map any that start with this NS into this one\r
+        */\r
+       public Result<Void> createNS(AuthzTrans trans, Namespace namespace, boolean fromApproval) {\r
+               Result<?> rq;\r
+\r
+               if (namespace.name.endsWith(Question.DOT_ADMIN)\r
+                               || namespace.name.endsWith(Question.DOT_OWNER)) {\r
+                       return Result.err(Status.ERR_BadData,\r
+                                       "'admin' and 'owner' are reserved names in AAF");\r
+               }\r
+\r
+               try {\r
+                       for (String u : namespace.owner) {\r
+                               Organization org = trans.org();\r
+                               Identity orgUser = org.getIdentity(trans, u);\r
+                               if (orgUser == null || !orgUser.isResponsible()) {\r
+                                       // check if user has explicit permission\r
+                                       String reason;\r
+                                       if (org.isTestEnv() && (reason=org.validate(trans, Policy.AS_EMPLOYEE,\r
+                                                       new CassExecutor(trans, this), u))!=null) {\r
+                                           return Result.err(Status.ERR_Policy,reason);\r
+                                       }\r
+                               }\r
+                       }\r
+               } catch (Exception e) {\r
+                       trans.error().log(e,\r
+                                       "Could not contact Organization for User Validation");\r
+               }\r
+\r
+               String user = trans.user();\r
+               // 1) May Change Parent?\r
+               int idx = namespace.name.lastIndexOf('.');\r
+               String parent;\r
+               if (idx < 0) {\r
+                       if (!q.isGranted(trans, user, Define.ROOT_NS,Question.NS, ".", "create")) {\r
+                               return Result.err(Result.ERR_Security,\r
+                                               "%s may not create Root Namespaces", user);\r
+                       }\r
+                       parent = null;\r
+                       fromApproval = true;\r
+               } else {\r
+                       parent = namespace.name.substring(0, idx);\r
+               }\r
+\r
+               if (!fromApproval) {\r
+                       Result<NsDAO.Data> rparent = q.deriveNs(trans, parent);\r
+                       if (rparent.notOK()) {\r
+                               return Result.err(rparent);\r
+                       }\r
+                       rparent = q.mayUser(trans, user, rparent.value, Access.write);\r
+                       if (rparent.notOK()) {\r
+                               return Result.err(rparent);\r
+                       }\r
+               }\r
+\r
+               // 2) Does requested NS exist\r
+               if (q.nsDAO.read(trans, namespace.name).isOKhasData()) {\r
+                       return Result.err(Status.ERR_ConflictAlreadyExists,\r
+                                       "Target Namespace already exists");\r
+               }\r
+\r
+               // Someone must be responsible.\r
+               if (namespace.owner == null || namespace.owner.isEmpty()) {\r
+                       return Result\r
+                                       .err(Status.ERR_Policy,\r
+                                                       "Namespaces must be assigned at least one responsible party");\r
+               }\r
+\r
+               // 3) Create NS\r
+               Date now = new Date();\r
+\r
+               Result<Void> r;\r
+               // 3a) Admin\r
+\r
+               try {\r
+                       // Originally, added the enterer as Admin, but that's not necessary,\r
+                       // or helpful for Operations folks..\r
+                       // Admins can be empty, because they can be changed by lower level\r
+                       // NSs\r
+                       // if(ns.admin(false).isEmpty()) {\r
+                       // ns.admin(true).add(user);\r
+                       // }\r
+                       if (namespace.admin != null) {\r
+                               for (String u : namespace.admin) {\r
+                                       if ((r = checkValidID(trans, now, u)).notOK()) {\r
+                                               return r;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       // 3b) Responsible\r
+                       Organization org = trans.org();\r
+                       for (String u : namespace.owner) {\r
+                               Identity orgUser = org.getIdentity(trans, u);\r
+                               if (orgUser == null) {\r
+                                       return Result\r
+                                                       .err(Status.ERR_BadData,\r
+                                                                       "NS must be created with an %s approved Responsible Party",\r
+                                                                       org.getName());\r
+                               }\r
+                       }\r
+               } catch (Exception e) {\r
+                       return Result.err(Status.ERR_UserNotFound, e.getMessage());\r
+               }\r
+\r
+               // VALIDATIONS done... Add NS\r
+               if ((rq = q.nsDAO.create(trans, namespace.data())).notOK()) {\r
+                   return Result.err(rq);\r
+               }\r
+\r
+               // Since Namespace is now created, we need to grab all subsequent errors\r
+               ErrBuilder eb = new ErrBuilder();\r
+\r
+               // Add UserRole(s)\r
+               UserRoleDAO.Data urdd = new UserRoleDAO.Data();\r
+               urdd.expires = trans.org().expiration(null, Expiration.UserInRole).getTime();\r
+               urdd.role(namespace.name, Question.ADMIN);\r
+               for (String admin : namespace.admin) {\r
+                       urdd.user = admin;\r
+                       eb.log(q.userRoleDAO.create(trans, urdd));\r
+               }\r
+               urdd.role(namespace.name,Question.OWNER);\r
+               for (String owner : namespace.owner) {\r
+                       urdd.user = owner;\r
+                       eb.log(q.userRoleDAO.create(trans, urdd));\r
+               }\r
+\r
+               addNSAdminRolesPerms(trans, eb, namespace.name);\r
+\r
+               addNSOwnerRolesPerms(trans, eb, namespace.name);\r
+\r
+               if (parent != null) {\r
+                       // Build up with any errors\r
+\r
+                       Result<NsDAO.Data> parentNS = q.deriveNs(trans, parent);\r
+                       String targetNs = parentNS.value.name; // Get the Parent Namespace,\r
+                                                                                                       // not target\r
+                       String targetName = namespace.name.substring(parentNS.value.name.length() + 1); // Remove the Parent Namespace from the\r
+                                                                       // Target + a dot, and you'll get the name\r
+                       int targetNameDot = targetName.length() + 1;\r
+\r
+                       // 4) Change any roles with children matching this NS, and\r
+                       Result<List<RoleDAO.Data>> rrdc = q.roleDAO.readChildren(trans, targetNs, targetName);\r
+                       if (rrdc.isOKhasData()) {\r
+                               for (RoleDAO.Data rdd : rrdc.value) {\r
+                                       // Remove old Role from Perms, save them off\r
+                                       List<PermDAO.Data> lpdd = new ArrayList<PermDAO.Data>();\r
+                                       for(String p : rdd.perms(false)) {\r
+                                               Result<PermDAO.Data> rpdd = PermDAO.Data.decode(trans,q,p);\r
+                                               if(rpdd.isOKhasData()) {\r
+                                                       PermDAO.Data pdd = rpdd.value;\r
+                                                       lpdd.add(pdd);\r
+                                                       q.permDAO.delRole(trans, pdd, rdd);\r
+                                               } else{\r
+                                                       trans.error().log(rpdd.errorString());\r
+                                               }\r
+                                       }\r
+                                       \r
+                                       // Save off Old keys\r
+                                       String delP1 = rdd.ns;\r
+                                       String delP2 = rdd.name;\r
+\r
+                                       // Write in new key\r
+                                       rdd.ns = namespace.name;\r
+                                       rdd.name = (delP2.length() > targetNameDot) ? delP2\r
+                                                       .substring(targetNameDot) : "";\r
+                                                       \r
+                                       // Need to use non-cached, because switching namespaces, not\r
+                                       // "create" per se\r
+                                       if ((rq = q.roleDAO.create(trans, rdd)).isOK()) {\r
+                                               // Put Role back into Perm, with correct info\r
+                                               for(PermDAO.Data pdd : lpdd) {\r
+                                                       q.permDAO.addRole(trans, pdd, rdd);\r
+                                               }\r
+                                               // Change data for User Roles \r
+                                               Result<List<UserRoleDAO.Data>> rurd = q.userRoleDAO.readByRole(trans, rdd.fullName());\r
+                                               if(rurd.isOKhasData()) {\r
+                                                       for(UserRoleDAO.Data urd : rurd.value) {\r
+                                                               urd.ns = rdd.ns;\r
+                                                               urd.rname = rdd.name;\r
+                                                               q.userRoleDAO.update(trans, urd);\r
+                                                       }\r
+                                               }\r
+                                               // Now delete old one\r
+                                               rdd.ns = delP1;\r
+                                               rdd.name = delP2;\r
+                                               if ((rq = q.roleDAO.delete(trans, rdd, false)).notOK()) {\r
+                                                       eb.log(rq);\r
+                                               }\r
+                                       } else {\r
+                                               eb.log(rq);\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       // 4) Change any Permissions with children matching this NS, and\r
+                       Result<List<PermDAO.Data>> rpdc = q.permDAO.readChildren(trans,targetNs, targetName);\r
+                       if (rpdc.isOKhasData()) {\r
+                               for (PermDAO.Data pdd : rpdc.value) {\r
+                                       // Remove old Perm from Roles, save them off\r
+                                       List<RoleDAO.Data> lrdd = new ArrayList<RoleDAO.Data>();\r
+                                       \r
+                                       for(String rl : pdd.roles(false)) {\r
+                                               Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,q,rl);\r
+                                               if(rrdd.isOKhasData()) {\r
+                                                       RoleDAO.Data rdd = rrdd.value;\r
+                                                       lrdd.add(rdd);\r
+                                                       q.roleDAO.delPerm(trans, rdd, pdd);\r
+                                               } else{\r
+                                                       trans.error().log(rrdd.errorString());\r
+                                               }\r
+                                       }\r
+                                       \r
+                                       // Save off Old keys\r
+                                       String delP1 = pdd.ns;\r
+                                       String delP2 = pdd.type;\r
+                                       pdd.ns = namespace.name;\r
+                                       pdd.type = (delP2.length() > targetNameDot) ? delP2\r
+                                                       .substring(targetNameDot) : "";\r
+                                       if ((rq = q.permDAO.create(trans, pdd)).isOK()) {\r
+                                               // Put Role back into Perm, with correct info\r
+                                               for(RoleDAO.Data rdd : lrdd) {\r
+                                                       q.roleDAO.addPerm(trans, rdd, pdd);\r
+                                               }\r
+\r
+                                               pdd.ns = delP1;\r
+                                               pdd.type = delP2;\r
+                                               if ((rq = q.permDAO.delete(trans, pdd, false)).notOK()) {\r
+                                                       eb.log(rq);\r
+                                                       // } else {\r
+                                                       // Need to invalidate directly, because we're\r
+                                                       // switching places in NS, not normal cache behavior\r
+                                                       // q.permDAO.invalidate(trans,pdd);\r
+                                               }\r
+                                       } else {\r
+                                               eb.log(rq);\r
+                                       }\r
+                               }\r
+                       }\r
+                       if (eb.hasErr()) {\r
+                               return Result.err(Status.ERR_ActionNotCompleted,eb.sb.toString(), eb.vars());\r
+                       }\r
+               }\r
+               return Result.ok();\r
+       }\r
+\r
+       private void addNSAdminRolesPerms(AuthzTrans trans, ErrBuilder eb, String ns) {\r
+               // Admin Role/Perm\r
+               RoleDAO.Data rd = new RoleDAO.Data();\r
+               rd.ns = ns;\r
+               rd.name = "admin";\r
+               rd.description = "AAF Namespace Administrators";\r
+\r
+               PermDAO.Data pd = new PermDAO.Data();\r
+               pd.ns = ns;\r
+               pd.type = "access";\r
+               pd.instance = Question.ASTERIX;\r
+               pd.action = Question.ASTERIX;\r
+               pd.description = "AAF Namespace Write Access";\r
+\r
+               rd.perms = new HashSet<String>();\r
+               rd.perms.add(pd.encode());\r
+               eb.log(q.roleDAO.create(trans, rd));\r
+\r
+               pd.roles = new HashSet<String>();\r
+               pd.roles.add(rd.encode());\r
+               eb.log(q.permDAO.create(trans, pd));\r
+       }\r
+\r
+       private void addNSOwnerRolesPerms(AuthzTrans trans, ErrBuilder eb, String ns) {\r
+               RoleDAO.Data rd = new RoleDAO.Data();\r
+               rd.ns = ns;\r
+               rd.name = "owner";\r
+               rd.description = "AAF Namespace Owners";\r
+\r
+               PermDAO.Data pd = new PermDAO.Data();\r
+               pd.ns = ns;\r
+               pd.type = "access";\r
+               pd.instance = Question.ASTERIX;\r
+               pd.action = Question.READ;\r
+               pd.description = "AAF Namespace Read Access";\r
+\r
+               rd.perms = new HashSet<String>();\r
+               rd.perms.add(pd.encode());\r
+               eb.log(q.roleDAO.create(trans, rd));\r
+\r
+               pd.roles = new HashSet<String>();\r
+               pd.roles.add(rd.encode());\r
+               eb.log(q.permDAO.create(trans, pd));\r
+       }\r
+\r
+       /**\r
+        * deleteNS\r
+        * \r
+        * Delete Namespace\r
+        * \r
+        * @param trans\r
+        * @param org\r
+        * @param ns\r
+        * @param force\r
+        * @param user\r
+        * @return\r
+        * @throws DAOException\r
+        * \r
+        * \r
+        *             To delete an NS, you need to: 1) validate permission to\r
+        *             modify this NS 2) Find all Roles with this NS, and 2a) if\r
+        *             Force, delete them, else modify to Parent NS 3) Find all\r
+        *             Perms with this NS, and modify to Parent NS 3a) if Force,\r
+        *             delete them, else modify to Parent NS 4) Find all IDs\r
+        *             associated to this NS, and deny if exists. 5) Remove NS\r
+        */\r
+       public Result<Void> deleteNS(AuthzTrans trans, String ns) {\r
+               boolean force = trans.forceRequested();\r
+               boolean move = trans.moveRequested();\r
+               // 1) Validate\r
+               Result<List<NsDAO.Data>> nsl;\r
+               if ((nsl = q.nsDAO.read(trans, ns)).notOKorIsEmpty()) {\r
+                       return Result.err(Status.ERR_NsNotFound, "%s does not exist", ns);\r
+               }\r
+               NsDAO.Data nsd = nsl.value.get(0);\r
+               NsType nt;\r
+               if (move && !q.canMove(nt = NsType.fromType(nsd.type))) {\r
+                       return Result.err(Status.ERR_Denied, "Namespace Force=move not permitted for Type %s",nt.name());\r
+               }\r
+\r
+               Result<NsDAO.Data> dnr = q.mayUser(trans, trans.user(), nsd, Access.write);\r
+               if (dnr.status != Status.OK) {\r
+                       return Result.err(dnr);\r
+               }\r
+\r
+               // 2) Find Parent\r
+               String user = trans.user();\r
+               int idx = ns.lastIndexOf('.');\r
+               NsDAO.Data parent;\r
+               if (idx < 0) {\r
+                       if (!q.isGranted(trans, user, Define.ROOT_NS,Question.NS, ".", "delete")) {\r
+                               return Result.err(Result.ERR_Security,\r
+                                               "%s may not delete Root Namespaces", user);\r
+                       }\r
+                       parent = null;\r
+               } else {\r
+                       Result<NsDAO.Data> rlparent = q.deriveNs(trans, ns.substring(0, idx));\r
+                       if (rlparent.notOKorIsEmpty()) {\r
+                               return Result.err(rlparent);\r
+                       }\r
+                       parent = rlparent.value;\r
+               }\r
+\r
+               // Build up with any errors\r
+               // If sb != null below is an indication of error\r
+               StringBuilder sb = null;\r
+               ErrBuilder er = new ErrBuilder();\r
+\r
+               // 2a) Deny if any IDs on Namespace\r
+               Result<List<CredDAO.Data>> creds = q.credDAO.readNS(trans, ns);\r
+               if (creds.isOKhasData()) {\r
+                       if (force || move) {\r
+                               for (CredDAO.Data cd : creds.value) {\r
+                                       er.log(q.credDAO.delete(trans, cd, false));\r
+                                       // Since we're deleting all the creds, we should delete all\r
+                                       // the user Roles for that Cred\r
+                                       Result<List<UserRoleDAO.Data>> rlurd = q.userRoleDAO\r
+                                                       .readByUser(trans, cd.id);\r
+                                       if (rlurd.isOK()) {\r
+                                               for (UserRoleDAO.Data data : rlurd.value) {\r
+                                                   q.userRoleDAO.delete(trans, data, false);\r
+                                               }\r
+                                       }\r
+\r
+                               }\r
+                       } else {\r
+                               // first possible StringBuilder Create.\r
+                               sb = new StringBuilder();\r
+                               sb.append('[');\r
+                               sb.append(ns);\r
+                               sb.append("] contains users");\r
+                       }\r
+               }\r
+\r
+               // 2b) Find (or delete if forced flag is set) dependencies\r
+               // First, find if NS Perms are the only ones\r
+               Result<List<PermDAO.Data>> rpdc = q.permDAO.readNS(trans, ns);\r
+               if (rpdc.isOKhasData()) {\r
+                       // Since there are now NS perms, we have to count NON-NS perms.\r
+                       // FYI, if we delete them now, and the NS is not deleted, it is in\r
+                       // an inconsistent state.\r
+                       boolean nonaccess = false;\r
+                       for (PermDAO.Data pdd : rpdc.value) {\r
+                               if (!"access".equals(pdd.type)) {\r
+                                       nonaccess = true;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       if (nonaccess && !force && !move) {\r
+                               if (sb == null) {\r
+                                       sb = new StringBuilder();\r
+                                       sb.append('[');\r
+                                       sb.append(ns);\r
+                                       sb.append("] contains ");\r
+                               } else {\r
+                                       sb.append(", ");\r
+                               }\r
+                               sb.append("permissions");\r
+                       }\r
+               }\r
+\r
+               Result<List<RoleDAO.Data>> rrdc = q.roleDAO.readNS(trans, ns);\r
+               if (rrdc.isOKhasData()) {\r
+                       // Since there are now NS roles, we have to count NON-NS roles.\r
+                       // FYI, if we delete th)em now, and the NS is not deleted, it is in\r
+                       // an inconsistent state.\r
+                       int count = rrdc.value.size();\r
+                       for (RoleDAO.Data rdd : rrdc.value) {\r
+                               if ("admin".equals(rdd.name) || "owner".equals(rdd.name)) {\r
+                                       --count;\r
+                               }\r
+                       }\r
+                       if (count > 0 && !force && !move) {\r
+                               if (sb == null) {\r
+                                       sb = new StringBuilder();\r
+                                       sb.append('[');\r
+                                       sb.append(ns);\r
+                                       sb.append("] contains ");\r
+                               } else {\r
+                                       sb.append(", ");\r
+                               }\r
+                               sb.append("roles");\r
+                       }\r
+               }\r
+\r
+               // 2c) Deny if dependencies exist that would be moved to root level\r
+               // parent is root level parent here. Need to find closest parent ns that\r
+               // exists\r
+               if (sb != null) {\r
+                       if (!force && !move) {\r
+                               sb.append(".\n  Delete dependencies and try again.  Note: using \"force=true\" will delete all. \"force=move\" will delete Creds, but move Roles and Perms to parent.");\r
+                               return Result.err(Status.ERR_DependencyExists, sb.toString());\r
+                       }\r
+\r
+                       if (move && (parent == null || parent.type == NsType.COMPANY.type)) {\r
+                               return Result\r
+                                               .err(Status.ERR_DependencyExists,\r
+                                                               "Cannot move users, roles or permissions to [%s].\nDelete dependencies and try again",\r
+                                                               parent.name);\r
+                       }\r
+               } else if (move && parent != null) {\r
+                       sb = new StringBuilder();\r
+                       // 3) Change any roles with children matching this NS, and\r
+                       moveRoles(trans, parent, sb, rrdc);\r
+                       // 4) Change any Perms with children matching this NS, and\r
+                       movePerms(trans, parent, sb, rpdc);\r
+               }\r
+\r
+               if (sb != null && sb.length() > 0) {\r
+                       return Result.err(Status.ERR_DependencyExists, sb.toString());\r
+               }\r
+\r
+               if (er.hasErr()) {\r
+                       if (trans.debug().isLoggable()) {\r
+                               trans.debug().log(er.toString());\r
+                       }\r
+                       return Result.err(Status.ERR_DependencyExists,\r
+                                       "Namespace members cannot be deleted for %s", ns);\r
+               }\r
+\r
+               // 5) OK... good to go for NS Deletion...\r
+               if (!rpdc.isEmpty()) {\r
+                       for (PermDAO.Data perm : rpdc.value) {\r
+                               deletePerm(trans, perm, true, true);\r
+                       }\r
+               }\r
+               if (!rrdc.isEmpty()) {\r
+                       for (RoleDAO.Data role : rrdc.value) {\r
+                               deleteRole(trans, role, true, true);\r
+                       }\r
+               }\r
+\r
+               return q.nsDAO.delete(trans, nsd, false);\r
+       }\r
+\r
+       public Result<List<String>> getOwners(AuthzTrans trans, String ns,\r
+                       boolean includeExpired) {\r
+               return getUsersByRole(trans, ns + Question.DOT_OWNER, includeExpired);\r
+       }\r
+\r
+       private Result<Void> mayAddOwner(AuthzTrans trans, String ns, String id) {\r
+               Result<NsDAO.Data> rq = q.deriveNs(trans, ns);\r
+               if (rq.notOK()) {\r
+                       return Result.err(rq);\r
+               }\r
+\r
+               rq = q.mayUser(trans, trans.user(), rq.value, Access.write);\r
+               if (rq.notOK()) {\r
+                       return Result.err(rq);\r
+               }\r
+\r
+               Identity user;\r
+               Organization org = trans.org();\r
+               try {\r
+                       if ((user = org.getIdentity(trans, id)) == null) {\r
+                               return Result.err(Status.ERR_Policy,\r
+                                               "%s reports that this is not a valid credential",\r
+                                               org.getName());\r
+                       }\r
+                       if (user.isResponsible()) {\r
+                               return Result.ok();\r
+                       } else {\r
+                               String reason="This is not a Test Environment";\r
+                               if (org.isTestEnv() && (reason = org.validate(trans, Policy.AS_EMPLOYEE, \r
+                                               new CassExecutor(trans, this), id))==null) {\r
+                                       return Result.ok();\r
+                               }\r
+                               return Result.err(Status.ERR_Policy,reason);\r
+                       }\r
+               } catch (Exception e) {\r
+                       return Result.err(e);\r
+               }\r
+       }\r
+\r
+       private Result<Void> mayAddAdmin(AuthzTrans trans, String ns,   String id) {\r
+               // Does NS Exist?\r
+               Result<Void> r = checkValidID(trans, new Date(), id);\r
+               if (r.notOK()) {\r
+                       return r;\r
+               }\r
+               // Is id able to be an Admin\r
+               Result<NsDAO.Data> rq = q.deriveNs(trans, ns);\r
+               if (rq.notOK()) {\r
+                       return Result.err(rq);\r
+               }\r
+       \r
+               rq = q.mayUser(trans, trans.user(), rq.value, Access.write);\r
+               if (rq.notOK()) {\r
+                       return Result.err(rq);\r
+               }\r
+               return r;\r
+       }\r
+\r
+       private Result<Void> checkValidID(AuthzTrans trans, Date now, String user) {\r
+               Organization org = trans.org();\r
+               if (user.endsWith(org.getRealm())) {\r
+                       try {\r
+                               if (org.getIdentity(trans, user) == null) {\r
+                                       return Result.err(Status.ERR_Denied,\r
+                                                       "%s reports that %s is a faulty ID", org.getName(),\r
+                                                       user);\r
+                               }\r
+                               return Result.ok();\r
+                       } catch (Exception e) {\r
+                               return Result.err(Result.ERR_Security,\r
+                                               "%s is not a valid %s Credential", user, org.getName());\r
+                       }\r
+               } else {\r
+                       Result<List<CredDAO.Data>> cdr = q.credDAO.readID(trans, user);\r
+                       if (cdr.notOKorIsEmpty()) {\r
+                               return Result.err(Status.ERR_Security,\r
+                                               "%s is not a valid AAF Credential", user);\r
+                       }\r
+       \r
+                       for (CredDAO.Data cd : cdr.value) {\r
+                               if (cd.expires.after(now)) {\r
+                                       return Result.ok();\r
+                               }\r
+                       }\r
+               }\r
+               return Result.err(Result.ERR_Security, "%s has expired", user);\r
+       }\r
+\r
+       public Result<Void> delOwner(AuthzTrans trans, String ns, String id) {\r
+               Result<NsDAO.Data> rq = q.deriveNs(trans, ns);\r
+               if (rq.notOK()) {\r
+                       return Result.err(rq);\r
+               }\r
+\r
+               rq = q.mayUser(trans, trans.user(), rq.value, Access.write);\r
+               if (rq.notOK()) {\r
+                       return Result.err(rq);\r
+               }\r
+\r
+               return delUserRole(trans, id, ns,Question.OWNER);\r
+       }\r
+\r
+       public Result<List<String>> getAdmins(AuthzTrans trans, String ns, boolean includeExpired) {\r
+               return getUsersByRole(trans, ns + Question.DOT_ADMIN, includeExpired);\r
+       }\r
+\r
+       public Result<Void> delAdmin(AuthzTrans trans, String ns, String id) {\r
+               Result<NsDAO.Data> rq = q.deriveNs(trans, ns);\r
+               if (rq.notOK()) {\r
+                       return Result.err(rq);\r
+               }\r
+\r
+               rq = q.mayUser(trans, trans.user(), rq.value, Access.write);\r
+               if (rq.notOK()) {\r
+                       return Result.err(rq);\r
+               }\r
+\r
+               return delUserRole(trans, id, ns, Question.ADMIN);\r
+       }\r
+\r
+       /**\r
+        * Helper function that moves permissions from a namespace being deleted to\r
+        * its parent namespace\r
+        * \r
+        * @param trans\r
+        * @param parent\r
+        * @param sb\r
+        * @param rpdc\r
+        *            - list of permissions in namespace being deleted\r
+        */\r
+       private void movePerms(AuthzTrans trans, NsDAO.Data parent,\r
+                       StringBuilder sb, Result<List<PermDAO.Data>> rpdc) {\r
+\r
+               Result<Void> rv;\r
+               Result<PermDAO.Data> pd;\r
+\r
+               if (rpdc.isOKhasData()) {\r
+                       for (PermDAO.Data pdd : rpdc.value) {\r
+                               String delP2 = pdd.type;\r
+                               if ("access".equals(delP2)) {\r
+                                   continue;\r
+                               }\r
+                               // Remove old Perm from Roles, save them off\r
+                               List<RoleDAO.Data> lrdd = new ArrayList<RoleDAO.Data>();\r
+                               \r
+                               for(String rl : pdd.roles(false)) {\r
+                                       Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,q,rl);\r
+                                       if(rrdd.isOKhasData()) {\r
+                                               RoleDAO.Data rdd = rrdd.value;\r
+                                               lrdd.add(rdd);\r
+                                               q.roleDAO.delPerm(trans, rdd, pdd);\r
+                                       } else{\r
+                                               trans.error().log(rrdd.errorString());\r
+                                       }\r
+                               }\r
+                               \r
+                               // Save off Old keys\r
+                               String delP1 = pdd.ns;\r
+                               NsSplit nss = new NsSplit(parent, pdd.fullType());\r
+                               pdd.ns = nss.ns;\r
+                               pdd.type = nss.name;\r
+                               // Use direct Create/Delete, because switching namespaces\r
+                               if ((pd = q.permDAO.create(trans, pdd)).isOK()) {\r
+                                       // Put Role back into Perm, with correct info\r
+                                       for(RoleDAO.Data rdd : lrdd) {\r
+                                               q.roleDAO.addPerm(trans, rdd, pdd);\r
+                                       }\r
+\r
+                                       pdd.ns = delP1;\r
+                                       pdd.type = delP2;\r
+                                       if ((rv = q.permDAO.delete(trans, pdd, false)).notOK()) {\r
+                                               sb.append(rv.details);\r
+                                               sb.append('\n');\r
+                                               // } else {\r
+                                               // Need to invalidate directly, because we're switching\r
+                                               // places in NS, not normal cache behavior\r
+                                               // q.permDAO.invalidate(trans,pdd);\r
+                                       }\r
+                               } else {\r
+                                       sb.append(pd.details);\r
+                                       sb.append('\n');\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Helper function that moves roles from a namespace being deleted to its\r
+        * parent namespace\r
+        * \r
+        * @param trans\r
+        * @param parent\r
+        * @param sb\r
+        * @param rrdc\r
+        *            - list of roles in namespace being deleted\r
+        */\r
+       private void moveRoles(AuthzTrans trans, NsDAO.Data parent,\r
+                       StringBuilder sb, Result<List<RoleDAO.Data>> rrdc) {\r
+\r
+               Result<Void> rv;\r
+               Result<RoleDAO.Data> rd;\r
+\r
+               if (rrdc.isOKhasData()) {\r
+                       for (RoleDAO.Data rdd : rrdc.value) {\r
+                               String delP2 = rdd.name;\r
+                               if ("admin".equals(delP2) || "owner".equals(delP2)) {\r
+                                   continue;\r
+                               }\r
+                               // Remove old Role from Perms, save them off\r
+                               List<PermDAO.Data> lpdd = new ArrayList<PermDAO.Data>();\r
+                               for(String p : rdd.perms(false)) {\r
+                                       Result<PermDAO.Data> rpdd = PermDAO.Data.decode(trans,q,p);\r
+                                       if(rpdd.isOKhasData()) {\r
+                                               PermDAO.Data pdd = rpdd.value;\r
+                                               lpdd.add(pdd);\r
+                                               q.permDAO.delRole(trans, pdd, rdd);\r
+                                       } else{\r
+                                               trans.error().log(rpdd.errorString());\r
+                                       }\r
+                               }\r
+                               \r
+                               // Save off Old keys\r
+                               String delP1 = rdd.ns;\r
+\r
+                               NsSplit nss = new NsSplit(parent, rdd.fullName());\r
+                               rdd.ns = nss.ns;\r
+                               rdd.name = nss.name;\r
+                               // Use direct Create/Delete, because switching namespaces\r
+                               if ((rd = q.roleDAO.create(trans, rdd)).isOK()) {\r
+                                       // Put Role back into Perm, with correct info\r
+                                       for(PermDAO.Data pdd : lpdd) {\r
+                                               q.permDAO.addRole(trans, pdd, rdd);\r
+                                       }\r
+\r
+                                       rdd.ns = delP1;\r
+                                       rdd.name = delP2;\r
+                                       if ((rv = q.roleDAO.delete(trans, rdd, true)).notOK()) {\r
+                                               sb.append(rv.details);\r
+                                               sb.append('\n');\r
+                                               // } else {\r
+                                               // Need to invalidate directly, because we're switching\r
+                                               // places in NS, not normal cache behavior\r
+                                               // q.roleDAO.invalidate(trans,rdd);\r
+                                       }\r
+                               } else {\r
+                                       sb.append(rd.details);\r
+                                       sb.append('\n');\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Create Permission (and any missing Permission between this and Parent) if\r
+        * we have permission\r
+        * \r
+        * Pass in the desired Management Permission for this Permission\r
+        * \r
+        * If Force is set, then Roles listed will be created, if allowed,\r
+        * pre-granted.\r
+        */\r
+       public Result<Void> createPerm(AuthzTrans trans, PermDAO.Data perm, boolean fromApproval) {\r
+               String user = trans.user();\r
+               // Next, see if User is allowed to Manage Parent Permission\r
+\r
+               Result<NsDAO.Data> rnsd;\r
+               if (!fromApproval) {\r
+                       rnsd = q.mayUser(trans, user, perm, Access.write);\r
+                       if (rnsd.notOK()) {\r
+                               return Result.err(rnsd);\r
+                       }\r
+               } else {\r
+                       rnsd = q.deriveNs(trans, perm.ns);\r
+               }\r
+\r
+               // Does Child exist?\r
+               if (!trans.forceRequested()) {\r
+                       if (q.permDAO.read(trans, perm).isOKhasData()) {\r
+                               return Result.err(Status.ERR_ConflictAlreadyExists,\r
+                                               "Permission [%s.%s|%s|%s] already exists.", perm.ns,\r
+                                               perm.type, perm.instance, perm.action);\r
+                       }\r
+               }\r
+\r
+               // Attempt to add perms to roles, creating as possible\r
+               Set<String> roles;\r
+               String pstring = perm.encode();\r
+\r
+               // For each Role\r
+               for (String role : roles = perm.roles(true)) {\r
+                       Result<RoleDAO.Data> rdd = RoleDAO.Data.decode(trans,q,role);\r
+                       if(rdd.isOKhasData()) {\r
+                               RoleDAO.Data rd = rdd.value;\r
+                               if (!fromApproval) {\r
+                                       // May User write to the Role in question.\r
+                                       Result<NsDAO.Data> rns = q.mayUser(trans, user, rd,\r
+                                                       Access.write);\r
+                                       if (rns.notOK()) {\r
+                                               // Remove the role from Add, because\r
+                                               roles.remove(role); // Don't allow adding\r
+                                               trans.warn()\r
+                                                               .log("User [%s] does not have permission to relate Permissions to Role [%s]",\r
+                                                                               user, role);\r
+                                       }\r
+                               }\r
+\r
+                               Result<List<RoleDAO.Data>> rlrd;\r
+                               if ((rlrd = q.roleDAO.read(trans, rd)).notOKorIsEmpty()) {\r
+                                       rd.perms(true).add(pstring);\r
+                                       if (q.roleDAO.create(trans, rd).notOK()) {\r
+                                               roles.remove(role); // Role doesn't exist, and can't be\r
+                                                                                       // created\r
+                                       }\r
+                               } else {\r
+                                       rd = rlrd.value.get(0);\r
+                                       if (!rd.perms.contains(pstring)) {\r
+                                               q.roleDAO.addPerm(trans, rd, perm);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               Result<PermDAO.Data> pdr = q.permDAO.create(trans, perm);\r
+               if (pdr.isOK()) {\r
+                       return Result.ok();\r
+               } else { \r
+                       return Result.err(pdr);\r
+               }\r
+       }\r
+\r
+       public Result<Void> deletePerm(final AuthzTrans trans, final PermDAO.Data perm, boolean force, boolean fromApproval) {\r
+               String user = trans.user();\r
+\r
+               // Next, see if User is allowed to Manage Permission\r
+               Result<NsDAO.Data> rnsd;\r
+               if (!fromApproval) {\r
+                       rnsd = q.mayUser(trans, user, perm, Access.write);\r
+                       if (rnsd.notOK()) {\r
+                               return Result.err(rnsd);\r
+                       }\r
+               }\r
+               // Does Perm exist?\r
+               Result<List<PermDAO.Data>> pdr = q.permDAO.read(trans, perm);\r
+               if (pdr.notOKorIsEmpty()) {\r
+                       return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist.",\r
+                                       perm.ns,perm.type, perm.instance, perm.action);\r
+               }\r
+               // Get perm, but with rest of data.\r
+               PermDAO.Data fullperm = pdr.value.get(0);\r
+\r
+               // Attached to any Roles?\r
+               if (fullperm.roles != null) {\r
+                       if (force) {\r
+                               for (String role : fullperm.roles) {\r
+                                       Result<Void> rv = null;\r
+                                       Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, q, role);\r
+                                       if(rrdd.isOKhasData()) {\r
+                                               trans.debug().log("Removing", role, "from", fullperm, "on Perm Delete");\r
+                                               if ((rv = q.roleDAO.delPerm(trans, rrdd.value, fullperm)).notOK()) {\r
+                                                       if (rv.notOK()) {\r
+                                                               trans.error().log("Error removing Role during delFromPermRole: ",\r
+                                                                                               trans.getUserPrincipal(),\r
+                                                                                               rv.errorString());\r
+                                                       }\r
+                                               }\r
+                                       } else {\r
+                                               return Result.err(rrdd);\r
+                                       }\r
+                               }\r
+                       } else if (!fullperm.roles.isEmpty()) {\r
+                               return Result\r
+                                               .err(Status.ERR_DependencyExists,\r
+                                                               "Permission [%s.%s|%s|%s] cannot be deleted as it is attached to 1 or more roles.",\r
+                                                               fullperm.ns, fullperm.type, fullperm.instance, fullperm.action);\r
+                       }\r
+               }\r
+\r
+               return q.permDAO.delete(trans, fullperm, false);\r
+       }\r
+\r
+       public Result<Void> deleteRole(final AuthzTrans trans, final RoleDAO.Data role, boolean force, boolean fromApproval) {\r
+               String user = trans.user();\r
+\r
+               // Next, see if User is allowed to Manage Role\r
+               Result<NsDAO.Data> rnsd;\r
+               if (!fromApproval) {\r
+                       rnsd = q.mayUser(trans, user, role, Access.write);\r
+                       if (rnsd.notOK()) {\r
+                               return Result.err(rnsd);\r
+                       }\r
+               }\r
+\r
+               // Are there any Users Attached to Role?\r
+               Result<List<UserRoleDAO.Data>> urdr = q.userRoleDAO.readByRole(trans,role.fullName());\r
+               if (force) {\r
+                       if (urdr.isOKhasData()) {\r
+                               for (UserRoleDAO.Data urd : urdr.value) {\r
+                                       q.userRoleDAO.delete(trans, urd, false);\r
+                               }\r
+                       }\r
+               } else if (urdr.isOKhasData()) {\r
+                       return Result.err(Status.ERR_DependencyExists,\r
+                                                       "Role [%s.%s] cannot be deleted as it is used by 1 or more Users.",\r
+                                                       role.ns, role.name);\r
+               }\r
+\r
+               // Does Role exist?\r
+               Result<List<RoleDAO.Data>> rdr = q.roleDAO.read(trans, role);\r
+               if (rdr.notOKorIsEmpty()) {\r
+                       return Result.err(Status.ERR_RoleNotFound,\r
+                                       "Role [%s.%s] does not exist", role.ns, role.name);\r
+               }\r
+               RoleDAO.Data fullrole = rdr.value.get(0); // full key search\r
+\r
+               // Remove Self from Permissions... always, force or not.  Force only applies to Dependencies (Users)\r
+               if (fullrole.perms != null) {\r
+                       for (String perm : fullrole.perms(false)) {\r
+                               Result<PermDAO.Data> rpd = PermDAO.Data.decode(trans,q,perm);\r
+                               if (rpd.isOK()) {\r
+                                       trans.debug().log("Removing", perm, "from", fullrole,"on Role Delete");\r
+\r
+                                       Result<?> r = q.permDAO.delRole(trans, rpd.value, fullrole);\r
+                                       if (r.notOK()) {\r
+                                               trans.error().log("ERR_FDR1 unable to remove",fullrole,"from",perm,':',r.status,'-',r.details);\r
+                                       }\r
+                               } else {\r
+                                       trans.error().log("ERR_FDR2 Could not remove",perm,"from",fullrole);\r
+                               }\r
+                       }\r
+               }\r
+               return q.roleDAO.delete(trans, fullrole, false);\r
+       }\r
+\r
+       /**\r
+        * Only owner of Permission may add to Role\r
+        * \r
+        * If force set, however, Role will be created before Grant, if User is\r
+        * allowed to create.\r
+        * \r
+        * @param trans\r
+        * @param role\r
+        * @param pd\r
+        * @return\r
+        */\r
+       public Result<Void> addPermToRole(AuthzTrans trans, RoleDAO.Data role,PermDAO.Data pd, boolean fromApproval) {\r
+               String user = trans.user();\r
+               \r
+               if (!fromApproval) {\r
+                       Result<NsDAO.Data> rRoleCo = q.deriveFirstNsForType(trans, role.ns, NsType.COMPANY);\r
+                       if(rRoleCo.notOK()) {\r
+                               return Result.err(rRoleCo);\r
+                       }\r
+                       Result<NsDAO.Data> rPermCo = q.deriveFirstNsForType(trans, pd.ns, NsType.COMPANY);\r
+                       if(rPermCo.notOK()) {\r
+                               return Result.err(rPermCo);\r
+                       }\r
+\r
+                       // Not from same company\r
+                       if(!rRoleCo.value.name.equals(rPermCo.value.name)) {\r
+                               Result<Data> r;\r
+                               // Only grant if User ALSO has Write ability in Other Company\r
+                               if((r = q.mayUser(trans, user, role, Access.write)).notOK()) {\r
+                                       return Result.err(r);\r
+                               }\r
+                       }\r
+                       \r
+\r
+                       // Must be Perm Admin, or Granted Special Permission\r
+                       Result<NsDAO.Data> ucp = q.mayUser(trans, user, pd, Access.write);\r
+                       if (ucp.notOK()) {\r
+                               // Don't allow CLI potential Grantees to change their own AAF\r
+                               // Perms,\r
+                               if ((Define.ROOT_NS.equals(pd.ns) && Question.NS.equals(pd.type)) \r
+                                               || !q.isGranted(trans, trans.user(),Define.ROOT_NS,Question.PERM, rPermCo.value.name, "grant")) {\r
+                               // Not otherwise granted\r
+                               // TODO Needed?\r
+                                       return Result.err(ucp);\r
+                               }\r
+                               // Final Check... Don't allow Grantees to add to Roles they are\r
+                               // part of\r
+                               Result<List<UserRoleDAO.Data>> rlurd = q.userRoleDAO\r
+                                               .readByUser(trans, trans.user());\r
+                               if (rlurd.isOK()) {\r
+                                       for (UserRoleDAO.Data ur : rlurd.value) {\r
+                                               if (role.ns.equals(ur.ns) && role.name.equals(ur.rname)) {\r
+                                                       return Result.err(ucp);\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               Result<List<PermDAO.Data>> rlpd = q.permDAO.read(trans, pd);\r
+               if (rlpd.notOKorIsEmpty()) {\r
+                       return Result.err(Status.ERR_PermissionNotFound,\r
+                                       "Permission must exist to add to Role");\r
+               }\r
+\r
+               Result<List<RoleDAO.Data>> rlrd = q.roleDAO.read(trans, role); // Already\r
+                                                                                                                                               // Checked\r
+                                                                                                                                               // for\r
+                                                                                                                                               // can\r
+                                                                                                                                               // change\r
+                                                                                                                                               // Role\r
+               Result<Void> rv;\r
+\r
+               if (rlrd.notOKorIsEmpty()) {\r
+                       if (trans.forceRequested()) {\r
+                               Result<NsDAO.Data> ucr = q.mayUser(trans, user, role,\r
+                                               Access.write);\r
+                               if (ucr.notOK()) {\r
+                                   return Result\r
+                                               .err(Status.ERR_Denied,\r
+                                                               "Role [%s.%s] does not exist. User [%s] cannot create.",\r
+                                                               role.ns, role.name, user);\r
+                               }\r
+\r
+                               role.perms(true).add(pd.encode());\r
+                               Result<RoleDAO.Data> rdd = q.roleDAO.create(trans, role);\r
+                               if (rdd.isOK()) {\r
+                                       rv = Result.ok();\r
+                               } else {\r
+                                       rv = Result.err(rdd);\r
+                               }\r
+                       } else {\r
+                           return Result.err(Status.ERR_RoleNotFound,\r
+                                       "Role [%s.%s] does not exist.", role.ns, role.name);\r
+                       }\r
+               } else {\r
+                       role = rlrd.value.get(0);\r
+                       if (role.perms(false).contains(pd.encode())) {\r
+                               return Result.err(Status.ERR_ConflictAlreadyExists,\r
+                                                               "Permission [%s.%s] is already a member of role [%s,%s]",\r
+                                                               pd.ns, pd.type, role.ns, role.name);\r
+                       }\r
+                       role.perms(true).add(pd.encode()); // this is added for Caching\r
+                                                                                               // access purposes... doesn't\r
+                                                                                               // affect addPerm\r
+                       rv = q.roleDAO.addPerm(trans, role, pd);\r
+               }\r
+               if (rv.status == Status.OK) {\r
+                       return q.permDAO.addRole(trans, pd, role);\r
+                       // exploring how to add information message to successful http\r
+                       // request\r
+               }\r
+               return rv;\r
+       }\r
+\r
+       /**\r
+        * Either Owner of Role or Permission may delete from Role\r
+        * \r
+        * @param trans\r
+        * @param role\r
+        * @param pd\r
+        * @return\r
+        */\r
+       public Result<Void> delPermFromRole(AuthzTrans trans, RoleDAO.Data role,PermDAO.Data pd, boolean fromApproval) {\r
+               String user = trans.user();\r
+               if (!fromApproval) {\r
+                       Result<NsDAO.Data> ucr = q.mayUser(trans, user, role, Access.write);\r
+                       Result<NsDAO.Data> ucp = q.mayUser(trans, user, pd, Access.write);\r
+\r
+                       // If Can't change either Role or Perm, then deny\r
+                       if (ucr.notOK() && ucp.notOK()) {\r
+                               return Result.err(Status.ERR_Denied,\r
+                                               "User [" + trans.user()\r
+                                                               + "] does not have permission to delete ["\r
+                                                               + pd.encode() + "] from Role ["\r
+                                                               + role.fullName() + ']');\r
+                       }\r
+               }\r
+\r
+               Result<List<RoleDAO.Data>> rlr = q.roleDAO.read(trans, role);\r
+               if (rlr.notOKorIsEmpty()) {\r
+                       // If Bad Data, clean out\r
+                       Result<List<PermDAO.Data>> rlp = q.permDAO.read(trans, pd);\r
+                       if (rlp.isOKhasData()) {\r
+                               for (PermDAO.Data pv : rlp.value) {\r
+                                       q.permDAO.delRole(trans, pv, role);\r
+                               }\r
+                       }\r
+                       return Result.err(rlr);\r
+               }\r
+               String perm1 = pd.encode();\r
+               boolean notFound;\r
+               if (trans.forceRequested()) {\r
+                       notFound = false;\r
+               } else { // only check if force not set.\r
+                       notFound = true;\r
+                       for (RoleDAO.Data r : rlr.value) {\r
+                               if (r.perms != null) {\r
+                                       for (String perm : r.perms) {\r
+                                               if (perm1.equals(perm)) {\r
+                                                       notFound = false;\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                                       if(!notFound) {\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               if (notFound) { // Need to check both, in case of corruption\r
+                       return Result.err(Status.ERR_PermissionNotFound,\r
+                                       "Permission [%s.%s|%s|%s] not associated with any Role",\r
+                                       pd.ns,pd.type,pd.instance,pd.action);\r
+               }\r
+\r
+               // Read Perm for full data\r
+               Result<List<PermDAO.Data>> rlp = q.permDAO.read(trans, pd);\r
+               Result<Void> rv = null;\r
+               if (rlp.isOKhasData()) {\r
+                       for (PermDAO.Data pv : rlp.value) {\r
+                               if ((rv = q.permDAO.delRole(trans, pv, role)).isOK()) {\r
+                                       if ((rv = q.roleDAO.delPerm(trans, role, pv)).notOK()) {\r
+                                               trans.error().log(\r
+                                                               "Error removing Perm during delFromPermRole:",\r
+                                                               trans.getUserPrincipal(), rv.errorString());\r
+                                       }\r
+                               } else {\r
+                                       trans.error().log(\r
+                                                       "Error removing Role during delFromPermRole:",\r
+                                                       trans.getUserPrincipal(), rv.errorString());\r
+                               }\r
+                       }\r
+               } else {\r
+                       rv = q.roleDAO.delPerm(trans, role, pd);\r
+                       if (rv.notOK()) {\r
+                               trans.error().log("Error removing Role during delFromPermRole",\r
+                                               rv.errorString());\r
+                       }\r
+               }\r
+               return rv == null ? Result.ok() : rv;\r
+       }\r
+\r
+       public Result<Void> delPermFromRole(AuthzTrans trans, String role,PermDAO.Data pd) {\r
+               Result<NsSplit> nss = q.deriveNsSplit(trans, role);\r
+               if (nss.notOK()) {\r
+                       return Result.err(nss);\r
+               }\r
+               RoleDAO.Data rd = new RoleDAO.Data();\r
+               rd.ns = nss.value.ns;\r
+               rd.name = nss.value.name;\r
+               return delPermFromRole(trans, rd, pd, false);\r
+       }\r
+\r
+       /**\r
+        * Add a User to Role\r
+        * \r
+        * 1) Role must exist 2) User must be a known Credential (i.e. mechID ok if\r
+        * Credential) or known Organizational User\r
+        * \r
+        * @param trans\r
+        * @param org\r
+        * @param urData\r
+        * @return\r
+        * @throws DAOException\r
+        */\r
+       public Result<Void> addUserRole(AuthzTrans trans,UserRoleDAO.Data urData) {\r
+               Result<Void> rv;\r
+               if(Question.ADMIN.equals(urData.rname)) {\r
+                       rv = mayAddAdmin(trans, urData.ns, urData.user);\r
+               } else if(Question.OWNER.equals(urData.rname)) {\r
+                       rv = mayAddOwner(trans, urData.ns, urData.user);\r
+               } else {\r
+                       rv = checkValidID(trans, new Date(), urData.user);\r
+               }\r
+               if(rv.notOK()) {\r
+                       return rv; \r
+               }\r
+               \r
+               // Check if record exists\r
+               if (q.userRoleDAO.read(trans, urData).isOKhasData()) {\r
+                       return Result.err(Status.ERR_ConflictAlreadyExists,\r
+                                       "User Role exists");\r
+               }\r
+               if (q.roleDAO.read(trans, urData.ns, urData.rname).notOKorIsEmpty()) {\r
+                       return Result.err(Status.ERR_RoleNotFound,\r
+                                       "Role [%s.%s] does not exist", urData.ns, urData.rname);\r
+               }\r
+\r
+               urData.expires = trans.org().expiration(null, Expiration.UserInRole, urData.user).getTime();\r
+               \r
+               \r
+               Result<UserRoleDAO.Data> udr = q.userRoleDAO.create(trans, urData);\r
+               switch (udr.status) {\r
+               case OK:\r
+                       return Result.ok();\r
+               default:\r
+                       return Result.err(udr);\r
+               }\r
+       }\r
+\r
+       public Result<Void> addUserRole(AuthzTrans trans, String user, String ns, String rname) {\r
+               UserRoleDAO.Data urdd = new UserRoleDAO.Data();\r
+               urdd.ns = ns;\r
+               urdd.role(ns, rname);\r
+               urdd.user = user;\r
+               return addUserRole(trans,urdd);\r
+       }\r
+\r
+       /**\r
+        * Extend User Role.\r
+        * \r
+        * extend the Expiration data, according to Organization rules.\r
+        * \r
+        * @param trans\r
+        * @param org\r
+        * @param urData\r
+        * @return\r
+        */\r
+       public Result<Void> extendUserRole(AuthzTrans trans, UserRoleDAO.Data urData, boolean checkForExist) {\r
+               // Check if record still exists\r
+               if (checkForExist && q.userRoleDAO.read(trans, urData).notOKorIsEmpty()) {\r
+                       return Result.err(Status.ERR_UserRoleNotFound,\r
+                                       "User Role does not exist");\r
+               }\r
+               if (q.roleDAO.read(trans, urData.ns, urData.rname).notOKorIsEmpty()) {\r
+                       return Result.err(Status.ERR_RoleNotFound,\r
+                                       "Role [%s.%s] does not exist", urData.ns,urData.rname);\r
+               }\r
+               // Special case for "Admin" roles. Issue brought forward with Prod\r
+               // problem 9/26\r
+\r
+               urData.expires = trans.org().expiration(null, Expiration.UserInRole).getTime(); // get\r
+                                                                                                                                                               // Full\r
+                                                                                                                                                               // time\r
+                                                                                                                                                               // starting\r
+                                                                                                                                                               // today\r
+               return q.userRoleDAO.update(trans, urData);\r
+       }\r
+\r
+       // ////////////////////////////////////////////////////\r
+       // Special User Role Functions\r
+       // These exist, because User Roles have Expiration dates, which must be\r
+       // accounted for\r
+       // Also, as of July, 2015, Namespace Owners and Admins are now regular User\r
+       // Roles\r
+       // ////////////////////////////////////////////////////\r
+       public Result<List<String>> getUsersByRole(AuthzTrans trans, String role, boolean includeExpired) {\r
+               Result<List<UserRoleDAO.Data>> rurdd = q.userRoleDAO.readByRole(trans,role);\r
+               if (rurdd.notOK()) {\r
+                       return Result.err(rurdd);\r
+               }\r
+               Date now = new Date();\r
+               List<UserRoleDAO.Data> list = rurdd.value;\r
+               List<String> rv = new ArrayList<String>(list.size()); // presize\r
+               for (UserRoleDAO.Data urdd : rurdd.value) {\r
+                       if (includeExpired || urdd.expires.after(now)) {\r
+                               rv.add(urdd.user);\r
+                       }\r
+               }\r
+               return Result.ok(rv);\r
+       }\r
+\r
+       public Result<Void> delUserRole(AuthzTrans trans, String user, String ns, String rname) {\r
+               UserRoleDAO.Data urdd = new UserRoleDAO.Data();\r
+               urdd.user = user;\r
+               urdd.role(ns,rname);\r
+               Result<List<UserRoleDAO.Data>> r = q.userRoleDAO.read(trans, urdd);\r
+               if (r.status == 404 || r.isEmpty()) {\r
+                       return Result.err(Status.ERR_UserRoleNotFound,\r
+                                       "UserRole [%s] [%s.%s]", user, ns, rname);\r
+               }\r
+               if (r.notOK()) {\r
+                       return Result.err(r);\r
+               }\r
+\r
+               return q.userRoleDAO.delete(trans, urdd, false);\r
+       }\r
+\r
+       public Result<List<Identity>> createFuture(AuthzTrans trans, FutureDAO.Data data, String id, String user,\r
+                       NsDAO.Data nsd, String op) {\r
+               // Create Future Object\r
+               List<Identity> approvers=null;\r
+               Result<FutureDAO.Data> fr = q.futureDAO.create(trans, data, id);\r
+               if (fr.isOK()) {\r
+                       // User Future ID as ticket for Approvals\r
+                       final UUID ticket = fr.value.id;\r
+                       ApprovalDAO.Data ad;\r
+                       try {\r
+                               Organization org = trans.org();\r
+                               approvers = org.getApprovers(trans, user);\r
+                               for (Identity u : approvers) {\r
+                                       ad = new ApprovalDAO.Data();\r
+                                       // Note ad.id is set by ApprovalDAO Create\r
+                                       ad.ticket = ticket;\r
+                                       ad.user = user;\r
+                                       ad.approver = u.id();\r
+                                       ad.status = ApprovalDAO.PENDING;\r
+                                       ad.memo = data.memo;\r
+                                       ad.type = org.getApproverType();\r
+                                       ad.operation = op;\r
+                                       // Note ad.updated is created in System\r
+                                       Result<ApprovalDAO.Data> ar = q.approvalDAO.create(trans,ad);\r
+                                       if (ar.notOK()) {\r
+                                               return Result.err(Status.ERR_ActionNotCompleted,\r
+                                                               "Approval for %s, %s could not be created: %s",\r
+                                                               ad.user, ad.approver, ar.details);\r
+                                       }\r
+                               }\r
+                               if (nsd != null) {\r
+                                       Result<List<UserRoleDAO.Data>> rrbr = q.userRoleDAO\r
+                                                       .readByRole(trans, nsd.name + Question.DOT_OWNER);\r
+                                       if (rrbr.isOK()) {\r
+                                               for (UserRoleDAO.Data urd : rrbr.value) {\r
+                                                       ad = new ApprovalDAO.Data();\r
+                                                       // Note ad.id is set by ApprovalDAO Create\r
+                                                       ad.ticket = ticket;\r
+                                                       ad.user = user;\r
+                                                       ad.approver = urd.user;\r
+                                                       ad.status = ApprovalDAO.PENDING;\r
+                                                       ad.memo = data.memo;\r
+                                                       ad.type = "owner";\r
+                                                       ad.operation = op;\r
+                                                       // Note ad.updated is created in System\r
+                                                       Result<ApprovalDAO.Data> ar = q.approvalDAO.create(trans, ad);\r
+                                                       if (ar.notOK()) {\r
+                                                               return Result.err(Status.ERR_ActionNotCompleted,\r
+                                                                                               "Approval for %s, %s could not be created: %s",\r
+                                                                                               ad.user, ad.approver,\r
+                                                                                               ar.details);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       } catch (Exception e) {\r
+                               return Result.err(e);\r
+                       }\r
+               }\r
+               \r
+               return Result.ok(approvers);\r
+       }\r
+\r
+       public Result<Void> performFutureOp(AuthzTrans trans, ApprovalDAO.Data cd) {\r
+               Result<List<FutureDAO.Data>> fd = q.futureDAO.read(trans, cd.ticket);\r
+               Result<List<ApprovalDAO.Data>> allApprovalsForTicket = q.approvalDAO\r
+                               .readByTicket(trans, cd.ticket);\r
+               Result<Void> rv = Result.ok();\r
+               for (FutureDAO.Data curr : fd.value) {\r
+                       if ("approved".equalsIgnoreCase(cd.status)) {\r
+                               if (allApprovalsForTicket.value.size() <= 1) {\r
+                                       // should check if any other pendings before performing\r
+                                       // actions\r
+                                       try {\r
+                                               if (FOP_ROLE.equalsIgnoreCase(curr.target)) {\r
+                                                       RoleDAO.Data data = new RoleDAO.Data();\r
+                                                       data.reconstitute(curr.construct);\r
+                                                       if ("C".equalsIgnoreCase(cd.operation)) {\r
+                                                               Result<RoleDAO.Data> rd;\r
+                                                               if ((rd = q.roleDAO.dao().create(trans, data)).notOK()) {\r
+                                                                       rv = Result.err(rd);\r
+                                                               }\r
+                                                       } else if ("D".equalsIgnoreCase(cd.operation)) {\r
+                                                               rv = deleteRole(trans, data, true, true);\r
+                                                       }\r
+       \r
+                                               } else if (FOP_PERM.equalsIgnoreCase(curr.target)) {\r
+                                                       PermDAO.Data pdd = new PermDAO.Data();\r
+                                                       pdd.reconstitute(curr.construct);\r
+                                                       if ("C".equalsIgnoreCase(cd.operation)) {\r
+                                                               rv = createPerm(trans, pdd, true);\r
+                                                       } else if ("D".equalsIgnoreCase(cd.operation)) {\r
+                                                               rv = deletePerm(trans, pdd, true, true);\r
+                                                       } else if ("G".equalsIgnoreCase(cd.operation)) {\r
+                                                               Set<String> roles = pdd.roles(true);\r
+                                                               Result<RoleDAO.Data> rrdd = null;\r
+                                                               for (String roleStr : roles) {\r
+                                                                       rrdd = RoleDAO.Data.decode(trans, q, roleStr);\r
+                                                                       if (rrdd.isOKhasData()) {\r
+                                                                               rv = addPermToRole(trans, rrdd.value, pdd, true);\r
+                                                                       } else {\r
+                                                                               trans.error().log(rrdd.errorString());\r
+                                                                       }\r
+                                                               }\r
+                                                       } else if ("UG".equalsIgnoreCase(cd.operation)) {\r
+                                                               Set<String> roles = pdd.roles(true);\r
+                                                               Result<RoleDAO.Data> rrdd;\r
+                                                               for (String roleStr : roles) {\r
+                                                                       rrdd = RoleDAO.Data.decode(trans, q, roleStr);\r
+                                                                       if (rrdd.isOKhasData()) {\r
+                                                                               rv = delPermFromRole(trans, rrdd.value, pdd,    true);\r
+                                                                       } else {\r
+                                                                               trans.error().log(rrdd.errorString());\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+       \r
+                                               } else if (FOP_USER_ROLE.equalsIgnoreCase(curr.target)) {\r
+                                                       UserRoleDAO.Data data = new UserRoleDAO.Data();\r
+                                                       data.reconstitute(curr.construct);\r
+                                                       // if I am the last to approve, create user role\r
+                                                       if ("C".equalsIgnoreCase(cd.operation)) {\r
+                                                               rv = addUserRole(trans, data);\r
+                                                       } else if ("U".equals(cd.operation)) {\r
+                                                               rv = extendUserRole(trans, data, true);\r
+                                                       }\r
+       \r
+                                               } else if (FOP_NS.equalsIgnoreCase(curr.target)) {\r
+                                                       Namespace namespace = new Namespace();\r
+                                                       namespace.reconstitute(curr.construct);\r
+       \r
+                                                       if ("C".equalsIgnoreCase(cd.operation)) {\r
+                                                               rv = createNS(trans, namespace, true);\r
+                                                       }\r
+       \r
+                                               } else if (FOP_DELEGATE.equalsIgnoreCase(curr.target)) {\r
+                                                       DelegateDAO.Data data = new DelegateDAO.Data();\r
+                                                       data.reconstitute(curr.construct);\r
+                                                       if ("C".equalsIgnoreCase(cd.operation)) {\r
+                                                               Result<DelegateDAO.Data> dd;\r
+                                                               if ((dd = q.delegateDAO.create(trans, data)).notOK()) {\r
+                                                                       rv = Result.err(dd);\r
+                                                               }\r
+                                                       } else if ("U".equalsIgnoreCase(cd.operation)) {\r
+                                                               rv = q.delegateDAO.update(trans, data);\r
+                                                       }\r
+                                               } else if (FOP_CRED.equalsIgnoreCase(curr.target)) {\r
+                                                       CredDAO.Data data = new CredDAO.Data();\r
+                                                       data.reconstitute(curr.construct);\r
+                                                       if ("C".equalsIgnoreCase(cd.operation)) {\r
+                                                               Result<CredDAO.Data> rd;\r
+                                                               if ((rd = q.credDAO.dao().create(trans, data)).notOK()) {\r
+                                                                       rv = Result.err(rd);\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       } catch (IOException e) {\r
+                                               trans.error().log("IOException: ", e.getMessage(),\r
+                                                               " \n occurred while performing", cd.memo,\r
+                                                               " from approval ", cd.id.toString());\r
+                                       }\r
+                               }\r
+                       } else if ("denied".equalsIgnoreCase(cd.status)) {\r
+                               for (ApprovalDAO.Data ad : allApprovalsForTicket.value) {\r
+                                   q.approvalDAO.delete(trans, ad, false);\r
+                               }\r
+                               q.futureDAO.delete(trans, curr, false);\r
+                               if (FOP_USER_ROLE.equalsIgnoreCase(curr.target)) {\r
+                                       // if I am the last to approve, create user role\r
+                                       if ("U".equals(cd.operation)) {\r
+                                               UserRoleDAO.Data data = new UserRoleDAO.Data();\r
+                                               try {\r
+                                                       data.reconstitute(curr.construct);\r
+                                               } catch (IOException e) {\r
+                                                       trans.error().log("Cannot reconstitue",curr.memo);\r
+                                               }\r
+                                               rv = delUserRole(trans, data.user, data.ns, data.rname);\r
+                                       }\r
+                               }\r
+\r
+                       }\r
+       \r
+                       // if I am the last to approve, delete the future object\r
+                       if (rv.isOK() && allApprovalsForTicket.value.size() <= 1) {\r
+                               q.futureDAO.delete(trans, curr, false);\r
+                       }\r
+       \r
+               } // end for each\r
+               return rv;\r
+       \r
+       }\r
+\r
+       public Executor newExecutor(AuthzTrans trans) {\r
+               return new CassExecutor(trans, this);\r
+       }\r
+\r
+}\r