Collection syntax change because of Sonar
[aaf/authz.git] / auth / auth-cass / src / main / java / org / onap / aaf / auth / dao / hl / Function.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.auth.dao.hl;
23
24 import static org.onap.aaf.auth.layer.Result.OK;
25
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Date;
29 import java.util.GregorianCalendar;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Set;
33 import java.util.UUID;
34
35 import org.onap.aaf.auth.common.Define;
36 import org.onap.aaf.auth.dao.DAOException;
37 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
38 import org.onap.aaf.auth.dao.cass.CredDAO;
39 import org.onap.aaf.auth.dao.cass.DelegateDAO;
40 import org.onap.aaf.auth.dao.cass.FutureDAO;
41 import org.onap.aaf.auth.dao.cass.Namespace;
42 import org.onap.aaf.auth.dao.cass.NsDAO;
43 import org.onap.aaf.auth.dao.cass.NsDAO.Data;
44 import org.onap.aaf.auth.dao.cass.NsSplit;
45 import org.onap.aaf.auth.dao.cass.NsType;
46 import org.onap.aaf.auth.dao.cass.PermDAO;
47 import org.onap.aaf.auth.dao.cass.RoleDAO;
48 import org.onap.aaf.auth.dao.cass.Status;
49 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
50 import org.onap.aaf.auth.dao.hl.Question.Access;
51 import org.onap.aaf.auth.env.AuthzTrans;
52 import org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE;
53 import org.onap.aaf.auth.layer.Result;
54 import org.onap.aaf.auth.org.Executor;
55 import org.onap.aaf.auth.org.Organization;
56 import org.onap.aaf.auth.org.Organization.Expiration;
57 import org.onap.aaf.auth.org.Organization.Identity;
58 import org.onap.aaf.auth.org.Organization.Policy;
59 import org.onap.aaf.auth.org.OrganizationException;
60
61 public class Function {
62
63         private static final String CANNOT_BE_THE_OWNER_OF_A_NAMESPACE = "%s(%s) cannot be the owner of the namespace '%s'. Owners %s.";
64
65         public enum FUTURE_OP {
66                 C("Create"),U("Update"),D("Delete"),G("Grant"),UG("UnGrant"),A("Approval");
67                 
68                 private String desc;
69         
70                 private FUTURE_OP(String desc) {
71                         this.desc = desc;
72                 }
73                 
74                 public String desc() {
75                         return desc;
76                 }
77                 
78                 /**
79                  *  Same as valueOf(), but passes back null instead of throwing Exception
80                  * @param value
81                  * @return
82                  */
83                 public static FUTURE_OP toFO(String value) {
84                         if(value!=null) {
85                                 for(FUTURE_OP fo : values()) {
86                                         if(fo.name().equals(value)){
87                                                 return fo;
88                                         }
89                                 }
90                         }
91                         return null;
92                 }
93         }
94
95         public enum OP_STATUS {
96                 E("Executed"),D("Denied"),P("Pending"),L("Lapsed");
97                 
98                 private String desc;
99                 public final static Result<OP_STATUS> RE = Result.ok(OP_STATUS.E);
100                 public final static Result<OP_STATUS> RD = Result.ok(OP_STATUS.D);
101                 public final static Result<OP_STATUS> RP = Result.ok(OP_STATUS.P);
102                 public final static Result<OP_STATUS> RL = Result.ok(OP_STATUS.L);
103
104                 private OP_STATUS(String desc) {
105                         this.desc = desc;
106                 }
107                 
108                 public String desc() {
109                         return desc;
110                 }
111                 
112         }
113
114         public static final String FOP_CRED = "cred";
115         public static final String FOP_DELEGATE = "delegate";
116         public static final String FOP_NS = "ns";
117         public static final String FOP_PERM = "perm";
118         public static final String FOP_ROLE = "role";
119         public static final String FOP_USER_ROLE = "user_role";
120         private static final List<Identity> NO_ADDL_APPROVE = new ArrayList<>();
121         private static final String ROOT_NS = Define.ROOT_NS();
122         // First Action should ALWAYS be "write", see "CreateRole"
123         public final Question q;
124
125         public Function(AuthzTrans trans, Question question) {
126                 q = question;
127         }
128
129         private class ErrBuilder {
130                 private StringBuilder sb;
131                 private List<String> ao;
132
133                 public void log(Result<?> result) {
134                         if (result.notOK()) {
135                                 if (sb == null) {
136                                         sb = new StringBuilder();
137                                         ao = new ArrayList<>();
138                                 }
139                                 sb.append(result.details);
140                                 sb.append('\n');
141                                 for (String s : result.variables) {
142                                         ao.add(s);
143                                 }
144                         }
145                 }
146
147                 public String[] vars() {
148                         String[] rv = new String[ao.size()];
149                         ao.toArray(rv);
150                         return rv;
151                 }
152
153                 public boolean hasErr() {
154                         return sb != null;
155                 }
156
157                 @Override
158                 public String toString() {
159                         return sb == null ? "" : String.format(sb.toString(), ao);
160                 }
161         }
162
163         /**
164          * createNS
165          * 
166          * Create Namespace
167          * 
168          * @param trans
169          * @param org
170          * @param ns
171          * @param user
172          * @return
173          * @throws DAOException
174          * 
175          *             To create an NS, you need to: 1) validate permission to
176          *             modify parent NS 2) Does NS exist already? 3) Create NS with
177          *             a) "user" as owner. NOTE: Per 10-15 request for AAF 1.0 4)
178          *             Loop through Roles with Parent NS, and map any that start
179          *             with this NS into this one 5) Loop through Perms with Parent
180          *             NS, and map any that start with this NS into this one
181          */
182         public Result<Void> createNS(AuthzTrans trans, Namespace namespace, boolean fromApproval) {
183                 Result<?> rq;
184 //              if (namespace.name.endsWith(Question.DOT_ADMIN)
185 //                              || namespace.name.endsWith(Question.DOT_OWNER)) {
186 //                      return Result.err(Status.ERR_BadData,
187 //                                      "'admin' and 'owner' are reserved names in AAF");
188 //              }
189
190                 try {
191                         for (String u : namespace.owner) {
192                                 Organization org = trans.org();
193                                 Identity orgUser = org.getIdentity(trans, u);
194                                 String reason;
195                                 if (orgUser == null) {
196                                         return Result.err(Status.ERR_Policy,"%s is not a valid user at %s",u,org.getName());    
197                                 } else if((reason=orgUser.mayOwn())!=null) {
198                                         if (org.isTestEnv()) {
199                                                 String reason2;
200                                                 if((reason2=org.validate(trans, Policy.AS_RESPONSIBLE,new CassExecutor(trans, this), u))!=null) { // can masquerade as responsible
201                                                         trans.debug().log(reason2);
202                                                         return Result.err(Status.ERR_Policy,CANNOT_BE_THE_OWNER_OF_A_NAMESPACE,orgUser.fullName(),orgUser.id(),namespace.name,reason);
203                                                 }
204                                                 // a null means ok
205                                         } else {
206                                                 if(orgUser.isFound()) {
207                                                         return Result.err(Status.ERR_Policy,CANNOT_BE_THE_OWNER_OF_A_NAMESPACE,orgUser.fullName(),orgUser.id(),namespace.name, reason);
208                                                 } else {
209                                                         return Result.err(Status.ERR_Policy,u + " is an invalid Identity");
210                                                 }
211                                         }
212                                 }
213                         }
214                 } catch (Exception e) {
215                         trans.error().log(e,
216                                         "Could not contact Organization for User Validation");
217                 }
218
219                 String user = trans.user();
220                 // 1) May Change Parent?
221                 int idx = namespace.name.lastIndexOf('.');
222                 String parent;
223                 if (idx < 0) {
224                         if (!q.isGranted(trans, user, ROOT_NS,Question.NS, ".", "create")) {
225                                 return Result.err(Result.ERR_Security,
226                                                 "%s may not create Root Namespaces", user);
227                         }
228                         parent = null;
229                         fromApproval = true;
230                 } else {
231                         parent = namespace.name.substring(0, idx); // get Parent String
232                 }
233
234                 Result<NsDAO.Data> rparent = q.deriveNs(trans, parent);
235                 if (rparent.notOK()) {
236                         return Result.err(rparent);
237                 }
238                 if (!fromApproval) {
239                         rparent = q.mayUser(trans, user, rparent.value, Access.write);
240                         if (rparent.notOK()) {
241                                 return Result.err(rparent);
242                         }
243                 }
244                 parent = namespace.parent = rparent.value.name; // Correct Namespace from real data
245
246                 // 2) Does requested NS exist
247                 if (q.nsDAO.read(trans, namespace.name).isOKhasData()) {
248                         return Result.err(Status.ERR_ConflictAlreadyExists,
249                                         "Target Namespace already exists");
250                 }
251
252                 // Someone must be responsible.
253                 if (namespace.owner == null || namespace.owner.isEmpty()) {
254                         return Result
255                                         .err(Status.ERR_Policy,
256                                                         "Namespaces must be assigned at least one responsible party");
257                 }
258
259                 // 3) Create NS
260                 Date now = new Date();
261
262                 Result<Void> r;
263                 // 3a) Admin
264
265                 try {
266                         // Originally, added the enterer as Admin, but that's not necessary,
267                         // or helpful for Operations folks..
268                         // Admins can be empty, because they can be changed by lower level
269                         // NSs
270                         // if(ns.admin(false).isEmpty()) {
271                         // ns.admin(true).add(user);
272                         // }
273                         if (namespace.admin != null) {
274                                 for (String u : namespace.admin) {
275                                         if ((r = checkValidID(trans, now, u)).notOK()) {
276                                                 return r;
277                                         }
278                                 }
279                         }
280
281                         // 3b) Responsible
282                         Organization org = trans.org();
283                         for (String u : namespace.owner) {
284                                 Identity orgUser = org.getIdentity(trans, u);
285                                 if (orgUser == null) {
286                                         return Result
287                                                         .err(Status.ERR_BadData,
288                                                                         "NS must be created with an %s approved Responsible Party",
289                                                                         org.getName());
290                                 }
291                         }
292                 } catch (Exception e) {
293                         return Result.err(Status.ERR_UserNotFound, e.getMessage());
294                 }
295
296                 // VALIDATIONS done... Add NS
297                 if ((rq = q.nsDAO.create(trans, namespace.data())).notOK()) {
298                     return Result.err(rq);
299                 }
300
301                 // Since Namespace is now created, we need to grab all subsequent errors
302                 ErrBuilder eb = new ErrBuilder();
303
304                 // Add UserRole(s)
305                 UserRoleDAO.Data urdd = new UserRoleDAO.Data();
306                 urdd.expires = trans.org().expiration(null, Expiration.UserInRole).getTime();
307                 urdd.role(namespace.name, Question.ADMIN);
308                 for (String admin : namespace.admin) {
309                         urdd.user = admin;
310                         eb.log(q.userRoleDAO.create(trans, urdd));
311                 }
312                 urdd.role(namespace.name,Question.OWNER);
313                 for (String owner : namespace.owner) {
314                         urdd.user = owner;
315                         eb.log(q.userRoleDAO.create(trans, urdd));
316                 }
317
318                 addNSAdminRolesPerms(trans, eb, namespace.name);
319
320                 addNSOwnerRolesPerms(trans, eb, namespace.name);
321
322                 if (parent != null) {
323                         // Build up with any errors
324
325                         String targetNs = rparent.value.name; // Get the Parent Namespace,
326                                                                                                         // not target
327                         String targetName = namespace.name.substring(targetNs.length() + 1); // Remove the Parent Namespace from the
328                                                                         // Target + a dot, and you'll get the name
329                         int targetNameDot = targetName.length() + 1;
330
331                         // 4) Change any roles with children matching this NS, and
332                         Result<List<RoleDAO.Data>> rrdc = q.roleDAO.readChildren(trans, targetNs, targetName);
333                         if (rrdc.isOKhasData()) {
334                                 for (RoleDAO.Data rdd : rrdc.value) {
335                                         // Remove old Role from Perms, save them off
336                                         List<PermDAO.Data> lpdd = new ArrayList<>();
337                                         for(String p : rdd.perms(false)) {
338                                                 Result<PermDAO.Data> rpdd = PermDAO.Data.decode(trans,q,p);
339                                                 if(rpdd.isOKhasData()) {
340                                                         PermDAO.Data pdd = rpdd.value;
341                                                         lpdd.add(pdd);
342                                                         q.permDAO.delRole(trans, pdd, rdd);
343                                                 } else{
344                                                         trans.error().log(rpdd.errorString());
345                                                 }
346                                         }
347                                         
348                                         // Save off Old keys
349                                         String delP1 = rdd.ns;
350                                         String delP2 = rdd.name;
351
352                                         // Write in new key
353                                         rdd.ns = namespace.name;
354                                         rdd.name = (delP2.length() > targetNameDot) ? delP2
355                                                         .substring(targetNameDot) : "";
356                                                         
357                                         // Need to use non-cached, because switching namespaces, not
358                                         // "create" per se
359                                         if ((rq = q.roleDAO.create(trans, rdd)).isOK()) {
360                                                 // Put Role back into Perm, with correct info
361                                                 for(PermDAO.Data pdd : lpdd) {
362                                                         q.permDAO.addRole(trans, pdd, rdd);
363                                                 }
364                                                 // Change data for User Roles 
365                                                 Result<List<UserRoleDAO.Data>> rurd = q.userRoleDAO.readByRole(trans, rdd.fullName());
366                                                 if(rurd.isOKhasData()) {
367                                                         for(UserRoleDAO.Data urd : rurd.value) {
368                                                                 urd.ns = rdd.ns;
369                                                                 urd.rname = rdd.name;
370                                                                 q.userRoleDAO.update(trans, urd);
371                                                         }
372                                                 }
373                                                 // Now delete old one
374                                                 rdd.ns = delP1;
375                                                 rdd.name = delP2;
376                                                 if ((rq = q.roleDAO.delete(trans, rdd, false)).notOK()) {
377                                                         eb.log(rq);
378                                                 }
379                                         } else {
380                                                 eb.log(rq);
381                                         }
382                                 }
383                         }
384
385                         // 4) Change any Permissions with children matching this NS, and
386                         Result<List<PermDAO.Data>> rpdc = q.permDAO.readChildren(trans,targetNs, targetName);
387                         if (rpdc.isOKhasData()) {
388                                 for (PermDAO.Data pdd : rpdc.value) {
389                                         // Remove old Perm from Roles, save them off
390                                         List<RoleDAO.Data> lrdd = new ArrayList<>();
391                                         
392                                         for(String rl : pdd.roles(false)) {
393                                                 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,q,rl);
394                                                 if(rrdd.isOKhasData()) {
395                                                         RoleDAO.Data rdd = rrdd.value;
396                                                         lrdd.add(rdd);
397                                                         q.roleDAO.delPerm(trans, rdd, pdd);
398                                                 } else{
399                                                         trans.error().log(rrdd.errorString());
400                                                 }
401                                         }
402                                         
403                                         // Save off Old keys
404                                         String delP1 = pdd.ns;
405                                         String delP2 = pdd.type;
406                                         pdd.ns = namespace.name;
407                                         pdd.type = (delP2.length() > targetNameDot) ? delP2
408                                                         .substring(targetNameDot) : "";
409                                         if ((rq = q.permDAO.create(trans, pdd)).isOK()) {
410                                                 // Put Role back into Perm, with correct info
411                                                 for(RoleDAO.Data rdd : lrdd) {
412                                                         q.roleDAO.addPerm(trans, rdd, pdd);
413                                                 }
414
415                                                 pdd.ns = delP1;
416                                                 pdd.type = delP2;
417                                                 if ((rq = q.permDAO.delete(trans, pdd, false)).notOK()) {
418                                                         eb.log(rq);
419                                                         // } else {
420                                                         // Need to invalidate directly, because we're
421                                                         // switching places in NS, not normal cache behavior
422                                                         // q.permDAO.invalidate(trans,pdd);
423                                                 }
424                                         } else {
425                                                 eb.log(rq);
426                                         }
427                                 }
428                         }
429                         if (eb.hasErr()) {
430                                 return Result.err(Status.ERR_ActionNotCompleted,eb.sb.toString(), eb.vars());
431                         }
432                 }
433                 return Result.ok();
434         }
435
436         private void addNSAdminRolesPerms(AuthzTrans trans, ErrBuilder eb, String ns) {
437                 // Admin Role/Perm
438                 RoleDAO.Data rd = new RoleDAO.Data();
439                 rd.ns = ns;
440                 rd.name = "admin";
441                 rd.description = "AAF Namespace Administrators";
442
443                 PermDAO.Data pd = new PermDAO.Data();
444                 pd.ns = ns;
445                 pd.type = "access";
446                 pd.instance = Question.ASTERIX;
447                 pd.action = Question.ASTERIX;
448                 pd.description = "AAF Namespace Write Access";
449
450                 rd.perms = new HashSet<>();
451                 rd.perms.add(pd.encode());
452                 eb.log(q.roleDAO.create(trans, rd));
453
454                 pd.roles = new HashSet<>();
455                 pd.roles.add(rd.encode());
456                 eb.log(q.permDAO.create(trans, pd));
457         }
458
459         private void addNSOwnerRolesPerms(AuthzTrans trans, ErrBuilder eb, String ns) {
460                 RoleDAO.Data rd = new RoleDAO.Data();
461                 rd.ns = ns;
462                 rd.name = "owner";
463                 rd.description = "AAF Namespace Owners";
464
465                 PermDAO.Data pd = new PermDAO.Data();
466                 pd.ns = ns;
467                 pd.type = "access";
468                 pd.instance = Question.ASTERIX;
469                 pd.action = Question.READ;
470                 pd.description = "AAF Namespace Read Access";
471
472                 rd.perms = new HashSet<>();
473                 rd.perms.add(pd.encode());
474                 eb.log(q.roleDAO.create(trans, rd));
475
476                 pd.roles = new HashSet<>();
477                 pd.roles.add(rd.encode());
478                 eb.log(q.permDAO.create(trans, pd));
479         }
480
481         /**
482          * deleteNS
483          * 
484          * Delete Namespace
485          * 
486          * @param trans
487          * @param org
488          * @param ns
489          * @param force
490          * @param user
491          * @return
492          * @throws DAOException
493          * 
494          * 
495          *             To delete an NS, you need to: 1) validate permission to
496          *             modify this NS 2) Find all Roles with this NS, and 2a) if
497          *             Force, delete them, else modify to Parent NS 3) Find all
498          *             Perms with this NS, and modify to Parent NS 3a) if Force,
499          *             delete them, else modify to Parent NS 4) Find all IDs
500          *             associated to this NS, and deny if exists. 5) Remove NS
501          */
502         public Result<Void> deleteNS(AuthzTrans trans, String ns) {
503                 boolean force = trans.requested(REQD_TYPE.force);
504                 boolean move = trans.requested(REQD_TYPE.move);
505                 // 1) Validate
506                 Result<List<NsDAO.Data>> nsl;
507                 if ((nsl = q.nsDAO.read(trans, ns)).notOKorIsEmpty()) {
508                         return Result.err(Status.ERR_NsNotFound, "%s does not exist", ns);
509                 }
510                 NsDAO.Data nsd = nsl.value.get(0);
511                 NsType nt;
512                 if (move && !q.canMove(nt = NsType.fromType(nsd.type))) {
513                         return Result.err(Status.ERR_Denied, "Namespace Force=move not permitted for Type %s",nt.name());
514                 }
515
516                 Result<NsDAO.Data> dnr = q.mayUser(trans, trans.user(), nsd, Access.write);
517                 if (dnr.status != Status.OK) {
518                         return Result.err(dnr);
519                 }
520
521                 // 2) Find Parent
522                 String user = trans.user();
523                 int idx = ns.lastIndexOf('.');
524                 NsDAO.Data parent;
525                 if (idx < 0) {
526                         if (!q.isGranted(trans, user, ROOT_NS,Question.NS, ".", "delete")) {
527                                 return Result.err(Result.ERR_Security,
528                                                 "%s may not delete Root Namespaces", user);
529                         }
530                         parent = null;
531                 } else {
532                         Result<NsDAO.Data> rlparent = q.deriveNs(trans, ns.substring(0, idx));
533                         if (rlparent.notOKorIsEmpty()) {
534                                 return Result.err(rlparent);
535                         }
536                         parent = rlparent.value;
537                 }
538
539                 // Build up with any errors
540                 // If sb != null below is an indication of error
541                 StringBuilder sb = null;
542                 ErrBuilder er = new ErrBuilder();
543
544                 // 2a) Deny if any IDs on Namespace
545                 Result<List<CredDAO.Data>> creds = q.credDAO.readNS(trans, ns);
546                 if (creds.isOKhasData()) {
547                         if (force || move) {
548                                 for (CredDAO.Data cd : creds.value) {
549                                         er.log(q.credDAO.delete(trans, cd, false));
550                                         // Since we're deleting all the creds, we should delete all
551                                         // the user Roles for that Cred
552                                         Result<List<UserRoleDAO.Data>> rlurd = q.userRoleDAO
553                                                         .readByUser(trans, cd.id);
554                                         if (rlurd.isOK()) {
555                                                 for (UserRoleDAO.Data data : rlurd.value) {
556                                                     q.userRoleDAO.delete(trans, data, false);
557                                                 }
558                                         }
559
560                                 }
561                         } else {
562                                 // first possible StringBuilder Create.
563                                 sb = new StringBuilder();
564                                 sb.append('[');
565                                 sb.append(ns);
566                                 sb.append("] contains users");
567                         }
568                 }
569
570                 // 2b) Find (or delete if forced flag is set) dependencies
571                 // First, find if NS Perms are the only ones
572                 Result<List<PermDAO.Data>> rpdc = q.permDAO.readNS(trans, ns);
573                 if (rpdc.isOKhasData()) {
574                         // Since there are now NS perms, we have to count NON-NS perms.
575                         // FYI, if we delete them now, and the NS is not deleted, it is in
576                         // an inconsistent state.
577                         boolean nonaccess = false;
578                         for (PermDAO.Data pdd : rpdc.value) {
579                                 if (!"access".equals(pdd.type)) {
580                                         nonaccess = true;
581                                         break;
582                                 }
583                         }
584                         if (nonaccess && !force && !move) {
585                                 if (sb == null) {
586                                         sb = new StringBuilder();
587                                         sb.append('[');
588                                         sb.append(ns);
589                                         sb.append("] contains ");
590                                 } else {
591                                         sb.append(", ");
592                                 }
593                                 sb.append("permissions");
594                         }
595                 }
596
597                 Result<List<RoleDAO.Data>> rrdc = q.roleDAO.readNS(trans, ns);
598                 if (rrdc.isOKhasData()) {
599                         // Since there are now NS roles, we have to count NON-NS roles.
600                         // FYI, if we delete th)em now, and the NS is not deleted, it is in
601                         // an inconsistent state.
602                         int count = rrdc.value.size();
603                         for (RoleDAO.Data rdd : rrdc.value) {
604                                 if ("admin".equals(rdd.name) || "owner".equals(rdd.name)) {
605                                         --count;
606                                 }
607                         }
608                         if (count > 0 && !force && !move) {
609                                 if (sb == null) {
610                                         sb = new StringBuilder();
611                                         sb.append('[');
612                                         sb.append(ns);
613                                         sb.append("] contains ");
614                                 } else {
615                                         sb.append(", ");
616                                 }
617                                 sb.append("roles");
618                         }
619                 }
620
621                 // 2c) Deny if dependencies exist that would be moved to root level
622                 // parent is root level parent here. Need to find closest parent ns that
623                 // exists
624                 if (sb != null) {
625                         if (!force && !move) {
626                                 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.");
627                                 return Result.err(Status.ERR_DependencyExists, sb.toString());
628                         }
629
630                         if (move && (parent == null || parent.type == NsType.COMPANY.type)) {
631                                 return Result
632                                                 .err(Status.ERR_DependencyExists,
633                                                                 "Cannot move users, roles or permissions to [%s].\nDelete dependencies and try again",
634                                                                 parent.name);
635                         }
636                 } else if (move && parent != null) {
637                         sb = new StringBuilder();
638                         // 3) Change any roles with children matching this NS, and
639                         moveRoles(trans, parent, sb, rrdc);
640                         // 4) Change any Perms with children matching this NS, and
641                         movePerms(trans, parent, sb, rpdc);
642                 }
643
644                 if (sb != null && sb.length() > 0) {
645                         return Result.err(Status.ERR_DependencyExists, sb.toString());
646                 }
647
648                 if (er.hasErr()) {
649                         if (trans.debug().isLoggable()) {
650                                 trans.debug().log(er.toString());
651                         }
652                         return Result.err(Status.ERR_DependencyExists,
653                                         "Namespace members cannot be deleted for %s", ns);
654                 }
655
656                 // 5) OK... good to go for NS Deletion...
657                 if (!rpdc.isEmpty()) {
658                         for (PermDAO.Data perm : rpdc.value) {
659                                 deletePerm(trans, perm, true, true);
660                         }
661                 }
662                 if (!rrdc.isEmpty()) {
663                         for (RoleDAO.Data role : rrdc.value) {
664                                 deleteRole(trans, role, true, true);
665                         }
666                 }
667
668                 return q.nsDAO.delete(trans, nsd, false);
669         }
670
671         public Result<List<String>> getOwners(AuthzTrans trans, String ns,
672                         boolean includeExpired) {
673                 return getUsersByRole(trans, ns + Question.DOT_OWNER, includeExpired);
674         }
675
676         private Result<Void> mayAddOwner(AuthzTrans trans, String ns, String id) {
677                 Result<NsDAO.Data> rq = q.deriveNs(trans, ns);
678                 if (rq.notOK()) {
679                         return Result.err(rq);
680                 }
681
682                 rq = q.mayUser(trans, trans.user(), rq.value, Access.write);
683                 if (rq.notOK()) {
684                         return Result.err(rq);
685                 }
686
687                 Identity user;
688                 Organization org = trans.org();
689                 try {
690                         if ((user = org.getIdentity(trans, id)) == null) {
691                                 return Result.err(Status.ERR_Policy,
692                                                 "%s reports that this is not a valid credential",
693                                                 org.getName());
694                         }
695                         String reason;
696                         if ((reason=user.mayOwn())==null) {
697                                 return Result.ok();
698                         } else {
699                                 if (org.isTestEnv()) {
700                                         String reason2;
701                                         if((reason2 = org.validate(trans, Policy.AS_RESPONSIBLE, new CassExecutor(trans, this), id))==null) {
702                                                 return Result.ok();
703                                         } else {
704                                                 trans.debug().log(reason2);
705                                         }
706                                 }
707                                 return Result.err(Status.ERR_Policy,CANNOT_BE_THE_OWNER_OF_A_NAMESPACE,user.fullName(),user.id(),ns, reason);
708                         }
709                 } catch (Exception e) {
710                         return Result.err(e);
711                 }
712         }
713
714         private Result<Void> mayAddAdmin(AuthzTrans trans, String ns,   String id) {
715                 // Does NS Exist?
716                 Result<Void> r = checkValidID(trans, new Date(), id);
717                 if (r.notOK()) {
718                         return r;
719                 }
720                 // Is id able to be an Admin
721                 Result<NsDAO.Data> rq = q.deriveNs(trans, ns);
722                 if (rq.notOK()) {
723                         return Result.err(rq);
724                 }
725         
726                 rq = q.mayUser(trans, trans.user(), rq.value, Access.write);
727                 if (rq.notOK()) {
728                         Result<List<UserRoleDAO.Data>> ruinr = q.userRoleDAO.readUserInRole(trans, trans.user(),ns+".owner");
729                         if(!(ruinr.isOKhasData() && ruinr.value.get(0).expires.after(new Date()))) {
730                                 return Result.err(rq);
731                         }
732                 }
733                 return r;
734         }
735
736         private Result<Void> checkValidID(AuthzTrans trans, Date now, String user) {
737                 Organization org = trans.org();
738                 if (org.supportsRealm(user)) {
739                         try {
740                                 if (org.getIdentity(trans, user) == null) {
741                                         return Result.err(Status.ERR_Denied,
742                                                         "%s reports that %s is a faulty ID", org.getName(),
743                                                         user);
744                                 }
745                                 return Result.ok();
746                         } catch (Exception e) {
747                                 return Result.err(Result.ERR_Security,
748                                                 "%s is not a valid %s Credential", user, org.getName());
749                         }
750                 //TODO find out how to make sure good ALTERNATE OAUTH DOMAIN USER
751 //              } else if(user.endsWith(ALTERNATE OAUTH DOMAIN)) {
752 //                      return Result.ok();
753                 } else {
754                         Result<List<CredDAO.Data>> cdr = q.credDAO.readID(trans, user);
755                         if (cdr.notOKorIsEmpty()) {
756                                 return Result.err(Status.ERR_Security,
757                                                 "%s is not a valid AAF Credential", user);
758                         }
759         
760                         for (CredDAO.Data cd : cdr.value) {
761                                 if (cd.expires.after(now)) {
762                                         return Result.ok();
763                                 }
764                         }
765                 }
766                 return Result.err(Result.ERR_Security, "%s has expired", user);
767         }
768
769         public Result<Void> delOwner(AuthzTrans trans, String ns, String id) {
770                 Result<NsDAO.Data> rq = q.deriveNs(trans, ns);
771                 if (rq.notOK()) {
772                         return Result.err(rq);
773                 }
774
775                 rq = q.mayUser(trans, trans.user(), rq.value, Access.write);
776                 if (rq.notOK()) {
777                         return Result.err(rq);
778                 }
779
780                 return delUserRole(trans, id, ns,Question.OWNER);
781         }
782
783         public Result<List<String>> getAdmins(AuthzTrans trans, String ns, boolean includeExpired) {
784                 return getUsersByRole(trans, ns + Question.DOT_ADMIN, includeExpired);
785         }
786
787         public Result<Void> delAdmin(AuthzTrans trans, String ns, String id) {
788                 Result<NsDAO.Data> rq = q.deriveNs(trans, ns);
789                 if (rq.notOK()) {
790                         return Result.err(rq);
791                 }
792
793                 rq = q.mayUser(trans, trans.user(), rq.value, Access.write);
794                 if (rq.notOK()) { 
795                         // Even though not a "writer", Owners still determine who gets to be an Admin
796                         Result<List<UserRoleDAO.Data>> ruinr = q.userRoleDAO.readUserInRole(trans, trans.user(),ns+".owner");
797                         if(!(ruinr.isOKhasData() && ruinr.value.get(0).expires.after(new Date()))) {
798                                 return Result.err(rq);
799                         }
800                 }
801
802                 return delUserRole(trans, id, ns, Question.ADMIN);
803         }
804
805         /**
806          * Helper function that moves permissions from a namespace being deleted to
807          * its parent namespace
808          * 
809          * @param trans
810          * @param parent
811          * @param sb
812          * @param rpdc
813          *            - list of permissions in namespace being deleted
814          */
815         private void movePerms(AuthzTrans trans, NsDAO.Data parent,
816                         StringBuilder sb, Result<List<PermDAO.Data>> rpdc) {
817
818                 Result<Void> rv;
819                 Result<PermDAO.Data> pd;
820
821                 if (rpdc.isOKhasData()) {
822                         for (PermDAO.Data pdd : rpdc.value) {
823                                 String delP2 = pdd.type;
824                                 if ("access".equals(delP2)) {
825                                     continue;
826                                 }
827                                 // Remove old Perm from Roles, save them off
828                                 List<RoleDAO.Data> lrdd = new ArrayList<>();
829                                 
830                                 for(String rl : pdd.roles(false)) {
831                                         Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,q,rl);
832                                         if(rrdd.isOKhasData()) {
833                                                 RoleDAO.Data rdd = rrdd.value;
834                                                 lrdd.add(rdd);
835                                                 q.roleDAO.delPerm(trans, rdd, pdd);
836                                         } else{
837                                                 trans.error().log(rrdd.errorString());
838                                         }
839                                 }
840                                 
841                                 // Save off Old keys
842                                 String delP1 = pdd.ns;
843                                 NsSplit nss = new NsSplit(parent, pdd.fullType());
844                                 pdd.ns = nss.ns;
845                                 pdd.type = nss.name;
846                                 // Use direct Create/Delete, because switching namespaces
847                                 if ((pd = q.permDAO.create(trans, pdd)).isOK()) {
848                                         // Put Role back into Perm, with correct info
849                                         for(RoleDAO.Data rdd : lrdd) {
850                                                 q.roleDAO.addPerm(trans, rdd, pdd);
851                                         }
852
853                                         pdd.ns = delP1;
854                                         pdd.type = delP2;
855                                         if ((rv = q.permDAO.delete(trans, pdd, false)).notOK()) {
856                                                 sb.append(rv.details);
857                                                 sb.append('\n');
858                                                 // } else {
859                                                 // Need to invalidate directly, because we're switching
860                                                 // places in NS, not normal cache behavior
861                                                 // q.permDAO.invalidate(trans,pdd);
862                                         }
863                                 } else {
864                                         sb.append(pd.details);
865                                         sb.append('\n');
866                                 }
867                         }
868                 }
869         }
870
871         /**
872          * Helper function that moves roles from a namespace being deleted to its
873          * parent namespace
874          * 
875          * @param trans
876          * @param parent
877          * @param sb
878          * @param rrdc
879          *            - list of roles in namespace being deleted
880          */
881         private void moveRoles(AuthzTrans trans, NsDAO.Data parent,
882                         StringBuilder sb, Result<List<RoleDAO.Data>> rrdc) {
883
884                 Result<Void> rv;
885                 Result<RoleDAO.Data> rd;
886
887                 if (rrdc.isOKhasData()) {
888                         for (RoleDAO.Data rdd : rrdc.value) {
889                                 String delP2 = rdd.name;
890                                 if ("admin".equals(delP2) || "owner".equals(delP2)) {
891                                     continue;
892                                 }
893                                 // Remove old Role from Perms, save them off
894                                 List<PermDAO.Data> lpdd = new ArrayList<>();
895                                 for(String p : rdd.perms(false)) {
896                                         Result<PermDAO.Data> rpdd = PermDAO.Data.decode(trans,q,p);
897                                         if(rpdd.isOKhasData()) {
898                                                 PermDAO.Data pdd = rpdd.value;
899                                                 lpdd.add(pdd);
900                                                 q.permDAO.delRole(trans, pdd, rdd);
901                                         } else{
902                                                 trans.error().log(rpdd.errorString());
903                                         }
904                                 }
905                                 
906                                 // Save off Old keys
907                                 String delP1 = rdd.ns;
908
909                                 NsSplit nss = new NsSplit(parent, rdd.fullName());
910                                 rdd.ns = nss.ns;
911                                 rdd.name = nss.name;
912                                 // Use direct Create/Delete, because switching namespaces
913                                 if ((rd = q.roleDAO.create(trans, rdd)).isOK()) {
914                                         // Put Role back into Perm, with correct info
915                                         for(PermDAO.Data pdd : lpdd) {
916                                                 q.permDAO.addRole(trans, pdd, rdd);
917                                         }
918
919                                         rdd.ns = delP1;
920                                         rdd.name = delP2;
921                                         if ((rv = q.roleDAO.delete(trans, rdd, true)).notOK()) {
922                                                 sb.append(rv.details);
923                                                 sb.append('\n');
924                                                 // } else {
925                                                 // Need to invalidate directly, because we're switching
926                                                 // places in NS, not normal cache behavior
927                                                 // q.roleDAO.invalidate(trans,rdd);
928                                         }
929                                 } else {
930                                         sb.append(rd.details);
931                                         sb.append('\n');
932                                 }
933                         }
934                 }
935         }
936
937         /**
938          * Create Permission (and any missing Permission between this and Parent) if
939          * we have permission
940          * 
941          * Pass in the desired Management Permission for this Permission
942          * 
943          * If Force is set, then Roles listed will be created, if allowed,
944          * pre-granted.
945          */
946         public Result<Void> createPerm(AuthzTrans trans, PermDAO.Data perm, boolean fromApproval) {
947                 String user = trans.user();
948                 // Next, see if User is allowed to Manage Parent Permission
949
950                 Result<NsDAO.Data> rnsd;
951                 if (!fromApproval) {
952                         rnsd = q.mayUser(trans, user, perm, Access.write);
953                         if (rnsd.notOK()) {
954                                 return Result.err(rnsd);
955                         }
956                 } else {
957                         rnsd = q.deriveNs(trans, perm.ns);
958                 }
959
960                 // Does Child exist?
961                 if (!trans.requested(REQD_TYPE.force)) {
962                         if (q.permDAO.read(trans, perm).isOKhasData()) {
963                                 return Result.err(Status.ERR_ConflictAlreadyExists,
964                                                 "Permission [%s.%s|%s|%s] already exists.", perm.ns,
965                                                 perm.type, perm.instance, perm.action);
966                         }
967                 }
968
969                 // Attempt to add perms to roles, creating as possible
970                 Set<String> roles;
971                 String pstring = perm.encode();
972
973                 // For each Role
974                 for (String role : roles = perm.roles(true)) {
975                         Result<RoleDAO.Data> rdd = RoleDAO.Data.decode(trans,q,role);
976                         if(rdd.isOKhasData()) {
977                                 RoleDAO.Data rd = rdd.value;
978                                 if (!fromApproval) {
979                                         // May User write to the Role in question.
980                                         Result<NsDAO.Data> rns = q.mayUser(trans, user, rd,
981                                                         Access.write);
982                                         if (rns.notOK()) {
983                                                 // Remove the role from Add, because
984                                                 roles.remove(role); // Don't allow adding
985                                                 trans.warn()
986                                                                 .log("User [%s] does not have permission to relate Permissions to Role [%s]",
987                                                                                 user, role);
988                                         }
989                                 }
990
991                                 Result<List<RoleDAO.Data>> rlrd;
992                                 if ((rlrd = q.roleDAO.read(trans, rd)).notOKorIsEmpty()) {
993                                         rd.perms(true).add(pstring);
994                                         if (q.roleDAO.create(trans, rd).notOK()) {
995                                                 roles.remove(role); // Role doesn't exist, and can't be
996                                                                                         // created
997                                         }
998                                 } else {
999                                         rd = rlrd.value.get(0);
1000                                         if (!rd.perms.contains(pstring)) {
1001                                                 q.roleDAO.addPerm(trans, rd, perm);
1002                                         }
1003                                 }
1004                         }
1005                 }
1006
1007                 Result<PermDAO.Data> pdr = q.permDAO.create(trans, perm);
1008                 if (pdr.isOK()) {
1009                         return Result.ok();
1010                 } else { 
1011                         return Result.err(pdr);
1012                 }
1013         }
1014
1015         public Result<Void> deletePerm(final AuthzTrans trans, final PermDAO.Data perm, boolean force, boolean fromApproval) {
1016                 String user = trans.user();
1017
1018                 // Next, see if User is allowed to Manage Permission
1019                 Result<NsDAO.Data> rnsd;
1020                 if (!fromApproval) {
1021                         rnsd = q.mayUser(trans, user, perm, Access.write);
1022                         if (rnsd.notOK()) {
1023                                 return Result.err(rnsd);
1024                         }
1025                 }
1026                 // Does Perm exist?
1027                 Result<List<PermDAO.Data>> pdr = q.permDAO.read(trans, perm);
1028                 if (pdr.notOKorIsEmpty()) {
1029                         return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist.",
1030                                         perm.ns,perm.type, perm.instance, perm.action);
1031                 }
1032                 // Get perm, but with rest of data.
1033                 PermDAO.Data fullperm = pdr.value.get(0);
1034
1035                 // Attached to any Roles?
1036                 if (fullperm.roles != null) {
1037                         if (force) {
1038                                 for (String role : fullperm.roles) {
1039                                         Result<Void> rv = null;
1040                                         Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, q, role);
1041                                         if(rrdd.isOKhasData()) {
1042                                                 trans.debug().log("Removing", role, "from", fullperm, "on Perm Delete");
1043                                                 if ((rv = q.roleDAO.delPerm(trans, rrdd.value, fullperm)).notOK()) {
1044                                                         if (rv.notOK()) {
1045                                                                 trans.error().log("Error removing Role during delFromPermRole: ",
1046                                                                                                 trans.getUserPrincipal(),
1047                                                                                                 rv.errorString());
1048                                                         }
1049                                                 }
1050                                         } else {
1051                                                 return Result.err(rrdd);
1052                                         }
1053                                 }
1054                         } else if (!fullperm.roles.isEmpty()) {
1055                                 return Result
1056                                                 .err(Status.ERR_DependencyExists,
1057                                                                 "Permission [%s.%s|%s|%s] cannot be deleted as it is attached to 1 or more roles.",
1058                                                                 fullperm.ns, fullperm.type, fullperm.instance, fullperm.action);
1059                         }
1060                 }
1061
1062                 return q.permDAO.delete(trans, fullperm, false);
1063         }
1064
1065         public Result<Void> deleteRole(final AuthzTrans trans, final RoleDAO.Data role, boolean force, boolean fromApproval) {
1066                 String user = trans.user();
1067
1068                 // Next, see if User is allowed to Manage Role
1069                 Result<NsDAO.Data> rnsd;
1070                 if (!fromApproval) {
1071                         rnsd = q.mayUser(trans, user, role, Access.write);
1072                         if (rnsd.notOK()) {
1073                                 return Result.err(rnsd);
1074                         }
1075                 }
1076
1077                 // Are there any Users Attached to Role?
1078                 Result<List<UserRoleDAO.Data>> urdr = q.userRoleDAO.readByRole(trans,role.fullName());
1079                 if (force) {
1080                         if (urdr.isOKhasData()) {
1081                                 for (UserRoleDAO.Data urd : urdr.value) {
1082                                         q.userRoleDAO.delete(trans, urd, false);
1083                                 }
1084                         }
1085                 } else if (urdr.isOKhasData()) {
1086                         return Result.err(Status.ERR_DependencyExists,
1087                                                         "Role [%s.%s] cannot be deleted as it is used by 1 or more Users.",
1088                                                         role.ns, role.name);
1089                 }
1090
1091                 // Does Role exist?
1092                 Result<List<RoleDAO.Data>> rdr = q.roleDAO.read(trans, role);
1093                 if (rdr.notOKorIsEmpty()) {
1094                         return Result.err(Status.ERR_RoleNotFound,
1095                                         "Role [%s.%s] does not exist", role.ns, role.name);
1096                 }
1097                 RoleDAO.Data fullrole = rdr.value.get(0); // full key search
1098
1099                 // Remove Self from Permissions... always, force or not.  Force only applies to Dependencies (Users)
1100                 if (fullrole.perms != null) {
1101                         for (String perm : fullrole.perms(false)) {
1102                                 Result<PermDAO.Data> rpd = PermDAO.Data.decode(trans,q,perm);
1103                                 if (rpd.isOK()) {
1104                                         trans.debug().log("Removing", perm, "from", fullrole,"on Role Delete");
1105
1106                                         Result<?> r = q.permDAO.delRole(trans, rpd.value, fullrole);
1107                                         if (r.notOK()) {
1108                                                 trans.error().log("ERR_FDR1 unable to remove",fullrole,"from",perm,':',r.status,'-',r.details);
1109                                         }
1110                                 } else {
1111                                         trans.error().log("ERR_FDR2 Could not remove",perm,"from",fullrole);
1112                                 }
1113                         }
1114                 }
1115                 return q.roleDAO.delete(trans, fullrole, false);
1116         }
1117
1118         /**
1119          * Only owner of Permission may add to Role
1120          * 
1121          * If force set, however, Role will be created before Grant, if User is
1122          * allowed to create.
1123          * 
1124          * @param trans
1125          * @param role
1126          * @param pd
1127          * @return
1128          */
1129         public Result<Void> addPermToRole(AuthzTrans trans, RoleDAO.Data role,PermDAO.Data pd, boolean fromApproval) {
1130                 String user = trans.user();
1131                 
1132                 if (!fromApproval) {
1133                         Result<NsDAO.Data> rRoleCo = q.deriveFirstNsForType(trans, role.ns, NsType.COMPANY);
1134                         if(rRoleCo.notOK()) {
1135                                 return Result.err(rRoleCo);
1136                         }
1137                         Result<NsDAO.Data> rPermCo = q.deriveFirstNsForType(trans, pd.ns, NsType.COMPANY);
1138                         if(rPermCo.notOK()) {
1139                                 return Result.err(rPermCo);
1140                         }
1141
1142                         // Not from same company
1143                         if(!rRoleCo.value.name.equals(rPermCo.value.name)) {
1144                                 Result<Data> r;
1145                                 // Only grant if User ALSO has Write ability in Other Company
1146                                 if((r = q.mayUser(trans, user, role, Access.write)).notOK()) {
1147                                         return Result.err(r);
1148                                 }
1149                         }
1150                         
1151
1152                         // Must be Perm Admin, or Granted Special Permission
1153                         Result<NsDAO.Data> ucp = q.mayUser(trans, user, pd, Access.write);
1154                         if (ucp.notOK()) {
1155                                 // Don't allow CLI potential Grantees to change their own AAF
1156                                 // Perms,
1157                                 if ((ROOT_NS.equals(pd.ns) && Question.NS.equals(pd.type)) 
1158                                                 || !q.isGranted(trans, trans.user(),ROOT_NS,Question.PERM, rPermCo.value.name, "grant")) {
1159                                 // Not otherwise granted
1160                                 // TODO Needed?
1161                                         return Result.err(ucp);
1162                                 }
1163                                 // Final Check... Don't allow Grantees to add to Roles they are
1164                                 // part of
1165                                 Result<List<UserRoleDAO.Data>> rlurd = q.userRoleDAO
1166                                                 .readByUser(trans, trans.user());
1167                                 if (rlurd.isOK()) {
1168                                         for (UserRoleDAO.Data ur : rlurd.value) {
1169                                                 if (role.ns.equals(ur.ns) && role.name.equals(ur.rname)) {
1170                                                         return Result.err(ucp);
1171                                                 }
1172                                         }
1173                                 }
1174                         }
1175                 }
1176
1177                 Result<List<PermDAO.Data>> rlpd = q.permDAO.read(trans, pd);
1178                 if (rlpd.notOKorIsEmpty()) {
1179                         return Result.err(Status.ERR_PermissionNotFound,
1180                                         "Permission must exist to add to Role");
1181                 }
1182
1183                 Result<List<RoleDAO.Data>> rlrd = q.roleDAO.read(trans, role); // Already
1184                                                                                                                                                 // Checked
1185                                                                                                                                                 // for
1186                                                                                                                                                 // can
1187                                                                                                                                                 // change
1188                                                                                                                                                 // Role
1189                 Result<Void> rv;
1190
1191                 if (rlrd.notOKorIsEmpty()) {
1192                         if (trans.requested(REQD_TYPE.force)) {
1193                                 Result<NsDAO.Data> ucr = q.mayUser(trans, user, role,
1194                                                 Access.write);
1195                                 if (ucr.notOK()) {
1196                                     return Result
1197                                                 .err(Status.ERR_Denied,
1198                                                                 "Role [%s.%s] does not exist. User [%s] cannot create.",
1199                                                                 role.ns, role.name, user);
1200                                 }
1201
1202                                 role.perms(true).add(pd.encode());
1203                                 Result<RoleDAO.Data> rdd = q.roleDAO.create(trans, role);
1204                                 if (rdd.isOK()) {
1205                                         rv = Result.ok();
1206                                 } else {
1207                                         rv = Result.err(rdd);
1208                                 }
1209                         } else {
1210                             return Result.err(Status.ERR_RoleNotFound,
1211                                         "Role [%s.%s] does not exist.", role.ns, role.name);
1212                         }
1213                 } else {
1214                         role = rlrd.value.get(0);
1215                         if (role.perms(false).contains(pd.encode())) {
1216                                 return Result.err(Status.ERR_ConflictAlreadyExists,
1217                                                                 "Permission [%s.%s] is already a member of role [%s,%s]",
1218                                                                 pd.ns, pd.type, role.ns, role.name);
1219                         }
1220                         role.perms(true).add(pd.encode()); // this is added for Caching
1221                                                                                                 // access purposes... doesn't
1222                                                                                                 // affect addPerm
1223                         rv = q.roleDAO.addPerm(trans, role, pd);
1224                 }
1225                 if (rv.status == Status.OK) {
1226                         return q.permDAO.addRole(trans, pd, role);
1227                         // exploring how to add information message to successful http
1228                         // request
1229                 }
1230                 return rv;
1231         }
1232
1233         /**
1234          * Either Owner of Role or Permission may delete from Role
1235          * 
1236          * @param trans
1237          * @param role
1238          * @param pd
1239          * @return
1240          */
1241         public Result<Void> delPermFromRole(AuthzTrans trans, RoleDAO.Data role,PermDAO.Data pd, boolean fromApproval) {
1242                 String user = trans.user();
1243                 if (!fromApproval) {
1244                         Result<NsDAO.Data> ucr = q.mayUser(trans, user, role, Access.write);
1245                         Result<NsDAO.Data> ucp = q.mayUser(trans, user, pd, Access.write);
1246
1247                         // If Can't change either Role or Perm, then deny
1248                         if (ucr.notOK() && ucp.notOK()) {
1249                                 return Result.err(Status.ERR_Denied,
1250                                                 "User [" + trans.user()
1251                                                                 + "] does not have permission to delete ["
1252                                                                 + pd.encode() + "] from Role ["
1253                                                                 + role.fullName() + ']');
1254                         }
1255                 }
1256
1257                 Result<List<RoleDAO.Data>> rlr = q.roleDAO.read(trans, role);
1258                 if (rlr.notOKorIsEmpty()) {
1259                         // If Bad Data, clean out
1260                         Result<List<PermDAO.Data>> rlp = q.permDAO.read(trans, pd);
1261                         if (rlp.isOKhasData()) {
1262                                 for (PermDAO.Data pv : rlp.value) {
1263                                         q.permDAO.delRole(trans, pv, role);
1264                                 }
1265                         }
1266                         return Result.err(rlr);
1267                 }
1268                 String perm1 = pd.encode();
1269                 boolean notFound;
1270                 if (trans.requested(REQD_TYPE.force)) {
1271                         notFound = false;
1272                 } else { // only check if force not set.
1273                         notFound = true;
1274                         for (RoleDAO.Data r : rlr.value) {
1275                                 if (r.perms != null) {
1276                                         for (String perm : r.perms) {
1277                                                 if (perm1.equals(perm)) {
1278                                                         notFound = false;
1279                                                         break;
1280                                                 }
1281                                         }
1282                                         if(!notFound) {
1283                                                 break;
1284                                         }
1285                                 }
1286                         }
1287                 }
1288                 if (notFound) { // Need to check both, in case of corruption
1289                         return Result.err(Status.ERR_PermissionNotFound,
1290                                         "Permission [%s.%s|%s|%s] not associated with any Role",
1291                                         pd.ns,pd.type,pd.instance,pd.action);
1292                 }
1293
1294                 // Read Perm for full data
1295                 Result<List<PermDAO.Data>> rlp = q.permDAO.read(trans, pd);
1296                 Result<Void> rv = null;
1297                 if (rlp.isOKhasData()) {
1298                         for (PermDAO.Data pv : rlp.value) {
1299                                 if ((rv = q.permDAO.delRole(trans, pv, role)).isOK()) {
1300                                         if ((rv = q.roleDAO.delPerm(trans, role, pv)).notOK()) {
1301                                                 trans.error().log(
1302                                                                 "Error removing Perm during delFromPermRole:",
1303                                                                 trans.getUserPrincipal(), rv.errorString());
1304                                         }
1305                                 } else {
1306                                         trans.error().log(
1307                                                         "Error removing Role during delFromPermRole:",
1308                                                         trans.getUserPrincipal(), rv.errorString());
1309                                 }
1310                         }
1311                 } else {
1312                         rv = q.roleDAO.delPerm(trans, role, pd);
1313                         if (rv.notOK()) {
1314                                 trans.error().log("Error removing Role during delFromPermRole",
1315                                                 rv.errorString());
1316                         }
1317                 }
1318                 return rv == null ? Result.ok() : rv;
1319         }
1320
1321         public Result<Void> delPermFromRole(AuthzTrans trans, String role,PermDAO.Data pd) {
1322                 Result<NsSplit> nss = q.deriveNsSplit(trans, role);
1323                 if (nss.notOK()) {
1324                         return Result.err(nss);
1325                 }
1326                 RoleDAO.Data rd = new RoleDAO.Data();
1327                 rd.ns = nss.value.ns;
1328                 rd.name = nss.value.name;
1329                 return delPermFromRole(trans, rd, pd, false);
1330         }
1331
1332         /**
1333          * Add a User to Role
1334          * 
1335          * 1) Role must exist 2) User must be a known Credential (i.e. mechID ok if
1336          * Credential) or known Organizational User
1337          * 
1338          * @param trans
1339          * @param org
1340          * @param urData
1341          * @return
1342          * @throws DAOException
1343          */
1344         public Result<Void> addUserRole(AuthzTrans trans,UserRoleDAO.Data urData) {
1345                 Result<Void> rv;
1346                 if(Question.ADMIN.equals(urData.rname)) {
1347                         rv = mayAddAdmin(trans, urData.ns, urData.user);
1348                 } else if(Question.OWNER.equals(urData.rname)) {
1349                         rv = mayAddOwner(trans, urData.ns, urData.user);
1350                 } else {
1351                         rv = checkValidID(trans, new Date(), urData.user);
1352                 }
1353                 if(rv.notOK()) {
1354                         return rv; 
1355                 }
1356                 
1357                 // Check if record exists
1358                 if (q.userRoleDAO.read(trans, urData).isOKhasData()) {
1359                         return Result.err(Status.ERR_ConflictAlreadyExists,
1360                                         "User Role exists");
1361                 }
1362                 if (q.roleDAO.read(trans, urData.ns, urData.rname).notOKorIsEmpty()) {
1363                         return Result.err(Status.ERR_RoleNotFound,
1364                                         "Role [%s.%s] does not exist", urData.ns, urData.rname);
1365                 }
1366
1367                 urData.expires = trans.org().expiration(null, Expiration.UserInRole, urData.user).getTime();
1368                 
1369                 
1370                 Result<UserRoleDAO.Data> udr = q.userRoleDAO.create(trans, urData);
1371                 switch (udr.status) {
1372                 case OK:
1373                         return Result.ok();
1374                 default:
1375                         return Result.err(udr);
1376                 }
1377         }
1378
1379         public Result<Void> addUserRole(AuthzTrans trans, String user, String ns, String rname) {
1380                 try {
1381                         if(trans.org().getIdentity(trans, user)==null) {
1382                                 return Result.err(Result.ERR_BadData,user+" is an Invalid Identity for " + trans.org().getName());
1383                         }
1384                 } catch (OrganizationException e) {
1385                         return Result.err(e);
1386                 }
1387                 UserRoleDAO.Data urdd = new UserRoleDAO.Data();
1388                 urdd.ns = ns;
1389                 urdd.role(ns, rname);
1390                 urdd.user = user;
1391                 return addUserRole(trans,urdd);
1392         }
1393
1394         /**
1395          * Extend User Role.
1396          * 
1397          * extend the Expiration data, according to Organization rules.
1398          * 
1399          * @param trans
1400          * @param org
1401          * @param urData
1402          * @return
1403          */
1404         public Result<Void> extendUserRole(AuthzTrans trans, UserRoleDAO.Data urData, boolean checkForExist) {
1405                 // Check if record still exists
1406                 if (checkForExist && q.userRoleDAO.read(trans, urData).notOKorIsEmpty()) {
1407                         return Result.err(Status.ERR_UserRoleNotFound,
1408                                         "User Role does not exist");
1409                 }
1410                 
1411                 if (q.roleDAO.read(trans, urData.ns, urData.rname).notOKorIsEmpty()) {
1412                         return Result.err(Status.ERR_RoleNotFound,
1413                                         "Role [%s.%s] does not exist", urData.ns,urData.rname);
1414                 }
1415                 // Special case for "Admin" roles. Issue brought forward with Prod
1416                 // problem 9/26
1417                 Date now = new Date();
1418                 GregorianCalendar gc = new GregorianCalendar();
1419                 gc.setTime(now.after(urData.expires)?now:urData.expires);
1420                 urData.expires = trans.org().expiration(gc, Expiration.UserInRole).getTime(); // get
1421                                                                                                                                                                 // Full
1422                                                                                                                                                                 // time
1423                                                                                                                                                                 // starting
1424                                                                                                                                                                 // today
1425                 return q.userRoleDAO.update(trans, urData);
1426         }
1427
1428         // ////////////////////////////////////////////////////
1429         // Special User Role Functions
1430         // These exist, because User Roles have Expiration dates, which must be
1431         // accounted for
1432         // Also, as of July, 2015, Namespace Owners and Admins are now regular User
1433         // Roles
1434         // ////////////////////////////////////////////////////
1435         public Result<List<String>> getUsersByRole(AuthzTrans trans, String role, boolean includeExpired) {
1436                 Result<List<UserRoleDAO.Data>> rurdd = q.userRoleDAO.readByRole(trans,role);
1437                 if (rurdd.notOK()) {
1438                         return Result.err(rurdd);
1439                 }
1440                 Date now = new Date();
1441                 List<UserRoleDAO.Data> list = rurdd.value;
1442                 List<String> rv = new ArrayList<>(list.size()); // presize
1443                 for (UserRoleDAO.Data urdd : rurdd.value) {
1444                         if (includeExpired || urdd.expires.after(now)) {
1445                                 rv.add(urdd.user);
1446                         }
1447                 }
1448                 return Result.ok(rv);
1449         }
1450
1451         public Result<Void> delUserRole(AuthzTrans trans, String user, String ns, String rname) {
1452                 UserRoleDAO.Data urdd = new UserRoleDAO.Data();
1453                 urdd.user = user;
1454                 urdd.role(ns,rname);
1455                 Result<List<UserRoleDAO.Data>> r = q.userRoleDAO.read(trans, urdd);
1456                 if (r.status == 404 || r.isEmpty()) {
1457                         return Result.err(Status.ERR_UserRoleNotFound,
1458                                         "UserRole [%s] [%s.%s]", user, ns, rname);
1459                 }
1460                 if (r.notOK()) {
1461                         return Result.err(r);
1462                 }
1463
1464                 return q.userRoleDAO.delete(trans, urdd, false);
1465         }
1466
1467         public Result<String> createFuture(AuthzTrans trans, FutureDAO.Data data, String id, String user,
1468                         NsDAO.Data nsd, FUTURE_OP op) {
1469                 StringBuilder sb = new StringBuilder();
1470                 try {
1471                         Organization org = trans.org();
1472                         // For Reapproval, only check Owners.. Do Supervisors, etc, separately
1473                         List<Identity> approvers = op.equals(FUTURE_OP.A)?NO_ADDL_APPROVE:org.getApprovers(trans, user);
1474                         List<Identity> owners = new ArrayList<>();
1475                         if (nsd != null) {
1476                                 Result<List<UserRoleDAO.Data>> rrbr = q.userRoleDAO
1477                                                 .readByRole(trans, nsd.name + Question.DOT_OWNER);
1478                                 if (rrbr.isOKhasData()) {
1479                                         for(UserRoleDAO.Data urd : rrbr.value) {
1480                                                 Identity owner = org.getIdentity(trans, urd.user);
1481                                                 if(owner==null) {
1482                                                         return Result.err(Result.ERR_NotFound,urd.user + " is not a Valid Owner of " + nsd.name);
1483                                                 } else {
1484                                                         owners.add(owner);
1485                                                 }
1486                                         }
1487                                 }
1488                         }
1489                         
1490                         if(owners.isEmpty()) {
1491                                 return Result.err(Result.ERR_NotFound,"No Owners found for " + nsd.name);
1492                         }
1493                         
1494                         // Create Future Object
1495                         
1496                         Result<FutureDAO.Data> fr = q.futureDAO.create(trans, data, id);
1497                         if (fr.isOK()) {
1498                                 sb.append("Created Future: ");
1499                                 sb.append(data.id);
1500                                 // User Future ID as ticket for Approvals
1501                                 final UUID ticket = fr.value.id;
1502                                 sb.append(", Approvals: ");
1503                                 Boolean first[] = new Boolean[]{true};
1504                                 if(op!=FUTURE_OP.A) {
1505                                         for (Identity u : approvers) {
1506                                                 Result<ApprovalDAO.Data> r = addIdentity(trans,sb,first,user,data.memo,op,u,ticket,org.getApproverType());
1507                                                 if(r.notOK()) {
1508                                                         return Result.err(r);
1509                                                 }
1510                                         }
1511                                 }
1512                                 for (Identity u : owners) {
1513                                         Result<ApprovalDAO.Data> r = addIdentity(trans,sb,first,user,data.memo,op,u,ticket,"owner");
1514                                         if(r.notOK()) {
1515                                                 return Result.err(r);
1516                                         }
1517                                 }
1518                         }
1519                 } catch (Exception e) {
1520                         return Result.err(e);
1521                 }
1522                 
1523                 return Result.ok(sb.toString());
1524         }
1525
1526         /*
1527          * This interface is to allow performFutureOps with either Realtime Data, or Batched lookups (See Expiring)
1528          */
1529         public interface Lookup<T> {
1530                 T get(AuthzTrans trans, Object ... keys);
1531         }
1532         
1533         public Lookup<UserRoleDAO.Data> urDBLookup = new Lookup<UserRoleDAO.Data>() {
1534                 @Override
1535                 public UserRoleDAO.Data get(AuthzTrans trans, Object ... keys) {
1536                         Result<List<UserRoleDAO.Data>> r = q.userRoleDAO.read(trans, keys);
1537                         if(r.isOKhasData()) {
1538                                 return r.value.get(0);
1539                         } else {
1540                                 return null;
1541                         }
1542                 }
1543         };
1544
1545         /**
1546          * Note: if "allApprovals for Ticket is null, it will be looked up.  
1547          *       if "fdd" is null, it will be looked up, but
1548          *       
1549          * They can be passed for performance reasons.
1550          * 
1551          * @param trans
1552          * @param cd
1553          * @param allApprovalsForTicket
1554          * @return
1555          */
1556         public Result<OP_STATUS> performFutureOp(final AuthzTrans trans, FUTURE_OP fop, FutureDAO.Data curr, Lookup<List<ApprovalDAO.Data>> la, Lookup<UserRoleDAO.Data> lur) {
1557                 // Pre-Evaluate if ReApproval is already done.
1558                 UserRoleDAO.Data urdd = null;
1559                 if(fop.equals(FUTURE_OP.A) && curr.target.equals(FOP_USER_ROLE) && curr.construct!=null) {
1560                         try {
1561                                 // Get Expected UserRole from Future
1562                                 urdd = new UserRoleDAO.Data();
1563                                 urdd.reconstitute(curr.construct);
1564                                 // Get Current UserRole from lookup
1565                                 UserRoleDAO.Data lurdd = lur.get(trans, urdd.user,urdd.role);
1566                                 if(lurdd==null) {
1567                                         q.futureDAO.delete(trans, curr, false);
1568                                         return OP_STATUS.RL;
1569                                 } else {
1570                                         if(curr.expires.compareTo(lurdd.expires)<0) {
1571                                                 q.futureDAO.delete(trans, curr, false);
1572                                                 return OP_STATUS.RL;
1573                                         }
1574                                 }
1575                         } catch (IOException e) {
1576                                 return Result.err(Result.ERR_BadData,"Cannot reconstitute %1",curr.memo);
1577                         }
1578                 }
1579                 
1580                 boolean aDenial = false;
1581                 int cntSuper=0, appSuper=0,cntOwner=0, appOwner=0;
1582                 for(ApprovalDAO.Data add : la.get(trans)) {
1583                         switch(add.status) {
1584                                 case "approved":
1585                                         if("owner".equals(add.type)) {
1586                                                 ++cntOwner;
1587                                                 ++appOwner;
1588                                         } else if("supervisor".equals(add.type)) {
1589                                                 ++cntSuper;
1590                                                 ++appSuper;
1591                                         }
1592                                         break;
1593                                 case "pending":
1594                                         if("owner".equals(add.type)) {
1595                                                 ++cntOwner;
1596                                         } else if("supervisor".equals(add.type)) {
1597                                                 ++cntSuper;
1598                                         }
1599                                         break;
1600                                 case "denied":
1601                                         aDenial=true;
1602                                         break;
1603                         }
1604                 }
1605                 
1606                 Result<OP_STATUS> ros=null;
1607                 if(aDenial) {
1608                         // Note: Denial will be Audit-logged.
1609 //                      for (ApprovalDAO.Data ad : allApprovalsForTicket.value) {
1610 //                          q.approvalDAO.delete(trans, ad, false);
1611 //                      }
1612                         ros = OP_STATUS.RD;
1613                         if(q.futureDAO.delete(trans, curr, false).notOK()) {
1614                                 trans.info().printf("Future %s could not be deleted", curr.id.toString());
1615                         }  else {
1616                                 if (FOP_USER_ROLE.equalsIgnoreCase(curr.target)) {
1617                                         // A Denial means we must remove UserRole
1618                                         if(fop.equals(FUTURE_OP.U) || fop.equals(FUTURE_OP.A)) {
1619                                                 UserRoleDAO.Data data = new UserRoleDAO.Data();
1620                                                 try {
1621                                                         data.reconstitute(curr.construct);
1622                                                 } catch (IOException e) {
1623                                                         trans.error().log("Cannot reconstitue",curr.memo);
1624                                                 }
1625                                                 ros = set(OP_STATUS.RD,delUserRole(trans, data.user, data.ns, data.rname));
1626                                         }
1627                                 }
1628                         }
1629                 }
1630                 
1631                 // Decision: If not Denied, and at least owner, if exists, and at least one Super, if exists
1632                 boolean goDecision = (cntOwner>0?appOwner>0:true) && (cntSuper>0?appSuper>0:true);
1633
1634                 if(goDecision) {
1635                         // should check if any other pendings before performing
1636                         // actions
1637                         try {
1638                                 if (FOP_ROLE.equalsIgnoreCase(curr.target)) {
1639                                         RoleDAO.Data data = new RoleDAO.Data();
1640                                         data.reconstitute(curr.construct);
1641                                         switch(fop) {
1642                                                 case C:
1643                                                         ros = set(OP_STATUS.RE,q.roleDAO.dao().create(trans, data));
1644                                                         break;
1645                                                 case D:
1646                                                         ros = set(OP_STATUS.RE,deleteRole(trans, data, true, true));
1647                                                         break;
1648                                                 default:
1649                                         }
1650                                 } else if (FOP_PERM.equalsIgnoreCase(curr.target)) {
1651                                         PermDAO.Data pdd = new PermDAO.Data();
1652                                         pdd.reconstitute(curr.construct);
1653                                         Set<String> roles;
1654                                         Result<RoleDAO.Data> rrdd;
1655                                         switch(fop) {
1656                                                 case C:
1657                                                         ros = set(OP_STATUS.RE,createPerm(trans, pdd, true));
1658                                                         break;
1659                                                 case D:
1660                                                         ros = set(OP_STATUS.RE,deletePerm(trans, pdd, true, true));
1661                                                         break;
1662                                                 case G:
1663                                                         roles = pdd.roles(true);
1664                                                         for (String roleStr : roles) {
1665                                                                 rrdd = RoleDAO.Data.decode(trans, q, roleStr);
1666                                                                 if (rrdd.isOKhasData()) {
1667                                                                         ros = set(OP_STATUS.RE,addPermToRole(trans, rrdd.value, pdd, true));
1668                                                                 } else {
1669                                                                         trans.error().log(rrdd.errorString());
1670                                                                 }
1671                                                         }
1672                                                         break;
1673                                                 case UG:
1674                                                         roles = pdd.roles(true);
1675                                                         for (String roleStr : roles) {
1676                                                                 rrdd = RoleDAO.Data.decode(trans, q, roleStr);
1677                                                                 if (rrdd.isOKhasData()) {
1678                                                                         ros = set(OP_STATUS.RE,delPermFromRole(trans, rrdd.value, pdd,  true));
1679                                                                 } else {
1680                                                                         trans.error().log(rrdd.errorString());
1681                                                                 }
1682                                                         }
1683                                                         break;
1684                                                 default:
1685                                         }
1686                                 } else if (FOP_USER_ROLE.equalsIgnoreCase(curr.target)) {
1687                                         if(urdd==null) {
1688                                                 urdd = new UserRoleDAO.Data();
1689                                                 urdd.reconstitute(curr.construct);
1690                                         }
1691                                         // if I am the last to approve, create user role
1692                                         switch(fop) {
1693                                                 case C:
1694                                                         ros = set(OP_STATUS.RE,addUserRole(trans, urdd));
1695                                                         break;
1696                                                 case U:
1697                                                 case A:
1698                                                         ros = set(OP_STATUS.RE,extendUserRole(trans,urdd,true));
1699                                                         break;
1700                                                 default:
1701                                         }
1702                                 } else if (FOP_NS.equalsIgnoreCase(curr.target)) {
1703                                         Namespace namespace = new Namespace();
1704                                         namespace.reconstitute(curr.construct);
1705                                         switch(fop) {
1706                                                 case C:
1707                                                         ros = set(OP_STATUS.RE,createNS(trans, namespace, true));
1708                                                         break;
1709                                                 default:
1710                                         }
1711                                 } else if (FOP_DELEGATE.equalsIgnoreCase(curr.target)) {
1712                                         DelegateDAO.Data data = new DelegateDAO.Data();
1713                                         data.reconstitute(curr.construct);
1714                                         switch(fop) {
1715                                                 case C:
1716                                                         ros = set(OP_STATUS.RE,q.delegateDAO.create(trans, data));
1717                                                         break;
1718                                                 case U:
1719                                                         ros = set(OP_STATUS.RE,q.delegateDAO.update(trans, data));
1720                                                         break;
1721                                                 default:
1722                                         }
1723                                 } else if (FOP_CRED.equalsIgnoreCase(curr.target)) {
1724                                         CredDAO.Data data = new CredDAO.Data();
1725                                         data.reconstitute(curr.construct);
1726                                         switch(fop) {
1727                                                 case C:
1728                                                         ros = set(OP_STATUS.RE,q.credDAO.dao().create(trans, data));
1729                                                         break;
1730                                                 default:
1731                                         }
1732                                 }                               
1733                         } catch (Throwable e) {
1734                                 trans.error().log("Exception: ", e.getMessage(),
1735                                         " \n occurred while performing", curr.memo,
1736                                         " from Ticket ", curr.id.toString());
1737                         }
1738                         q.futureDAO.delete(trans, curr, false);
1739                 } // end for goDecision
1740                 if(ros==null) {
1741                         //return Result.err(Status.ACC_Future, "Full Approvals not obtained: No action taken");
1742                         ros = OP_STATUS.RP;
1743                 }
1744                         
1745                 return ros;
1746         }
1747
1748         // Convenience method for setting OPSTatus Results
1749         private Result<OP_STATUS> set(Result<OP_STATUS> rs, Result<?> orig) {
1750                 if(orig.isOK()) {
1751                         return rs;
1752                 } else {
1753                         return Result.err(orig);
1754                 }
1755         }
1756
1757         private Result<ApprovalDAO.Data>  addIdentity(AuthzTrans trans, StringBuilder sb, 
1758                                                 Boolean[] first, String user, String memo, FUTURE_OP op, Identity u, UUID ticket, String type) throws OrganizationException {
1759                 ApprovalDAO.Data ad = new ApprovalDAO.Data();
1760                 // Note ad.id is set by ApprovalDAO Create
1761                 ad.ticket = ticket;
1762                 ad.user = user;
1763                 ad.approver = u.fullID();
1764                 ad.status = ApprovalDAO.PENDING;
1765                 ad.memo = memo;
1766                 ad.type = type;
1767                 ad.operation = op.name();
1768                 // Note ad.updated is created in System
1769             Result<ApprovalDAO.Data> r = q.approvalDAO.create(trans,ad);
1770             if(r.isOK()) {
1771                         if(first[0]) {
1772                                 first[0] = false;
1773                         } else {
1774                                 sb.append(", ");
1775                         }
1776                         sb.append(r.value.user);
1777                         sb.append(':');
1778                         sb.append(r.value.ticket);
1779                         return r;
1780             } else {
1781                 return Result.err(Status.ERR_ActionNotCompleted,
1782                                         "Approval for %s, %s could not be created: %s",
1783                                         ad.user, ad.approver,
1784                                         r.details, sb.toString());
1785             }
1786         }
1787
1788         public Executor newExecutor(AuthzTrans trans) {
1789                 return new CassExecutor(trans, this);
1790         }
1791
1792 }