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