2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6 * ===========================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END====================================================
22 package org.onap.aaf.auth.service;
24 import static org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE.force;
25 import static org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE.future;
26 import static org.onap.aaf.auth.layer.Result.OK;
27 import static org.onap.aaf.auth.rserv.HttpMethods.DELETE;
28 import static org.onap.aaf.auth.rserv.HttpMethods.GET;
29 import static org.onap.aaf.auth.rserv.HttpMethods.POST;
30 import static org.onap.aaf.auth.rserv.HttpMethods.PUT;
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.Comparator;
37 import java.util.Date;
38 import java.util.GregorianCalendar;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.List;
44 import java.util.TreeMap;
45 import java.util.UUID;
47 import javax.servlet.http.HttpServletRequest;
49 import org.onap.aaf.auth.common.Define;
50 import org.onap.aaf.auth.dao.DAOException;
51 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
52 import org.onap.aaf.auth.dao.cass.CertDAO;
53 import org.onap.aaf.auth.dao.cass.CredDAO;
54 import org.onap.aaf.auth.dao.cass.DelegateDAO;
55 import org.onap.aaf.auth.dao.cass.FutureDAO;
56 import org.onap.aaf.auth.dao.cass.HistoryDAO;
57 import org.onap.aaf.auth.dao.cass.Namespace;
58 import org.onap.aaf.auth.dao.cass.NsDAO;
59 import org.onap.aaf.auth.dao.cass.NsDAO.Data;
60 import org.onap.aaf.auth.dao.cass.NsSplit;
61 import org.onap.aaf.auth.dao.cass.NsType;
62 import org.onap.aaf.auth.dao.cass.PermDAO;
63 import org.onap.aaf.auth.dao.cass.RoleDAO;
64 import org.onap.aaf.auth.dao.cass.Status;
65 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
66 import org.onap.aaf.auth.dao.hl.CassExecutor;
67 import org.onap.aaf.auth.dao.hl.Function;
68 import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP;
69 import org.onap.aaf.auth.dao.hl.Function.Lookup;
70 import org.onap.aaf.auth.dao.hl.Function.OP_STATUS;
71 import org.onap.aaf.auth.dao.hl.Question;
72 import org.onap.aaf.auth.dao.hl.Question.Access;
73 import org.onap.aaf.auth.env.AuthzTrans;
74 import org.onap.aaf.auth.layer.Result;
75 import org.onap.aaf.auth.org.Executor;
76 import org.onap.aaf.auth.org.Organization;
77 import org.onap.aaf.auth.org.Organization.Expiration;
78 import org.onap.aaf.auth.org.Organization.Identity;
79 import org.onap.aaf.auth.org.Organization.Policy;
80 import org.onap.aaf.auth.org.OrganizationException;
81 import org.onap.aaf.auth.rserv.doc.ApiDoc;
82 import org.onap.aaf.auth.service.mapper.Mapper;
83 import org.onap.aaf.auth.service.mapper.Mapper.API;
84 import org.onap.aaf.auth.service.validation.ServiceValidator;
85 import org.onap.aaf.auth.validation.Validator;
86 import org.onap.aaf.cadi.principal.BasicPrincipal;
87 import org.onap.aaf.misc.env.Env;
88 import org.onap.aaf.misc.env.TimeTaken;
89 import org.onap.aaf.misc.env.util.Chrono;
90 import org.onap.aaf.misc.env.util.Split;
92 import aaf.v2_0.CredRequest;
95 * AuthzCassServiceImpl implements AuthzCassService for
110 public class AuthzCassServiceImpl <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS>
111 implements AuthzService <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> {
113 private Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
115 public Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper() {return mapper;}
117 private static final String ASTERIX = "*";
118 private static final String CACHE = "cache";
119 private static final String ROOT_NS = Define.ROOT_NS();
120 private static final String ROOT_COMPANY = Define.ROOT_COMPANY();
122 private final Question ques;
123 private final Function func;
125 public AuthzCassServiceImpl(AuthzTrans trans, Mapper<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper,Question question) {
126 this.ques = question;
127 func = new Function(trans, question);
128 this.mapper = mapper;
132 /***********************************
134 ***********************************/
137 * @throws DAOException
138 * @see org.onap.aaf.auth.service.AuthzService#createNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
145 errorCodes = { 403,404,406,409 },
146 text = { "Namespace consists of: ",
147 "<ul><li>name - What you want to call this Namespace</li>",
148 "<li>responsible(s) - Person(s) who receive Notifications and approves Requests ",
149 "regarding this Namespace. Companies have Policies as to who may take on ",
150 "this Responsibility. Separate multiple identities with commas</li>",
151 "<li>admin(s) - Person(s) who are allowed to make changes on the namespace, ",
152 "including creating Roles, Permissions and Credentials. Separate multiple ",
153 "identities with commas</li></ul>",
154 "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ",
155 "created with parent credentials (i.e. To create com.myCompany.myApp, you must ",
156 "be an admin of com.myCompany or com"
160 public Result<Void> createNS(final AuthzTrans trans, REQUEST from, NsType type) {
161 final Result<Namespace> rnamespace = mapper.ns(trans, from);
162 final ServiceValidator v = new ServiceValidator();
163 if(v.ns(rnamespace).err()) {
164 return Result.err(Status.ERR_BadData,v.errs());
166 final Namespace namespace = rnamespace.value;
167 final Result<NsDAO.Data> parentNs = ques.deriveNs(trans,namespace.name);
168 if(parentNs.notOK()) {
169 return Result.err(parentNs);
172 if(namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed
173 return func.createNS(trans, namespace, false);
176 Result<FutureDAO.Data> fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true,
179 public String get() {
180 return "Create Namespace [" + namespace.name + ']';
184 private Result<NsDAO.Data> rnd;
186 public Result<?> mayChange() {
188 rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write);
195 Result<String> rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C);
197 return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name);
199 return Result.err(rfc);
202 return func.createNS(trans, namespace, false);
204 return Result.err(fd);
210 path = "/authz/ns/:ns/admin/:id",
211 params = { "ns|string|true",
215 errorCodes = { 403,404,406,409 },
216 text = { "Add an Identity :id to the list of Admins for the Namespace :ns",
217 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
220 public Result<Void> addAdminNS(AuthzTrans trans, String ns, String id) {
221 return func.addUserRole(trans, id, ns,Question.ADMIN);
226 path = "/authz/ns/:ns/admin/:id",
227 params = { "ns|string|true",
231 errorCodes = { 403,404 },
232 text = { "Remove an Identity :id from the list of Admins for the Namespace :ns",
233 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
236 public Result<Void> delAdminNS(AuthzTrans trans, String ns, String id) {
237 return func.delAdmin(trans,ns,id);
242 path = "/authz/ns/:ns/responsible/:id",
243 params = { "ns|string|true",
247 errorCodes = { 403,404,406,409 },
248 text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns",
249 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
252 public Result<Void> addResponsibleNS(AuthzTrans trans, String ns, String id) {
253 return func.addUserRole(trans,id,ns,Question.OWNER);
258 path = "/authz/ns/:ns/responsible/:id",
259 params = { "ns|string|true",
263 errorCodes = { 403,404 },
264 text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns",
265 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)",
266 "Note: A namespace must have at least 1 responsible party"
270 public Result<Void> delResponsibleNS(AuthzTrans trans, String ns, String id) {
271 return func.delOwner(trans,ns,id);
275 * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object)
279 path = "/authz/ns/:ns/attrib/:key/:value",
280 params = { "ns|string|true",
282 "value|string|true"},
284 errorCodes = { 403,404,406,409 },
286 "Create an attribute in the Namespace",
287 "You must be given direct permission for key by AAF"
291 public Result<Void> createNsAttrib(AuthzTrans trans, String ns, String key, String value) {
292 TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
295 final Validator v = new ServiceValidator();
298 v.value(value).err()) {
299 return Result.err(Status.ERR_BadData,v.errs());
302 // Check if exists already
303 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
304 if(rlnsd.notOKorIsEmpty()) {
305 return Result.err(rlnsd);
307 NsDAO.Data nsd = rlnsd.value.get(0);
309 // Check for Existence
310 if(nsd.attrib.get(key)!=null) {
311 return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key);
314 // Check if User may put
315 if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
316 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
317 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
321 nsd.attrib.put(key, value);
322 ques.nsDAO.dao().attribAdd(trans,ns,key,value);
331 path = "/authz/ns/attrib/:key",
332 params = { "key|string|true" },
334 errorCodes = { 403,404 },
336 "Read Attributes for Namespace"
340 public Result<KEYS> readNsByAttrib(AuthzTrans trans, String key) {
342 final Validator v = new ServiceValidator();
343 if(v.nullOrBlank("Key",key).err()) {
344 return Result.err(Status.ERR_BadData,v.errs());
348 if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
349 ":"+trans.org().getDomain()+".*:"+key, Question.READ)) {
350 return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key);
353 Result<Set<String>> rsd = ques.nsDAO.dao().readNsByAttrib(trans, key);
355 return Result.err(rsd);
357 return mapper().keys(rsd.value);
363 path = "/authz/ns/:ns/attrib/:key/:value",
364 params = { "ns|string|true",
367 errorCodes = { 403,404 },
369 "Update Value on an existing attribute in the Namespace",
370 "You must be given direct permission for key by AAF"
374 public Result<?> updateNsAttrib(AuthzTrans trans, String ns, String key, String value) {
375 TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
378 final Validator v = new ServiceValidator();
381 v.value(value).err()) {
382 return Result.err(Status.ERR_BadData,v.errs());
385 // Check if exists already (NS must exist)
386 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
387 if(rlnsd.notOKorIsEmpty()) {
388 return Result.err(rlnsd);
390 NsDAO.Data nsd = rlnsd.value.get(0);
392 // Check for Existence
393 if(nsd.attrib.get(key)==null) {
394 return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key);
397 // Check if User may put
398 if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
399 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
400 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
404 nsd.attrib.put(key, value);
406 return ques.nsDAO.update(trans,nsd);
415 path = "/authz/ns/:ns/attrib/:key",
416 params = { "ns|string|true",
419 errorCodes = { 403,404 },
421 "Delete an attribute in the Namespace",
422 "You must be given direct permission for key by AAF"
426 public Result<Void> deleteNsAttrib(AuthzTrans trans, String ns, String key) {
427 TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB);
430 final Validator v = new ServiceValidator();
431 if(v.nullOrBlank("NS",ns).err() ||
432 v.nullOrBlank("Key",key).err()) {
433 return Result.err(Status.ERR_BadData,v.errs());
436 // Check if exists already
437 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
438 if(rlnsd.notOKorIsEmpty()) {
439 return Result.err(rlnsd);
441 NsDAO.Data nsd = rlnsd.value.get(0);
443 // Check for Existence
444 if(nsd.attrib.get(key)==null) {
445 return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key);
448 // Check if User may del
449 if(!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) {
450 return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key);
454 nsd.attrib.remove(key);
455 ques.nsDAO.dao().attribRemove(trans,ns,key);
464 path = "/authz/nss/:id",
465 params = { "id|string|true" },
467 errorCodes = { 404,406 },
469 "Lists the Admin(s), Responsible Party(s), Role(s), Permission(s)",
470 "Credential(s) and Expiration of Credential(s) in Namespace :id",
474 public Result<NSS> getNSbyName(AuthzTrans trans, String ns) {
475 final Validator v = new ServiceValidator();
476 if(v.nullOrBlank("NS", ns).err()) {
477 return Result.err(Status.ERR_BadData,v.errs());
480 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.read(trans, ns);
483 return Result.err(Status.ERR_NotFound, "No data found for %s",ns);
485 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read);
487 return Result.err(rnd);
491 Namespace namespace = new Namespace(rnd.value);
492 Result<List<String>> rd = func.getOwners(trans, namespace.name, false);
494 namespace.owner = rd.value;
496 rd = func.getAdmins(trans, namespace.name, false);
498 namespace.admin = rd.value;
501 NSS nss = mapper.newInstance(API.NSS);
502 return mapper.nss(trans, namespace, nss);
504 return Result.err(rlnd);
510 path = "/authz/nss/admin/:id",
511 params = { "id|string|true" },
513 errorCodes = { 403,404 },
514 text = { "Lists all Namespaces where Identity :id is an Admin",
515 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
519 public Result<NSS> getNSbyAdmin(AuthzTrans trans, String user, boolean full) {
520 final Validator v = new ServiceValidator();
521 if (v.nullOrBlank("User", user).err()) {
522 return Result.err(Status.ERR_BadData, v.errs());
525 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".admin", full);
527 return Result.err(rn);
530 return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user);
532 NSS nss = mapper.newInstance(API.NSS);
533 // Note: "loadNamespace" already validates view of Namespace
534 return mapper.nss(trans, rn.value, nss);
540 path = "/authz/nss/either/:id",
541 params = { "id|string|true" },
543 errorCodes = { 403,404 },
544 text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner",
545 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
549 public Result<NSS> getNSbyEither(AuthzTrans trans, String user, boolean full) {
550 final Validator v = new ServiceValidator();
551 if (v.nullOrBlank("User", user).err()) {
552 return Result.err(Status.ERR_BadData, v.errs());
555 Result<Collection<Namespace>> rn = loadNamepace(trans, user, null, full);
557 return Result.err(rn);
560 return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user);
562 NSS nss = mapper.newInstance(API.NSS);
563 // Note: "loadNamespace" already validates view of Namespace
564 return mapper.nss(trans, rn.value, nss);
567 private Result<Collection<Namespace>> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) {
568 Result<List<UserRoleDAO.Data>> urd = ques.userRoleDAO.readByUser(trans, user);
569 if(urd.notOKorIsEmpty()) {
570 return Result.err(urd);
572 Map<String, Namespace> lm = new HashMap<String,Namespace>();
573 Map<String, Namespace> other = full || endsWith==null?null:new TreeMap<String,Namespace>();
574 for(UserRoleDAO.Data urdd : urd.value) {
576 if(endsWith==null || urdd.role.endsWith(endsWith)) {
577 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
578 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
580 Namespace namespace = lm.get(nsd.value.name);
581 if(namespace==null) {
582 namespace = new Namespace(nsd.value);
583 lm.put(namespace.name,namespace);
585 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
587 namespace.admin=rls.value;
590 rls = func.getOwners(trans, namespace.name, false);
592 namespace.owner=rls.value;
596 } else { // Shortened version. Only Namespace Info available from Role.
597 if(Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) {
598 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
599 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
601 Namespace namespace = lm.get(nsd.value.name);
602 if(namespace==null) {
604 namespace = other.remove(nsd.value.name);
606 if(namespace==null) {
607 namespace = new Namespace(nsd.value);
608 namespace.admin=new ArrayList<String>();
609 namespace.owner=new ArrayList<String>();
611 if(endsWith==null || urdd.role.endsWith(endsWith)) {
612 lm.put(namespace.name,namespace);
614 other.put(namespace.name,namespace);
617 if(Question.OWNER.equals(urdd.rname)) {
618 namespace.owner.add(urdd.user);
620 namespace.admin.add(urdd.user);
626 return Result.ok(lm.values());
631 path = "/authz/nss/responsible/:id",
632 params = { "id|string|true" },
634 errorCodes = { 403,404 },
635 text = { "Lists all Namespaces where Identity :id is a Responsible Party",
636 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
640 public Result<NSS> getNSbyResponsible(AuthzTrans trans, String user, boolean full) {
641 final Validator v = new ServiceValidator();
642 if (v.nullOrBlank("User", user).err()) {
643 return Result.err(Status.ERR_BadData, v.errs());
645 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".owner",full);
647 return Result.err(rn);
650 return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user);
652 NSS nss = mapper.newInstance(API.NSS);
653 // Note: "loadNamespace" prevalidates
654 return mapper.nss(trans, rn.value, nss);
659 path = "/authz/nss/children/:id",
660 params = { "id|string|true" },
662 errorCodes = { 403,404 },
663 text = { "Lists all Child Namespaces of Namespace :id",
664 "Note: This is not a cached read"
668 public Result<NSS> getNSsChildren(AuthzTrans trans, String parent) {
669 final Validator v = new ServiceValidator();
670 if(v.nullOrBlank("NS", parent).err()) {
671 return Result.err(Status.ERR_BadData,v.errs());
674 Result<NsDAO.Data> rnd = ques.deriveNs(trans, parent);
676 return Result.err(rnd);
678 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
680 return Result.err(rnd);
683 Set<Namespace> lm = new HashSet<Namespace>();
684 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.dao().getChildren(trans, parent);
687 return Result.err(Status.ERR_NotFound, "No data found for %s",parent);
689 for(NsDAO.Data ndd : rlnd.value) {
690 Namespace namespace = new Namespace(ndd);
691 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
693 namespace.admin=rls.value;
696 rls = func.getOwners(trans, namespace.name, false);
698 namespace.owner=rls.value;
703 NSS nss = mapper.newInstance(API.NSS);
704 return mapper.nss(trans,lm, nss);
706 return Result.err(rlnd);
716 errorCodes = { 403,404,406 },
717 text = { "Replace the Current Description of a Namespace with a new one"
721 public Result<Void> updateNsDescription(AuthzTrans trans, REQUEST from) {
722 final Result<Namespace> nsd = mapper.ns(trans, from);
723 final ServiceValidator v = new ServiceValidator();
724 if(v.ns(nsd).err()) {
725 return Result.err(Status.ERR_BadData,v.errs());
727 if(v.nullOrBlank("description", nsd.value.description).err()) {
728 return Result.err(Status.ERR_BadData,v.errs());
731 Namespace namespace = nsd.value;
732 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.read(trans, namespace.name);
734 if(rlnd.notOKorIsEmpty()) {
735 return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name);
738 if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) {
739 return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name);
742 Result<Void> rdr = ques.nsDAO.dao().addDescription(trans, namespace.name, namespace.description);
746 return Result.err(rdr);
752 * @throws DAOException
753 * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
757 path = "/authz/ns/:ns",
758 params = { "ns|string|true" },
760 errorCodes = { 403,404,424 },
761 text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ",
762 "are still credentials associated with them, but they can be deleted by setting ",
763 "the \"force\" property. To do this: Add 'force=true' as a query parameter",
764 "<p>WARNING: Using force will delete all credentials attached to this namespace. Use with care.</p>"
765 + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted,"
766 + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted "
767 + "at or below Application Scope"
771 public Result<Void> deleteNS(AuthzTrans trans, String ns) {
772 return func.deleteNS(trans, ns);
776 /***********************************
778 ***********************************/
782 * @see org.onap.aaf.auth.service.AuthzService#createOrUpdatePerm(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object, boolean, java.lang.String, java.lang.String, java.lang.String, java.util.List, java.util.List)
786 path = "/authz/perm",
789 errorCodes = {403,404,406,409},
790 text = { "Permission consists of:",
791 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
792 + "is being protected</li>",
793 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
794 + " instance of the type</li>",
795 "<li>action - what kind of action is allowed</li></ul>",
796 "Note: instance and action can be an *"
800 public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {
801 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
802 final ServiceValidator v = new ServiceValidator();
803 if(v.perm(newPd).err()) {
804 return Result.err(Status.ERR_BadData,v.errs());
807 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
810 public String get() {
811 return "Create Permission [" +
812 newPd.value.fullType() + '|' +
813 newPd.value.instance + '|' +
814 newPd.value.action + ']';
818 private Result<NsDAO.Data> nsd;
820 public Result<?> mayChange() {
822 nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
827 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, newPd.value.ns);
828 if(nsr.notOKorIsEmpty()) {
829 return Result.err(nsr);
833 Result<String> rfc = func.createFuture(trans,fd.value,
834 newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
839 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
842 newPd.value.instance,
845 return Result.err(rfc);
848 return func.createPerm(trans, newPd.value, true);
850 return Result.err(fd);
856 path = "/authz/perms/:type",
857 params = {"type|string|true"},
859 errorCodes = { 404,406 },
860 text = { "List All Permissions that match the :type element of the key" }
863 public Result<PERMS> getPermsByType(AuthzTrans trans, final String permType) {
864 final Validator v = new ServiceValidator();
865 if(v.nullOrBlank("PermType", permType).err()) {
866 return Result.err(Status.ERR_BadData,v.errs());
869 Result<List<PermDAO.Data>> rlpd = ques.getPermsByType(trans, permType);
871 return Result.err(rlpd);
874 // We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper?
875 // Result<NsDAO.Data> r;
876 // if((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r);
878 PERMS perms = mapper.newInstance(API.PERMS);
879 if(!rlpd.isEmpty()) {
880 // Note: Mapper will restrict what can be viewed
881 return mapper.perms(trans, rlpd.value, perms, true);
883 return Result.ok(perms);
888 path = "/authz/perms/:type/:instance/:action",
889 params = {"type|string|true",
890 "instance|string|true",
891 "action|string|true"},
893 errorCodes = { 404,406 },
894 text = { "List Permissions that match key; :type, :instance and :action" }
897 public Result<PERMS> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
898 final Validator v = new ServiceValidator();
899 if(v.nullOrBlank("PermType", type).err()
900 || v.nullOrBlank("PermInstance", instance).err()
901 || v.nullOrBlank("PermAction", action).err()) {
902 return Result.err(Status.ERR_BadData,v.errs());
905 Result<List<PermDAO.Data>> rlpd = ques.getPermsByName(trans, type, instance, action);
907 return Result.err(rlpd);
910 PERMS perms = mapper.newInstance(API.PERMS);
911 if(!rlpd.isEmpty()) {
912 // Note: Mapper will restrict what can be viewed
913 return mapper.perms(trans, rlpd.value, perms, true);
915 return Result.ok(perms);
920 path = "/authz/perms/user/:user",
921 params = {"user|string|true"},
923 errorCodes = { 404,406 },
924 text = { "List All Permissions that match user :user",
925 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>"}
928 public Result<PERMS> getPermsByUser(AuthzTrans trans, String user) {
929 final Validator v = new ServiceValidator();
930 if(v.nullOrBlank("User", user).err()) {
931 return Result.err(Status.ERR_BadData,v.errs());
934 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,
935 trans.requested(force));
937 return Result.err(rlpd);
940 PERMS perms = mapper.newInstance(API.PERMS);
943 return Result.ok(perms);
945 // Note: Mapper will restrict what can be viewed
946 // if user is the same as that which is looked up, no filtering is required
947 return mapper.perms(trans, rlpd.value,
949 !user.equals(trans.user()));
954 path = "/authz/perms/user/:user/scope/:scope",
955 params = {"user|string|true","scope|string|true"},
957 errorCodes = { 404,406 },
958 text = { "List All Permissions that match user :user, filtered by NS (Scope)",
959 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
960 "<p>'scope' must be expressed as NSs separated by ':'</p>"
964 public Result<PERMS> getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) {
965 final Validator v = new ServiceValidator();
966 if(v.nullOrBlank("User", user).err()) {
967 return Result.err(Status.ERR_BadData,v.errs());
970 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user, trans.requested(force));
972 return Result.err(rlpd);
975 PERMS perms = mapper.newInstance(API.PERMS);
978 return Result.ok(perms);
980 // Note: Mapper will restrict what can be viewed
981 // if user is the same as that which is looked up, no filtering is required
982 return mapper.perms(trans, rlpd.value,
985 !user.equals(trans.user()));
990 path = "/authz/perms/user/:user",
991 params = {"user|string|true"},
993 errorCodes = { 404,406 },
994 text = { "List All Permissions that match user :user",
995 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
997 "Present Queries as one or more Permissions (see ContentType Links below for format).",
999 "If the Caller is Granted this specific Permission, and the Permission is valid",
1000 " for the User, it will be included in response Permissions, along with",
1001 " all the normal permissions on the 'GET' version of this call. If it is not",
1002 " valid, or Caller does not have permission to see, it will be removed from the list",
1004 " *Note: This design allows you to make one call for all expected permissions",
1005 " The permission to be included MUST be:",
1006 " <user namespace>.access|:<ns|role|perm>[:key]|<create|read|write>",
1008 " com.att.myns.access|:ns|write",
1009 " com.att.myns.access|:role:myrole|create",
1010 " com.att.myns.access|:perm:mytype:myinstance:myaction|read",
1015 public Result<PERMS> getPermsByUser(AuthzTrans trans, PERMS _perms, String user) {
1016 PERMS perms = _perms;
1017 final Validator v = new ServiceValidator();
1018 if(v.nullOrBlank("User", user).err()) {
1019 return Result.err(Status.ERR_BadData,v.errs());
1023 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,trans.requested(force));
1025 return Result.err(rlpd);
1029 1) See if allowed to query
1030 2) See if User is allowed
1032 Result<List<PermDAO.Data>> in = mapper.perms(trans, perms);
1033 if(in.isOKhasData()) {
1034 List<PermDAO.Data> out = rlpd.value;
1036 for(PermDAO.Data pdd : in.value) {
1038 if("access".equals(pdd.type)) {
1039 Access access = Access.valueOf(pdd.action);
1040 String[] mdkey = Split.splitTrim(':',pdd.instance);
1041 if(mdkey.length>1) {
1042 String type = mdkey[1];
1043 if("role".equals(type)) {
1044 if(mdkey.length>2) {
1045 RoleDAO.Data rdd = new RoleDAO.Data();
1048 ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK();
1050 } else if("perm".equals(type)) {
1051 if(mdkey.length>4) { // also need instance/action
1052 PermDAO.Data p = new PermDAO.Data();
1055 p.instance=mdkey[3];
1057 ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK();
1059 } else if("ns".equals(type)) {
1060 NsDAO.Data ndd = new NsDAO.Data();
1062 ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK();
1072 perms = mapper.newInstance(API.PERMS);
1073 if(rlpd.isEmpty()) {
1074 return Result.ok(perms);
1076 // Note: Mapper will restrict what can be viewed
1077 // if user is the same as that which is looked up, no filtering is required
1078 return mapper.perms(trans, rlpd.value,
1080 !user.equals(trans.user()));
1085 path = "/authz/perms/role/:role",
1086 params = {"role|string|true"},
1088 errorCodes = { 404,406 },
1089 text = { "List All Permissions that are granted to :role" }
1092 public Result<PERMS> getPermsByRole(AuthzTrans trans,String role) {
1093 final Validator v = new ServiceValidator();
1094 if(v.nullOrBlank("Role", role).err()) {
1095 return Result.err(Status.ERR_BadData,v.errs());
1098 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques,role);
1100 return Result.err(rrdd);
1103 Result<NsDAO.Data> r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
1105 return Result.err(r);
1108 PERMS perms = mapper.newInstance(API.PERMS);
1110 Result<List<PermDAO.Data>> rlpd = ques.getPermsByRole(trans, role, trans.requested(force));
1111 if(rlpd.isOKhasData()) {
1112 // Note: Mapper will restrict what can be viewed
1113 return mapper.perms(trans, rlpd.value, perms, true);
1115 return Result.ok(perms);
1120 path = "/authz/perms/ns/:ns",
1121 params = {"ns|string|true"},
1123 errorCodes = { 404,406 },
1124 text = { "List All Permissions that are in Namespace :ns" }
1127 public Result<PERMS> getPermsByNS(AuthzTrans trans,String ns) {
1128 final Validator v = new ServiceValidator();
1129 if(v.nullOrBlank("NS", ns).err()) {
1130 return Result.err(Status.ERR_BadData,v.errs());
1133 Result<NsDAO.Data> rnd = ques.deriveNs(trans, ns);
1135 return Result.err(rnd);
1138 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
1140 return Result.err(rnd);
1143 Result<List<PermDAO.Data>> rlpd = ques.permDAO.readNS(trans, ns);
1145 return Result.err(rlpd);
1148 PERMS perms = mapper.newInstance(API.PERMS);
1149 if(!rlpd.isEmpty()) {
1150 // Note: Mapper will restrict what can be viewed
1151 return mapper.perms(trans, rlpd.value,perms, true);
1153 return Result.ok(perms);
1158 path = "/authz/perm/:type/:instance/:action",
1159 params = {"type|string|true",
1160 "instance|string|true",
1161 "action|string|true"},
1163 errorCodes = { 404,406, 409 },
1164 text = { "Rename the Permission referenced by :type :instance :action, and "
1165 + "rename (copy/delete) to the Permission described in PermRequest" }
1168 public Result<Void> renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) {
1169 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
1170 final ServiceValidator v = new ServiceValidator();
1171 if(v.perm(newPd).err()) {
1172 return Result.err(Status.ERR_BadData,v.errs());
1175 if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) {
1176 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1177 newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action);
1180 Result<NsSplit> nss = ques.deriveNsSplit(trans, origType);
1181 Result<List<PermDAO.Data>> origRlpd = ques.permDAO.read(trans, nss.value.ns, nss.value.name, origInstance, origAction);
1183 if(origRlpd.notOKorIsEmpty()) {
1184 return Result.err(Status.ERR_PermissionNotFound,
1185 "Permission [%s|%s|%s] does not exist",
1186 origType,origInstance,origAction);
1189 PermDAO.Data origPd = origRlpd.value.get(0);
1191 if (!origPd.ns.equals(newPd.value.ns)) {
1192 return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " +
1193 "<new type> must start with [" + origPd.ns + "]");
1196 if ( origPd.type.equals(newPd.value.type) &&
1197 origPd.action.equals(newPd.value.action) &&
1198 origPd.instance.equals(newPd.value.instance) ) {
1199 return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission");
1202 Set<String> origRoles = origPd.roles(false);
1203 if (!origRoles.isEmpty()) {
1204 Set<String> roles = newPd.value.roles(true);
1205 for (String role : origPd.roles) {
1210 newPd.value.description = origPd.description;
1212 Result<Void> rv = null;
1214 rv = func.createPerm(trans, newPd.value, false);
1216 rv = func.deletePerm(trans, origPd, true, false);
1223 path = "/authz/perm",
1226 errorCodes = { 404,406 },
1227 text = { "Add Description Data to Perm" }
1230 public Result<Void> updatePermDescription(AuthzTrans trans, REQUEST from) {
1231 final Result<PermDAO.Data> pd = mapper.perm(trans, from);
1232 final ServiceValidator v = new ServiceValidator();
1233 if(v.perm(pd).err()) {
1234 return Result.err(Status.ERR_BadData,v.errs());
1236 if(v.nullOrBlank("description", pd.value.description).err()) {
1237 return Result.err(Status.ERR_BadData,v.errs());
1239 final PermDAO.Data perm = pd.value;
1240 if(ques.permDAO.read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) {
1241 return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist",
1242 perm.ns,perm.type,perm.instance,perm.action);
1245 if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) {
1246 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1247 perm.ns,perm.type,perm.instance,perm.action);
1250 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, pd.value.ns);
1251 if(nsr.notOKorIsEmpty()) {
1252 return Result.err(nsr);
1255 Result<Void> rdr = ques.permDAO.addDescription(trans, perm.ns, perm.type, perm.instance,
1256 perm.action, perm.description);
1260 return Result.err(rdr);
1267 path = "/authz/role/perm",
1270 errorCodes = {403,404,406,409},
1271 text = { "Set a permission's roles to roles given" }
1275 public Result<Void> resetPermRoles(final AuthzTrans trans, REQUEST rreq) {
1276 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1277 if(updt.notOKorIsEmpty()) {
1278 return Result.err(updt);
1281 final ServiceValidator v = new ServiceValidator();
1282 if(v.perm(updt).err()) {
1283 return Result.err(Status.ERR_BadData,v.errs());
1286 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
1288 return Result.err(nsd);
1291 // Read full set to get CURRENT values
1292 Result<List<PermDAO.Data>> rcurr = ques.permDAO.read(trans,
1295 updt.value.instance,
1298 if(rcurr.notOKorIsEmpty()) {
1299 return Result.err(Status.ERR_PermissionNotFound,
1300 "Permission [%s.%s|%s|%s] does not exist",
1301 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
1304 // Create a set of Update Roles, which are in Internal Format
1305 Set<String> updtRoles = new HashSet<String>();
1306 Result<NsSplit> nss;
1307 for(String role : updt.value.roles(false)) {
1308 nss = ques.deriveNsSplit(trans, role);
1310 updtRoles.add(nss.value.ns + '|' + nss.value.name);
1312 trans.error().log(nss.errorString());
1316 Result<Void> rv = null;
1318 for(PermDAO.Data curr : rcurr.value) {
1319 Set<String> currRoles = curr.roles(false);
1320 // must add roles to this perm, and add this perm to each role
1321 // in the update, but not in the current
1322 for (String role : updtRoles) {
1323 if (!currRoles.contains(role)) {
1324 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1325 if(key.isOKhasData()) {
1326 Result<List<RoleDAO.Data>> rrd = ques.roleDAO.read(trans, key.value);
1327 if(rrd.isOKhasData()) {
1328 for(RoleDAO.Data r : rrd.value) {
1329 rv = func.addPermToRole(trans, r, curr, false);
1330 if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) {
1331 return Result.err(rv);
1335 return Result.err(rrd);
1340 // similarly, must delete roles from this perm, and delete this perm from each role
1341 // in the update, but not in the current
1342 for (String role : currRoles) {
1343 if (!updtRoles.contains(role)) {
1344 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1345 if(key.isOKhasData()) {
1346 Result<List<RoleDAO.Data>> rdd = ques.roleDAO.read(trans, key.value);
1347 if(rdd.isOKhasData()) {
1348 for(RoleDAO.Data r : rdd.value) {
1349 rv = func.delPermFromRole(trans, r, curr, true);
1350 if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) {
1351 return Result.err(rv);
1359 return rv==null?Result.ok():rv;
1364 path = "/authz/perm",
1367 errorCodes = { 404,406 },
1368 text = { "Delete the Permission referenced by PermKey.",
1369 "You cannot normally delete a permission which is still granted to roles,",
1370 "however the \"force\" property allows you to do just that. To do this: Add",
1371 "'force=true' as a query parameter.",
1372 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>" }
1375 public Result<Void> deletePerm(final AuthzTrans trans, REQUEST from) {
1376 Result<PermDAO.Data> pd = mapper.perm(trans, from);
1378 return Result.err(pd);
1380 final ServiceValidator v = new ServiceValidator();
1381 if(v.nullOrBlank(pd.value).err()) {
1382 return Result.err(Status.ERR_BadData,v.errs());
1384 final PermDAO.Data perm = pd.value;
1385 if (ques.permDAO.read(trans, perm).notOKorIsEmpty()) {
1386 return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
1387 perm.ns,perm.type,perm.instance,perm.action );
1390 Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
1393 public String get() {
1394 return "Delete Permission [" + perm.fullPerm() + ']';
1398 private Result<NsDAO.Data> nsd;
1400 public Result<?> mayChange() {
1402 nsd = ques.mayUser(trans, trans.user(), perm, Access.write);
1410 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, perm.ns);
1411 if(nsr.notOKorIsEmpty()) {
1412 return Result.err(nsr);
1415 Result<String> rfc = func.createFuture(trans, fd.value,
1416 perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
1418 return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode());
1420 return Result.err(rfc);
1422 case Status.ACC_Now:
1423 return func.deletePerm(trans,perm,trans.requested(force), false);
1425 return Result.err(fd);
1431 path = "/authz/perm/:name/:type/:action",
1432 params = {"type|string|true",
1433 "instance|string|true",
1434 "action|string|true"},
1436 errorCodes = { 404,406 },
1437 text = { "Delete the Permission referenced by :type :instance :action",
1438 "You cannot normally delete a permission which is still granted to roles,",
1439 "however the \"force\" property allows you to do just that. To do this: Add",
1440 "'force=true' as a query parameter",
1441 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>"}
1444 public Result<Void> deletePerm(AuthzTrans trans, String type, String instance, String action) {
1445 final Validator v = new ServiceValidator();
1446 if(v.nullOrBlank("Type",type)
1447 .nullOrBlank("Instance",instance)
1448 .nullOrBlank("Action",action)
1450 return Result.err(Status.ERR_BadData,v.errs());
1453 Result<PermDAO.Data> pd = ques.permFrom(trans, type, instance, action);
1455 return func.deletePerm(trans, pd.value, trans.requested(force), false);
1457 return Result.err(pd);
1461 /***********************************
1463 ***********************************/
1466 path = "/authz/role",
1469 errorCodes = {403,404,406,409},
1472 "Roles are part of Namespaces",
1474 "<ul><li>org.onap.aaf - The team that created and maintains AAF</li>",
1475 "Roles do not include implied permissions for an App. Instead, they contain explicit Granted Permissions by any Namespace in AAF (See Permissions)",
1476 "Restrictions on Role Names:",
1477 "<ul><li>Must start with valid Namespace name, terminated by . (dot/period)</li>",
1478 "<li>Allowed Characters are a-zA-Z0-9._-</li>",
1479 "<li>role names are Case Sensitive</li></ul>",
1480 "The right questions to ask for defining and populating a Role in AAF, therefore, are:",
1481 "<ul><li>'What Job Function does this represent?'</li>",
1482 "<li>'Does this person perform this Job Function?'</li></ul>" }
1486 public Result<Void> createRole(final AuthzTrans trans, REQUEST from) {
1487 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1488 final ServiceValidator v = new ServiceValidator();
1489 if(v.role(rd).err()) {
1490 return Result.err(Status.ERR_BadData,v.errs());
1492 final RoleDAO.Data role = rd.value;
1493 if(ques.roleDAO.read(trans, role.ns, role.name).isOKhasData()) {
1494 return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists");
1497 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
1500 public String get() {
1501 return "Create Role [" +
1502 rd.value.fullName() +
1507 private Result<NsDAO.Data> nsd;
1509 public Result<?> mayChange() {
1511 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
1517 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
1518 if(nsr.notOKorIsEmpty()) {
1519 return Result.err(nsr);
1524 Result<String> rfc = func.createFuture(trans, fd.value,
1525 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.C);
1527 return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing",
1531 return Result.err(rfc);
1533 case Status.ACC_Now:
1534 Result<RoleDAO.Data> rdr = ques.roleDAO.create(trans, role);
1538 return Result.err(rdr);
1541 return Result.err(fd);
1546 * @see org.onap.aaf.auth.service.AuthzService#getRolesByName(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1550 path = "/authz/roles/:role",
1551 params = {"role|string|true"},
1553 errorCodes = {404,406},
1554 text = { "List Roles that match :role",
1555 "Note: You must have permission to see any given role"
1559 public Result<ROLES> getRolesByName(AuthzTrans trans, String role) {
1560 final Validator v = new ServiceValidator();
1561 if(v.nullOrBlank("Role", role).err()) {
1562 return Result.err(Status.ERR_BadData,v.errs());
1565 // Determine if User can ask this question
1566 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
1567 if(rrdd.isOKhasData()) {
1568 Result<NsDAO.Data> r;
1569 if((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) {
1570 return Result.err(r);
1573 return Result.err(rrdd);
1577 int query = role.indexOf('?');
1578 Result<List<RoleDAO.Data>> rlrd = ques.getRolesByName(trans, query<0?role:role.substring(0, query));
1580 // Note: Mapper will restrict what can be viewed
1581 ROLES roles = mapper.newInstance(API.ROLES);
1582 return mapper.roles(trans, rlrd.value, roles, true);
1584 return Result.err(rlrd);
1589 * @see org.onap.aaf.auth.service.AuthzService#getRolesByUser(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1593 path = "/authz/roles/user/:name",
1594 params = {"name|string|true"},
1596 errorCodes = {404,406},
1597 text = { "List all Roles that match user :name",
1598 "'user' must be expressed as full identity (ex: id@full.domain.com)",
1599 "Note: You must have permission to see any given role"
1604 public Result<ROLES> getRolesByUser(AuthzTrans trans, String user) {
1605 final Validator v = new ServiceValidator();
1606 if(v.nullOrBlank("User", user).err()) {
1607 return Result.err(Status.ERR_BadData,v.errs());
1610 ROLES roles = mapper.newInstance(API.ROLES);
1611 // Get list of roles per user, then add to Roles as we go
1612 Result<List<RoleDAO.Data>> rlrd;
1613 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, user);
1614 if(rlurd.isOKhasData()) {
1615 for(UserRoleDAO.Data urd : rlurd.value ) {
1616 rlrd = ques.roleDAO.read(trans, urd.ns,urd.rname);
1617 // Note: Mapper will restrict what can be viewed
1618 // if user is the same as that which is looked up, no filtering is required
1619 if(rlrd.isOKhasData()) {
1620 mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user()));
1624 return Result.ok(roles);
1629 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1633 path = "/authz/roles/ns/:ns",
1634 params = {"ns|string|true"},
1636 errorCodes = {404,406},
1637 text = { "List all Roles for the Namespace :ns",
1638 "Note: You must have permission to see any given role"
1643 public Result<ROLES> getRolesByNS(AuthzTrans trans, String ns) {
1644 final Validator v = new ServiceValidator();
1645 if(v.nullOrBlank("NS", ns).err()) {
1646 return Result.err(Status.ERR_BadData,v.errs());
1649 // check if user is allowed to view NS
1650 Result<NsDAO.Data> rnsd = ques.deriveNs(trans, ns);
1652 return Result.err(rnsd);
1654 rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read);
1656 return Result.err(rnsd);
1659 TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB);
1661 ROLES roles = mapper.newInstance(API.ROLES);
1662 // Get list of roles per user, then add to Roles as we go
1663 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.readNS(trans, ns);
1665 if(!rlrd.isEmpty()) {
1666 // Note: Mapper doesn't need to restrict what can be viewed, because we did it already.
1667 mapper.roles(trans,rlrd.value,roles,false);
1669 return Result.ok(roles);
1671 return Result.err(rlrd);
1680 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1684 path = "/authz/roles/name/:name",
1685 params = {"name|string|true"},
1687 errorCodes = {404,406},
1688 text = { "List all Roles for only the Name of Role (without Namespace)",
1689 "Note: You must have permission to see any given role"
1693 public Result<ROLES> getRolesByNameOnly(AuthzTrans trans, String name) {
1694 final Validator v = new ServiceValidator();
1695 if(v.nullOrBlank("Name", name).err()) {
1696 return Result.err(Status.ERR_BadData,v.errs());
1699 // User Mapper to make sure user is allowed to view NS
1701 TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB);
1703 ROLES roles = mapper.newInstance(API.ROLES);
1704 // Get list of roles per user, then add to Roles as we go
1705 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.readName(trans, name);
1707 if(!rlrd.isEmpty()) {
1708 // Note: Mapper will restrict what can be viewed
1709 mapper.roles(trans,rlrd.value,roles,true);
1711 return Result.ok(roles);
1713 return Result.err(rlrd);
1722 path = "/authz/roles/perm/:type/:instance/:action",
1723 params = {"type|string|true",
1724 "instance|string|true",
1725 "action|string|true"},
1727 errorCodes = {404,406},
1728 text = { "Find all Roles containing the given Permission." +
1729 "Permission consists of:",
1730 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1731 + "is being protected</li>",
1732 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1733 + " instance of the type</li>",
1734 "<li>action - what kind of action is allowed</li></ul>",
1735 "Notes: instance and action can be an *",
1736 " You must have permission to see any given role"
1741 public Result<ROLES> getRolesByPerm(AuthzTrans trans, String type, String instance, String action) {
1742 final Validator v = new ServiceValidator();
1744 .permInstance(instance)
1747 return Result.err(Status.ERR_BadData,v.errs());
1750 TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB);
1752 ROLES roles = mapper.newInstance(API.ROLES);
1753 // Get list of roles per user, then add to Roles as we go
1754 Result<NsSplit> nsSplit = ques.deriveNsSplit(trans, type);
1755 if(nsSplit.isOK()) {
1756 PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action);
1758 if((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) {
1759 return Result.err(res);
1762 Result<List<PermDAO.Data>> pdlr = ques.permDAO.read(trans, pdd);
1763 if(pdlr.isOK())for(PermDAO.Data pd : pdlr.value) {
1764 Result<List<RoleDAO.Data>> rlrd;
1765 for(String r : pd.roles) {
1766 Result<String[]> rs = RoleDAO.Data.decodeToArray(trans, ques, r);
1768 rlrd = ques.roleDAO.read(trans, rs.value[0],rs.value[1]);
1769 // Note: Mapper will restrict what can be viewed
1770 if(rlrd.isOKhasData()) {
1771 mapper.roles(trans,rlrd.value,roles,true);
1777 return Result.ok(roles);
1785 path = "/authz/role",
1788 errorCodes = {404,406},
1789 text = { "Add Description Data to a Role" }
1793 public Result<Void> updateRoleDescription(AuthzTrans trans, REQUEST from) {
1794 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1795 final ServiceValidator v = new ServiceValidator();
1796 if(v.role(rd).err()) {
1797 return Result.err(Status.ERR_BadData,v.errs());
1799 if(v.nullOrBlank("description", rd.value.description).err()) {
1800 return Result.err(Status.ERR_BadData,v.errs());
1803 final RoleDAO.Data role = rd.value;
1804 if(ques.roleDAO.read(trans, role.ns, role.name).notOKorIsEmpty()) {
1805 return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist");
1808 if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) {
1809 return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName());
1812 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
1813 if(nsr.notOKorIsEmpty()) {
1814 return Result.err(nsr);
1817 Result<Void> rdr = ques.roleDAO.addDescription(trans, role.ns, role.name, role.description);
1821 return Result.err(rdr);
1828 path = "/authz/role/perm",
1831 errorCodes = {403,404,406,409},
1832 text = { "Grant a Permission to a Role",
1833 "Permission consists of:",
1834 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1835 + "is being protected</li>",
1836 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1837 + " instance of the type</li>",
1838 "<li>action - what kind of action is allowed</li></ul>",
1839 "Note: instance and action can be an *",
1840 "Note: Using the \"force\" property will create the Permission, if it doesn't exist AND the requesting " +
1841 " ID is allowed to create. It will then grant",
1842 " the permission to the role in one step. To do this: add 'force=true' as a query parameter."
1847 public Result<Void> addPermToRole(final AuthzTrans trans, REQUEST rreq) {
1848 // Translate Request into Perm and Role Objects
1849 final Result<PermDAO.Data> rpd = mapper.permFromRPRequest(trans, rreq);
1850 if(rpd.notOKorIsEmpty()) {
1851 return Result.err(rpd);
1853 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1854 if(rrd.notOKorIsEmpty()) {
1855 return Result.err(rrd);
1858 // Validate Role and Perm values
1859 final ServiceValidator v = new ServiceValidator();
1860 if(v.perm(rpd.value)
1863 return Result.err(Status.ERR_BadData,v.errs());
1866 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.read(trans, rrd.value.ns, rrd.value.name);
1867 if(rlrd.notOKorIsEmpty()) {
1868 return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName());
1871 // Check Status of Data in DB (does it exist)
1872 Result<List<PermDAO.Data>> rlpd = ques.permDAO.read(trans, rpd.value.ns,
1873 rpd.value.type, rpd.value.instance, rpd.value.action);
1874 PermDAO.Data createPerm = null; // if not null, create first
1875 if(rlpd.notOKorIsEmpty()) { // Permission doesn't exist
1876 if(trans.requested(force)) {
1877 // Remove roles from perm data object so we just create the perm here
1878 createPerm = rpd.value;
1879 createPerm.roles.clear();
1881 return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist",
1882 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action);
1885 if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) {
1886 return Result.err(Status.ERR_ConflictAlreadyExists,
1887 "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]",
1888 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action,
1889 rrd.value.ns,rrd.value.name
1895 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals
1898 public String get() {
1899 return "Grant Permission [" + rpd.value.fullPerm() + ']' +
1900 " to Role [" + rrd.value.fullName() + "]";
1904 private Result<NsDAO.Data> nsd;
1906 public Result<?> mayChange() {
1908 nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
1913 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rpd.value.ns);
1914 if(nsr.notOKorIsEmpty()) {
1915 return Result.err(nsr);
1919 Result<String> rfc = func.createFuture(trans,fd.value,
1920 rpd.value.fullPerm(),
1925 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
1931 return Result.err(rfc);
1933 case Status.ACC_Now:
1934 Result<Void> rv = null;
1935 if(createPerm!=null) {// has been validated for creating
1936 rv = func.createPerm(trans, createPerm, false);
1938 if(rv==null || rv.isOK()) {
1939 rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
1943 return Result.err(fd);
1949 * Delete Perms from Roles (UnGrant)
1951 * @param roleFullName
1956 path = "/authz/role/:role/perm",
1957 params = {"role|string|true"},
1959 errorCodes = {404,406},
1960 text = { "Ungrant a permission from Role :role" }
1964 public Result<Void> delPermFromRole(final AuthzTrans trans, REQUEST rreq) {
1965 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1966 if(updt.notOKorIsEmpty()) {
1967 return Result.err(updt);
1969 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1970 if(rrd.notOKorIsEmpty()) {
1971 return Result.err(rrd);
1974 final ServiceValidator v = new ServiceValidator();
1975 if(v.nullOrBlank(updt.value)
1976 .nullOrBlank(rrd.value)
1978 return Result.err(Status.ERR_BadData,v.errs());
1981 return delPermFromRole(trans, updt.value,rrd.value, rreq);
1984 private Result<Void> delPermFromRole(final AuthzTrans trans, PermDAO.Data pdd, RoleDAO.Data rdd, REQUEST rreq) {
1985 Result<List<PermDAO.Data>> rlpd = ques.permDAO.read(trans, pdd.ns, pdd.type,
1986 pdd.instance, pdd.action);
1988 if(rlpd.notOKorIsEmpty()) {
1989 return Result.err(Status.ERR_PermissionNotFound,
1990 "Permission [%s.%s|%s|%s] does not exist",
1991 pdd.ns,pdd.type,pdd.instance,pdd.action);
1994 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, pdd,true, // allow ungrants requests
1997 public String get() {
1998 return "Ungrant Permission [" + pdd.fullPerm() + ']' +
1999 " from Role [" + rdd.fullName() + "]";
2003 private Result<NsDAO.Data> nsd;
2005 public Result<?> mayChange() {
2007 nsd = ques.mayUser(trans, trans.user(), pdd, Access.write);
2012 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, pdd.ns);
2013 if(nsr.notOKorIsEmpty()) {
2014 return Result.err(nsr);
2018 Result<String> rfc = func.createFuture(trans,fd.value,
2025 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2031 return Result.err(rfc);
2033 case Status.ACC_Now:
2034 return func.delPermFromRole(trans, rdd, pdd, false);
2036 return Result.err(fd);
2043 path = "/authz/role/:role/perm/:type/:instance/:action",
2044 params = {"role|string|true",
2045 "perm type|string|true",
2046 "perm instance|string|true",
2047 "perm action|string|true"
2050 errorCodes = {404,406},
2051 text = { "Ungrant a single permission from Role :role with direct key" }
2055 public Result<Void> delPermFromRole(AuthzTrans trans, String role, String type, String instance, String action) {
2056 Result<Data> rpns = ques.deriveNs(trans, type);
2057 if(rpns.notOKorIsEmpty()) {
2058 return Result.err(rpns);
2061 final Validator v = new ServiceValidator();
2063 .permType(rpns.value.name,rpns.value.parent)
2064 .permInstance(instance)
2067 return Result.err(Status.ERR_BadData,v.errs());
2070 Result<Data> rrns = ques.deriveNs(trans, role);
2071 if(rrns.notOKorIsEmpty()) {
2072 return Result.err(rrns);
2075 final Result<List<RoleDAO.Data>> rrd = ques.roleDAO.read(trans, rrns.value.parent, rrns.value.name);
2076 if(rrd.notOKorIsEmpty()) {
2077 return Result.err(rrd);
2080 final Result<List<PermDAO.Data>> rpd = ques.permDAO.read(trans, rpns.value.parent, rpns.value.name, instance, action);
2081 if(rpd.notOKorIsEmpty()) {
2082 return Result.err(rpd);
2086 return delPermFromRole(trans,rpd.value.get(0), rrd.value.get(0), mapper.ungrantRequest(trans, role, type, instance, action));
2091 path = "/authz/role/:role",
2092 params = {"role|string|true"},
2094 errorCodes = {404,406},
2095 text = { "Delete the Role named :role"}
2099 public Result<Void> deleteRole(AuthzTrans trans, String role) {
2100 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
2101 if(rrdd.isOKhasData()) {
2102 final ServiceValidator v = new ServiceValidator();
2103 if(v.nullOrBlank(rrdd.value).err()) {
2104 return Result.err(Status.ERR_BadData,v.errs());
2106 return func.deleteRole(trans, rrdd.value, false, false);
2108 return Result.err(rrdd);
2114 path = "/authz/role",
2117 errorCodes = { 404,406 },
2118 text = { "Delete the Role referenced by RoleKey",
2119 "You cannot normally delete a role which still has permissions granted or users assigned to it,",
2120 "however the \"force\" property allows you to do just that. To do this: Add 'force=true'",
2121 "as a query parameter.",
2122 "<p>WARNING: Using force will remove all users and permission from this role. Use with care.</p>"}
2126 public Result<Void> deleteRole(final AuthzTrans trans, REQUEST from) {
2127 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
2128 final ServiceValidator v = new ServiceValidator();
2130 return Result.err(Status.ERR_BadData,"Request does not contain Role");
2132 if(v.nullOrBlank(rd.value).err()) {
2133 return Result.err(Status.ERR_BadData,v.errs());
2135 final RoleDAO.Data role = rd.value;
2136 if(ques.roleDAO.read(trans, role).notOKorIsEmpty() && !trans.requested(force)) {
2137 return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist");
2140 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
2143 public String get() {
2144 return "Delete Role [" + role.fullName() + ']'
2145 + " and all attached user roles";
2149 private Result<NsDAO.Data> nsd;
2151 public Result<?> mayChange() {
2153 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
2161 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
2162 if(nsr.notOKorIsEmpty()) {
2163 return Result.err(nsr);
2166 Result<String> rfc = func.createFuture(trans, fd.value,
2167 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
2169 return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing",
2173 return Result.err(rfc);
2175 case Status.ACC_Now:
2176 return func.deleteRole(trans,role,trans.requested(force), true /*preapproved*/);
2178 return Result.err(fd);
2183 /***********************************
2185 ***********************************/
2186 private class MayCreateCred implements MayChange {
2187 private Result<NsDAO.Data> nsd;
2188 private AuthzTrans trans;
2189 private CredDAO.Data cred;
2190 private Executor exec;
2192 public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) {
2199 public Result<?> mayChange() {
2201 nsd = ques.validNSOfDomain(trans, cred.id);
2203 // is Ns of CredID valid?
2207 if(trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) {
2210 Result<?> rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write);
2211 if(rmc.isOKhasData()) {
2215 } catch (Exception e) {
2216 trans.warn().log(e);
2219 trans.warn().log(nsd.errorString());
2221 return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns);
2225 private class MayChangeCred implements MayChange {
2227 private Result<NsDAO.Data> nsd;
2228 private AuthzTrans trans;
2229 private CredDAO.Data cred;
2230 public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) {
2236 public Result<?> mayChange() {
2237 // User can change himself (but not create)
2238 if(trans.user().equals(cred.id)) {
2242 nsd = ques.validNSOfDomain(trans, cred.id);
2244 // Get the Namespace
2246 if(ques.mayUser(trans, trans.user(), nsd.value,Access.write).isOK()) {
2249 String user[] = Split.split('.',trans.user());
2251 String company = user[user.length-1] + '.' + user[user.length-2];
2252 if(ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,"reset")) {
2257 return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns);
2262 private final long DAY_IN_MILLIS = 24*3600*1000L;
2266 path = "/authn/cred",
2269 errorCodes = {403,404,406,409},
2270 text = { "A credential consists of:",
2271 "<ul><li>id - the ID to create within AAF. The domain is in reverse",
2272 "order of Namespace (i.e. Users of Namespace com.att.myapp would be",
2273 "AB1234@myapp.att.com</li>",
2274 "<li>password - Company Policy Compliant Password</li></ul>",
2275 "Note: AAF does support multiple credentials with the same ID.",
2276 "Check with your organization if you have this implemented."
2280 public Result<Void> createUserCred(final AuthzTrans trans, REQUEST from) {
2281 final String cmdDescription = ("Create User Credential");
2282 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2285 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2286 if(rcred.isOKhasData()) {
2287 byte[] rawCred = rcred.value.cred.array();
2288 rcred = ques.userCredSetup(trans, rcred.value);
2290 final ServiceValidator v = new ServiceValidator();
2292 if(v.cred(trans, trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations
2293 return Result.err(Status.ERR_BadData,v.errs());
2297 // 2016-4 Jonathan, New Behavior - If MechID is not registered with Org, deny creation
2298 Identity mechID = null;
2299 Organization org = trans.org();
2301 mechID = org.getIdentity(trans, rcred.value.id);
2302 } catch (Exception e1) {
2303 trans.error().log(e1,rcred.value.id,"cannot be validated at this time");
2305 if(mechID==null || !mechID.isFound()) {
2306 return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName());
2309 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rcred.value.ns);
2310 if(nsr.notOKorIsEmpty()) {
2311 return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns);
2315 boolean firstID = false;
2318 CassExecutor exec = new CassExecutor(trans, func);
2319 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, rcred.value.id);
2320 if (rlcd.isOKhasData()) {
2321 if (!org.canHaveMultipleCreds(rcred.value.id)) {
2322 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists");
2325 for (CredDAO.Data curr : rlcd.value) {
2326 // May not use the same password in the list
2327 // Note: ASPR specifies character differences, but we don't actually store the
2328 // password to validate char differences.
2330 rb = ques.userCredCheck(trans, curr, rawCred);
2332 return Result.err(rb);
2333 } else if(rb.value){
2334 return Result.err(Status.ERR_Policy, "Credential content cannot be reused.");
2335 } else if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) {
2336 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'");
2341 // 2016-04-12 Jonathan If Caller is the Sponsor and is also an Owner of NS, allow without special Perm
2342 String theMechID = rcred.value.id;
2343 Boolean otherMechIDs = false;
2344 // find out if this is the only mechID. other MechIDs mean special handling (not automated)
2345 for(CredDAO.Data cd : ques.credDAO.readNS(trans,nsr.value.get(0).name).value) {
2346 if(!cd.id.equals(theMechID)) {
2347 otherMechIDs = true;
2352 // We can say "ID does not exist" here
2353 if((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) {
2354 return Result.err(Status.ERR_Denied, reason);
2357 } catch (Exception e) {
2358 return Result.err(e);
2362 mc = new MayCreateCred(trans, rcred.value, exec);
2364 final CredDAO.Data cdd = rcred.value;
2365 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future.
2368 public String get() {
2369 return cmdDescription + " [" +
2372 + cdd.expires + ']';
2379 Result<String> rfc = func.createFuture(trans, fd.value,
2380 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2381 trans.user(), nsr.value.get(0), FUTURE_OP.C);
2383 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing",
2385 Integer.toString(rcred.value.type),
2386 rcred.value.expires.toString());
2388 return Result.err(rfc);
2390 case Status.ACC_Now:
2393 // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) {
2394 Result<List<String>> admins = func.getAdmins(trans, nsr.value.get(0).name, false);
2395 // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length
2396 // Note, we only do this on First time, because of possibility of
2397 // prematurely expiring a production id
2398 if(admins.isOKhasData() && !admins.value.contains(trans.user())) {
2399 rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime();
2402 } catch (Exception e) {
2403 trans.error().log(e, "While setting expiration to TempPassword");
2405 Result<?>udr = ques.credDAO.create(trans, rcred.value);
2409 return Result.err(udr);
2411 return Result.err(fd);
2415 return Result.err(rcred);
2424 path = "/authn/creds/ns/:ns",
2425 params = {"ns|string|true"},
2427 errorCodes = {403,404,406},
2428 text = { "Return all IDs in Namespace :ns"
2432 public Result<USERS> getCredsByNS(AuthzTrans trans, String ns) {
2433 final Validator v = new ServiceValidator();
2434 if(v.ns(ns).err()) {
2435 return Result.err(Status.ERR_BadData,v.errs());
2438 // check if user is allowed to view NS
2439 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2441 return Result.err(rnd);
2443 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2445 return Result.err(rnd);
2448 TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB);
2450 USERS users = mapper.newInstance(API.USERS);
2451 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readNS(trans, ns);
2454 if(!rlcd.isEmpty()) {
2455 return mapper.cred(rlcd.value, users);
2457 return Result.ok(users);
2459 return Result.err(rlcd);
2469 path = "/authn/creds/id/:ns",
2470 params = {"id|string|true"},
2472 errorCodes = {403,404,406},
2473 text = { "Return all IDs in for ID"
2474 ,"(because IDs are multiple, due to multiple Expiration Dates)"
2478 public Result<USERS> getCredsByID(AuthzTrans trans, String id) {
2479 final Validator v = new ServiceValidator();
2480 if(v.nullOrBlank("ID",id).err()) {
2481 return Result.err(Status.ERR_BadData,v.errs());
2484 String ns = Question.domain2ns(id);
2485 // check if user is allowed to view NS
2486 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2488 return Result.err(rnd);
2490 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2492 return Result.err(rnd);
2495 TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB);
2497 USERS users = mapper.newInstance(API.USERS);
2498 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, id);
2501 if(!rlcd.isEmpty()) {
2502 return mapper.cred(rlcd.value, users);
2504 return Result.ok(users);
2506 return Result.err(rlcd);
2516 path = "/authn/certs/id/:id",
2517 params = {"id|string|true"},
2519 errorCodes = {403,404,406},
2520 text = { "Return Cert Info for ID"
2524 public Result<CERTS> getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) {
2525 TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB);
2527 CERTS certs = mapper.newInstance(API.CERTS);
2528 Result<List<CertDAO.Data>> rlcd = ques.certDAO.readID(trans, id);
2531 if(!rlcd.isEmpty()) {
2532 return mapper.cert(rlcd.value, certs);
2534 return Result.ok(certs);
2536 return Result.err(rlcd);
2546 path = "/authn/cred",
2549 errorCodes = {300,403,404,406},
2550 text = { "Reset a Credential Password. If multiple credentials exist for this",
2551 "ID, you will need to specify which entry you are resetting in the",
2552 "CredRequest object"
2556 public Result<Void> changeUserCred(final AuthzTrans trans, REQUEST from) {
2557 final String cmdDescription = "Update User Credential";
2558 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2560 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2561 if(rcred.isOKhasData()) {
2562 rcred = ques.userCredSetup(trans, rcred.value);
2564 final ServiceValidator v = new ServiceValidator();
2566 if(v.cred(trans, trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations
2567 return Result.err(Status.ERR_BadData,v.errs());
2569 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, rcred.value.id);
2570 if(rlcd.notOKorIsEmpty()) {
2571 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2574 MayChange mc = new MayChangeCred(trans, rcred.value);
2575 Result<?> rmc = mc.mayChange();
2577 return Result.err(rmc);
2580 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2582 return Result.err(ri);
2584 int entry = ri.value;
2587 final CredDAO.Data cred = rcred.value;
2589 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false,
2592 public String get() {
2593 return cmdDescription + " [" +
2596 + cred.expires + ']';
2601 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rcred.value.ns);
2602 if(nsr.notOKorIsEmpty()) {
2603 return Result.err(nsr);
2608 Result<String> rfc = func.createFuture(trans, fd.value,
2609 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2610 trans.user(), nsr.value.get(0), FUTURE_OP.U);
2612 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]",
2614 Integer.toString(rcred.value.type),
2615 rcred.value.expires.toString());
2617 return Result.err(rfc);
2619 case Status.ACC_Now:
2620 Result<?>udr = null;
2621 // If we are Resetting Password on behalf of someone else (am not the Admin)
2622 // use TempPassword Expiration time.
2624 if(ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) {
2625 exp = Expiration.Password;
2627 exp = Expiration.TempPassword;
2630 Organization org = trans.org();
2631 CredDAO.Data current = rlcd.value.get(entry);
2632 // If user resets password in same day, we will have a primary key conflict, so subtract 1 day
2633 if (current.expires.equals(rcred.value.expires)
2634 && rlcd.value.get(entry).type==rcred.value.type) {
2635 GregorianCalendar gc = org.expiration(null, exp,rcred.value.id);
2636 gc = Chrono.firstMomentOfDay(gc);
2637 gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay());
2638 rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS);
2640 rcred.value.expires = org.expiration(null,exp).getTime();
2642 // Copy in other fields 10/21/2016
2643 rcred.value.notes=current.notes;
2645 udr = ques.credDAO.create(trans, rcred.value);
2647 udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false);
2653 return Result.err(udr);
2655 return Result.err(fd);
2658 return Result.err(rcred);
2666 * Codify the way to get Either Choice Needed or actual Integer from Credit Request
2668 private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd) {
2670 if (lcd.size() > 1) {
2671 String inputOption = cr.getEntry();
2672 if (inputOption == null) {
2673 String message = selectCredFromList(lcd, false);
2674 String[] variables = buildVariables(lcd);
2675 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2677 entry = Integer.parseInt(inputOption) - 1;
2679 if (entry < 0 || entry >= lcd.size()) {
2680 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2683 return Result.ok(entry);
2688 path = "/authn/cred/:days",
2689 params = {"days|string|true"},
2691 errorCodes = {300,403,404,406},
2692 text = { "Extend a Credential Expiration Date. The intention of this API is",
2693 "to avoid an outage in PROD due to a Credential expiring before it",
2694 "can be configured correctly. Measures are being put in place ",
2695 "so that this is not abused."
2699 public Result<Void> extendUserCred(final AuthzTrans trans, REQUEST from, String days) {
2700 TimeTaken tt = trans.start("Extend User Credential", Env.SUB);
2702 Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2703 Organization org = trans.org();
2704 final ServiceValidator v = new ServiceValidator();
2705 if(v.notOK(cred).err() ||
2706 v.nullOrBlank(cred.value.id, "Invalid ID").err() ||
2707 v.user(org,cred.value.id).err()) {
2708 return Result.err(Status.ERR_BadData,v.errs());
2713 if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) {
2714 return Result.err(Status.ERR_Policy,reason);
2716 } catch (Exception e) {
2718 trans.error().log(e, msg="Could not contact Organization for User Validation");
2719 return Result.err(Status.ERR_Denied, msg);
2722 // Get the list of Cred Entries
2723 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, cred.value.id);
2724 if(rlcd.notOKorIsEmpty()) {
2725 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2728 //Need to do the "Pick Entry" mechanism
2729 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2731 return Result.err(ri);
2734 CredDAO.Data found = rlcd.value.get(ri.value);
2735 CredDAO.Data cd = cred.value;
2736 // Copy over the cred
2738 cd.cred = found.cred;
2739 cd.other = found.other;
2740 cd.type = found.type;
2741 cd.notes = found.notes;
2743 cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime();
2745 cred = ques.credDAO.create(trans, cd);
2749 return Result.err(cred);
2755 private String[] buildVariables(List<CredDAO.Data> value) {
2756 // ensure credentials are sorted so we can fully automate Cred regression test
2757 Collections.sort(value, new Comparator<CredDAO.Data>() {
2759 public int compare(CredDAO.Data cred1, CredDAO.Data cred2) {
2760 return cred1.expires.compareTo(cred2.expires);
2763 String [] vars = new String[value.size()+1];
2765 for (int i = 0; i < value.size(); i++) {
2766 vars[i+1] = value.get(i).id + " " + value.get(i).type
2767 + " |" + value.get(i).expires;
2772 private String selectCredFromList(List<CredDAO.Data> value, boolean isDelete) {
2773 StringBuilder errMessage = new StringBuilder();
2774 String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:";
2775 int numSpaces = value.get(0).id.length() - "Id".length();
2777 errMessage.append(userPrompt + '\n');
2778 errMessage.append(" Id");
2779 for (int i = 0; i < numSpaces; i++) {
2780 errMessage.append(' ');
2782 errMessage.append(" Type Expires" + '\n');
2783 for(int i=0;i<value.size();++i) {
2784 errMessage.append(" %s\n");
2786 errMessage.append("Run same command again with chosen entry as last parameter");
2788 return errMessage.toString();
2794 path = "/authn/cred",
2797 errorCodes = {300,403,404,406},
2798 text = { "Delete a Credential. If multiple credentials exist for this",
2799 "ID, you will need to specify which entry you are deleting in the",
2800 "CredRequest object."
2804 public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from) {
2805 final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2806 final Validator v = new ServiceValidator();
2807 if(v.nullOrBlank("cred", cred.value.id).err()) {
2808 return Result.err(Status.ERR_BadData,v.errs());
2811 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, cred.value.id);
2812 if(rlcd.notOKorIsEmpty()) {
2813 // Empty Creds should have no user_roles.
2814 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id);
2816 for(UserRoleDAO.Data data : rlurd.value) {
2817 ques.userRoleDAO.delete(trans, data, false);
2820 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2822 boolean isLastCred = rlcd.value.size()==1;
2824 MayChange mc = new MayChangeCred(trans,cred.value);
2825 Result<?> rmc = mc.mayChange();
2827 return Result.err(rmc);
2831 if(!trans.requested(force)) {
2832 if (rlcd.value.size() > 1) {
2833 CredRequest cr = (CredRequest)from;
2834 String inputOption = cr.getEntry();
2835 if (inputOption == null) {
2836 String message = selectCredFromList(rlcd.value, true);
2837 String[] variables = buildVariables(rlcd.value);
2838 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2841 if(inputOption.length()>5) { // should be a date
2842 Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime();
2844 for(CredDAO.Data cd : rlcd.value) {
2845 if(cd.type.equals(cr.getType()) && cd.expires.equals(d)) {
2851 entry = Integer.parseInt(inputOption) - 1;
2853 } catch(NullPointerException e) {
2854 return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry");
2855 } catch(NumberFormatException e) {
2856 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2859 isLastCred = (entry==-1)?true:false;
2863 if (entry < -1 || entry >= rlcd.value.size()) {
2864 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2868 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
2871 public String get() {
2872 return "Delete Credential [" +
2879 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, cred.value.ns);
2880 if(nsr.notOKorIsEmpty()) {
2881 return Result.err(nsr);
2886 Result<String> rfc = func.createFuture(trans, fd.value, cred.value.id,
2887 trans.user(), nsr.value.get(0), FUTURE_OP.D);
2890 return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
2892 return Result.err(rfc);
2894 case Status.ACC_Now:
2895 Result<?>udr = null;
2896 if (!trans.requested(force)) {
2897 if(entry<0 || entry >= rlcd.value.size()) {
2898 return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
2900 udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false);
2902 for (CredDAO.Data curr : rlcd.value) {
2903 udr = ques.credDAO.delete(trans, curr, false);
2905 return Result.err(udr);
2910 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id);
2912 for(UserRoleDAO.Data data : rlurd.value) {
2913 ques.userRoleDAO.delete(trans, data, false);
2918 return Result.err(Result.ERR_NotFound,"No User Data found");
2923 return Result.err(udr);
2925 return Result.err(fd);
2932 public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
2933 TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
2935 // Note: Mapper assigns RAW type
2936 Result<CredDAO.Data> data = mapper.cred(trans, credReq,false);
2937 if(data.notOKorIsEmpty()) {
2938 return Result.err(data);
2940 CredDAO.Data cred = data.value; // of the Mapped Cred
2941 if(cred.cred==null) {
2942 return Result.err(Result.ERR_BadData,"No Password");
2944 return ques.doesUserCredMatch(trans, cred.id, cred.cred.array());
2947 } catch (DAOException e) {
2948 trans.error().log(e,"Error looking up cred");
2949 return Result.err(Status.ERR_Denied,"Credential does not match");
2957 path = "/authn/basicAuth",
2960 errorCodes = { 403 },
2961 text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n"
2962 + "Use /authn/validate instead\n"
2963 + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
2964 + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
2965 + "security, and 403 if it does not." }
2967 private void basicAuth() {
2968 // This is a place holder for Documentation. The real BasicAuth API does not call Service.
2973 path = "/authn/validate",
2976 errorCodes = { 403 },
2977 text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can "
2978 + "do more than BasicAuth as Credential types exp" }
2981 public Result<Date> validateBasicAuth(AuthzTrans trans, String basicAuth) {
2982 //TODO how to make sure people don't use this in browsers? Do we care?
2983 TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB);
2985 BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm());
2986 Result<Date> rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred());
2987 // Note: Only want to log problem, don't want to send back to end user
2991 trans.audit().log(rq.errorString());
2993 } catch (Exception e) {
2994 trans.warn().log(e);
2998 return Result.err(Status.ERR_Denied,"Bad Basic Auth");
3001 /***********************************
3003 ***********************************/
3006 path = "/authz/userRole",
3009 errorCodes = {403,404,406,409},
3010 text = { "Create a UserRole relationship (add User to Role)",
3011 "A UserRole is an object Representation of membership of a Role for limited time.",
3012 "If a shorter amount of time for Role ownership is required, use the 'End' field.",
3013 "** Note: Owners of Namespaces will be required to revalidate users in these roles ",
3014 "before Expirations expire. Namespace owners will be notified by email."
3018 public Result<Void> createUserRole(final AuthzTrans trans, REQUEST from) {
3019 TimeTaken tt = trans.start("Create UserRole", Env.SUB);
3021 Result<UserRoleDAO.Data> urr = mapper.userRole(trans, from);
3022 if(urr.notOKorIsEmpty()) {
3023 return Result.err(urr);
3025 final UserRoleDAO.Data userRole = urr.value;
3027 final ServiceValidator v = new ServiceValidator();
3028 if(v.user_role(userRole).err() ||
3029 v.user(trans.org(), userRole.user).err()) {
3030 return Result.err(Status.ERR_BadData,v.errs());
3035 // Check if user can change first
3036 Result<FutureDAO.Data> fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals
3039 public String get() {
3040 return "Add User [" + userRole.user + "] to Role [" +
3046 private Result<NsDAO.Data> nsd;
3048 public Result<?> mayChange() {
3050 RoleDAO.Data r = RoleDAO.Data.decode(userRole);
3051 nsd = ques.mayUser(trans, trans.user(), r, Access.write);
3056 Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
3057 if(nsr.notOKorIsEmpty()) {
3058 return Result.err(nsr);
3063 Result<String> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname,
3064 userRole.user, nsr.value, FUTURE_OP.C);
3066 return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
3071 return Result.err(rfc);
3073 case Status.ACC_Now:
3074 return func.addUserRole(trans, userRole);
3076 return Result.err(fd);
3084 * getUserRolesByRole
3088 path = "/authz/userRoles/role/:role",
3089 params = {"role|string|true"},
3091 errorCodes = {404,406},
3092 text = { "List all Users that are attached to Role specified in :role",
3096 public Result<USERROLES> getUserRolesByRole(AuthzTrans trans, String role) {
3097 final Validator v = new ServiceValidator();
3098 if(v.nullOrBlank("Role",role).err()) {
3099 return Result.err(Status.ERR_BadData,v.errs());
3102 Result<RoleDAO.Data> rrdd;
3103 rrdd = RoleDAO.Data.decode(trans,ques,role);
3105 return Result.err(rrdd);
3107 // May Requester see result?
3108 Result<NsDAO.Data> ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read);
3110 return Result.err(ns);
3113 // boolean filter = true;
3114 // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user()))
3117 // Get list of roles per user, then add to Roles as we go
3118 HashSet<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
3119 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role);
3121 for(UserRoleDAO.Data data : rlurd.value) {
3126 @SuppressWarnings("unchecked")
3127 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3128 // Checked for permission
3129 mapper.userRoles(trans, userSet, users);
3130 return Result.ok(users);
3133 * getUserRolesByRole
3137 path = "/authz/userRoles/user/:user",
3138 params = {"role|string|true"},
3140 errorCodes = {404,406},
3141 text = { "List all UserRoles for :user",
3145 public Result<USERROLES> getUserRolesByUser(AuthzTrans trans, String user) {
3146 final Validator v = new ServiceValidator();
3147 if(v.nullOrBlank("User",user).err()) {
3148 return Result.err(Status.ERR_BadData,v.errs());
3151 // Get list of roles per user, then add to Roles as we go
3152 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, user);
3154 return Result.err(rlurd);
3159 * 2) is User's Supervisor
3160 * 3) Has special global access =read permission
3162 * If none of the 3, then filter results to NSs in which Calling User has Ns.access * read
3165 String callingUser = trans.getUserPrincipal().getName();
3166 NsDAO.Data ndd = new NsDAO.Data();
3168 if(user.equals(callingUser)) {
3171 Organization org = trans.org();
3173 Identity orgID = org.getIdentity(trans, user);
3174 Identity manager = orgID==null?null:orgID.responsibleTo();
3175 if(orgID!=null && (manager!=null && callingUser.equals(manager.fullID()))) {
3177 } else if(ques.isGranted(trans, callingUser, ROOT_NS, Question.ACCESS, "*", Access.read.name())) {
3182 } catch (OrganizationException e) {
3188 List<UserRoleDAO.Data> content;
3190 content = new ArrayList<UserRoleDAO.Data>(rlurd.value.size()); // avoid multi-memory redos
3192 for(UserRoleDAO.Data data : rlurd.value) {
3194 Result<Data> mur = ques.mayUser(trans, callingUser, ndd, Access.read);
3201 content = rlurd.value;
3205 @SuppressWarnings("unchecked")
3206 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3207 // Checked for permission
3208 mapper.userRoles(trans, content, users);
3209 return Result.ok(users);
3215 path = "/authz/userRole/user",
3218 errorCodes = {403,404,406},
3219 text = { "Set a User's roles to the roles specified in the UserRoleRequest object.",
3220 "WARNING: Roles supplied will be the ONLY roles attached to this user",
3221 "If no roles are supplied, user's roles are reset."
3225 public Result<Void> resetRolesForUser(AuthzTrans trans, REQUEST rreq) {
3226 Result<UserRoleDAO.Data> rurdd = mapper.userRole(trans, rreq);
3227 final ServiceValidator v = new ServiceValidator();
3228 if(rurdd.notOKorIsEmpty()) {
3229 return Result.err(rurdd);
3231 if (v.user(trans.org(), rurdd.value.user).err()) {
3232 return Result.err(Status.ERR_BadData,v.errs());
3235 Set<String> currRoles = new HashSet<String>();
3236 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, rurdd.value.user);
3238 for(UserRoleDAO.Data data : rlurd.value) {
3239 currRoles.add(data.role);
3243 Result<Void> rv = null;
3245 if(rurdd.value.role==null) {
3246 roles = new String[0];
3248 roles = rurdd.value.role.split(",");
3251 for (String role : roles) {
3252 if (v.role(role).err()) {
3253 return Result.err(Status.ERR_BadData,v.errs());
3255 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3257 return Result.err(rrdd);
3260 rurdd.value.role(rrdd.value);
3262 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), rrdd.value,Access.write);
3264 return Result.err(nsd);
3266 Result<NsDAO.Data> nsr = ques.deriveNs(trans, role);
3267 if(nsr.notOKorIsEmpty()) {
3268 return Result.err(nsr);
3271 if(currRoles.contains(role)) {
3272 currRoles.remove(role);
3274 rv = func.addUserRole(trans, rurdd.value);
3281 for (String role : currRoles) {
3282 rurdd.value.role(trans,ques,role);
3283 rv = ques.userRoleDAO.delete(trans, rurdd.value, false);
3285 trans.info().log(rurdd.value.user,"/",rurdd.value.role, "expected to be deleted, but does not exist");
3286 // return rv; // if it doesn't exist, don't error out
3297 path = "/authz/userRole/role",
3300 errorCodes = {403,404,406},
3301 text = { "Set a Role's users to the users specified in the UserRoleRequest object.",
3302 "WARNING: Users supplied will be the ONLY users attached to this role",
3303 "If no users are supplied, role's users are reset."
3307 public Result<Void> resetUsersForRole(AuthzTrans trans, REQUEST rreq) {
3308 Result<UserRoleDAO.Data> rurdd = mapper.userRole(trans, rreq);
3309 if(rurdd.notOKorIsEmpty()) {
3310 return Result.err(rurdd);
3312 final ServiceValidator v = new ServiceValidator();
3313 if (v.user_role(rurdd.value).err()) {
3314 return Result.err(Status.ERR_BadData,v.errs());
3317 RoleDAO.Data rd = RoleDAO.Data.decode(rurdd.value);
3319 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), rd, Access.write);
3321 return Result.err(nsd);
3324 Result<NsDAO.Data> nsr = ques.deriveNs(trans, rurdd.value.role);
3325 if(nsr.notOKorIsEmpty()) {
3326 return Result.err(nsr);
3329 Set<String> currUsers = new HashSet<String>();
3330 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, rurdd.value.role);
3332 for(UserRoleDAO.Data data : rlurd.value) {
3333 currUsers.add(data.user);
3337 // found when connected remotely to DEVL, can't replicate locally
3338 // inconsistent errors with cmd: role user setTo [nothing]
3339 // deleteUserRole --> read --> get --> cacheIdx(?)
3340 // sometimes returns idx for last added user instead of user passed in
3344 Result<Void> rv = null;
3345 String[] users = {};
3346 if (rurdd.value.user != null) {
3347 users = rurdd.value.user.split(",");
3350 for (String user : users) {
3351 if (v.user(trans.org(), user).err()) {
3352 return Result.err(Status.ERR_BadData,v.errs());
3354 rurdd.value.user = user;
3356 if(currUsers.contains(user)) {
3357 currUsers.remove(user);
3359 rv = func.addUserRole(trans, rurdd.value);
3366 for (String user : currUsers) {
3367 rurdd.value.user = user;
3368 rv = ques.userRoleDAO.delete(trans, rurdd.value, false);
3370 trans.info().log(rurdd.value, "expected to be deleted, but not exists");
3380 path = "/authz/userRole/extend/:user/:role",
3381 params = { "user|string|true",
3385 errorCodes = {403,404,406},
3386 text = { "Extend the Expiration of this User Role by the amount set by Organization",
3387 "Requestor must be allowed to modify the role"
3391 public Result<Void> extendUserRole(AuthzTrans trans, String user, String role) {
3392 Organization org = trans.org();
3393 final ServiceValidator v = new ServiceValidator();
3394 if(v.user(org, user)
3397 return Result.err(Status.ERR_BadData,v.errs());
3400 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3402 return Result.err(rrdd);
3405 Result<NsDAO.Data> rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write);
3406 boolean mayNotChange;
3407 if((mayNotChange = rcr.notOK()) && !trans.requested(future)) {
3408 return Result.err(rcr);
3411 Result<List<UserRoleDAO.Data>> rr = ques.userRoleDAO.read(trans, user,role);
3413 return Result.err(rr);
3415 for(UserRoleDAO.Data userRole : rr.value) {
3416 if(mayNotChange) { // Function exited earlier if !trans.futureRequested
3417 FutureDAO.Data fto = new FutureDAO.Data();
3418 fto.target=UserRoleDAO.TABLE;
3419 fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]";
3420 GregorianCalendar now = new GregorianCalendar();
3421 fto.start = now.getTime();
3422 fto.expires = org.expiration(now, Expiration.Future).getTime();
3424 fto.construct = userRole.bytify();
3425 } catch (IOException e) {
3426 trans.error().log(e, "Error while bytifying UserRole for Future");
3427 return Result.err(e);
3430 Result<String> rfc = func.createFuture(trans, fto,
3431 userRole.user+'|'+userRole.role, userRole.user, rcr.value, FUTURE_OP.U);
3433 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3437 return Result.err(rfc);
3440 return func.extendUserRole(trans, userRole, false);
3443 return Result.err(Result.ERR_NotFound,"This user and role doesn't exist");
3448 path = "/authz/userRole/:user/:role",
3449 params = { "user|string|true",
3453 errorCodes = {403,404,406},
3454 text = { "Remove Role :role from User :user."
3458 public Result<Void> deleteUserRole(AuthzTrans trans, String usr, String role) {
3459 Validator val = new ServiceValidator();
3460 if(val.nullOrBlank("User", usr)
3461 .nullOrBlank("Role", role).err()) {
3462 return Result.err(Status.ERR_BadData, val.errs());
3465 boolean mayNotChange;
3466 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3468 return Result.err(rrdd);
3471 RoleDAO.Data rdd = rrdd.value;
3472 Result<NsDAO.Data> rns = ques.mayUser(trans, trans.user(), rdd, Access.write);
3474 // Make sure we don't delete the last owner of valid NS
3475 if(rns.isOKhasData() && Question.OWNER.equals(rdd.name) && ques.countOwner(trans,rdd.ns)<=1) {
3476 return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns );
3479 if(mayNotChange=rns.notOK()) {
3480 if(!trans.requested(future)) {
3481 return Result.err(rns);
3485 Result<List<UserRoleDAO.Data>> rulr;
3486 if((rulr=ques.userRoleDAO.read(trans, usr, role)).notOKorIsEmpty()) {
3487 return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not "
3488 + "Assigned to the Role [ " + role + " ]");
3491 UserRoleDAO.Data userRole = rulr.value.get(0);
3492 if(mayNotChange) { // Function exited earlier if !trans.futureRequested
3493 FutureDAO.Data fto = new FutureDAO.Data();
3494 fto.target=UserRoleDAO.TABLE;
3495 fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]";
3496 GregorianCalendar now = new GregorianCalendar();
3497 fto.start = now.getTime();
3498 fto.expires = trans.org().expiration(now, Expiration.Future).getTime();
3500 Result<String> rfc = func.createFuture(trans, fto,
3501 userRole.user+'|'+userRole.role, userRole.user, rns.value, FUTURE_OP.D);
3503 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3507 return Result.err(rfc);
3510 return ques.userRoleDAO.delete(trans, rulr.value.get(0), false);
3516 path = "/authz/userRole/:user/:role",
3517 params = {"user|string|true",
3518 "role|string|true"},
3520 errorCodes = {403,404,406},
3521 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3525 public Result<USERS> getUserInRole(AuthzTrans trans, String user, String role) {
3526 final Validator v = new ServiceValidator();
3527 if(v.role(role).nullOrBlank("User", user).err()) {
3528 return Result.err(Status.ERR_BadData,v.errs());
3531 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3532 // if (ns.notOK()) return Result.err(ns);
3534 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3535 // May calling user see by virtue of the Role
3536 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3538 return Result.err(rrdd);
3540 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3542 return Result.err(rnd);
3545 HashSet<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
3546 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readUserInRole(trans, user, role);
3548 for(UserRoleDAO.Data data : rlurd.value) {
3553 @SuppressWarnings("unchecked")
3554 USERS users = (USERS) mapper.newInstance(API.USERS);
3555 mapper.users(trans, userSet, users);
3556 return Result.ok(users);
3561 path = "/authz/users/role/:role",
3562 params = {"user|string|true",
3563 "role|string|true"},
3565 errorCodes = {403,404,406},
3566 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3570 public Result<USERS> getUsersByRole(AuthzTrans trans, String role) {
3571 final Validator v = new ServiceValidator();
3572 if(v.nullOrBlank("Role",role).err()) {
3573 return Result.err(Status.ERR_BadData,v.errs());
3576 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3577 // if (ns.notOK()) return Result.err(ns);
3579 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3580 // May calling user see by virtue of the Role
3581 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3583 return Result.err(rrdd);
3586 boolean contactOnly = false;
3587 // Allow the request of any valid user to find the contact of the NS (Owner)
3588 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3590 if(Question.OWNER.equals(rrdd.value.name)) {
3593 return Result.err(rnd);
3597 HashSet<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
3598 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role);
3600 for(UserRoleDAO.Data data : rlurd.value) {
3601 if(contactOnly) { //scrub data
3602 // Can't change actual object, or will mess up the cache.
3603 UserRoleDAO.Data scrub = new UserRoleDAO.Data();
3605 scrub.rname = data.rname;
3606 scrub.role = data.role;
3607 scrub.user = data.user;
3615 @SuppressWarnings("unchecked")
3616 USERS users = (USERS) mapper.newInstance(API.USERS);
3617 mapper.users(trans, userSet, users);
3618 return Result.ok(users);
3622 * getUsersByPermission
3626 path = "/authz/users/perm/:type/:instance/:action",
3627 params = { "type|string|true",
3628 "instance|string|true",
3629 "action|string|true"
3632 errorCodes = {404,406},
3633 text = { "List all Users that have Permission specified by :type :instance :action",
3637 public Result<USERS> getUsersByPermission(AuthzTrans trans, String type, String instance, String action) {
3638 final Validator v = new ServiceValidator();
3639 if(v.nullOrBlank("Type",type)
3640 .nullOrBlank("Instance",instance)
3641 .nullOrBlank("Action",action)
3643 return Result.err(Status.ERR_BadData,v.errs());
3646 Result<NsSplit> nss = ques.deriveNsSplit(trans, type);
3648 return Result.err(nss);
3651 Result<List<NsDAO.Data>> nsd = ques.nsDAO.read(trans, nss.value.ns);
3653 return Result.err(nsd);
3656 boolean allInstance = ASTERIX.equals(instance);
3657 boolean allAction = ASTERIX.equals(action);
3658 // Get list of roles per Permission,
3659 // Then loop through Roles to get Users
3660 // Note: Use Sets to avoid processing or responding with Duplicates
3661 Set<String> roleUsed = new HashSet<String>();
3662 Set<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
3664 if(!nss.isEmpty()) {
3665 Result<List<PermDAO.Data>> rlp = ques.permDAO.readByType(trans, nss.value.ns, nss.value.name);
3666 if(rlp.isOKhasData()) {
3667 for(PermDAO.Data pd : rlp.value) {
3668 if((allInstance || pd.instance.equals(instance)) &&
3669 (allAction || pd.action.equals(action))) {
3670 if(ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) {
3671 for(String role : pd.roles) {
3672 if(!roleUsed.contains(role)) { // avoid evaluating Role many times
3674 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role.replace('|', '.'));
3675 if(rlurd.isOKhasData()) {
3676 for(UserRoleDAO.Data urd : rlurd.value) {
3687 @SuppressWarnings("unchecked")
3688 USERS users = (USERS) mapper.newInstance(API.USERS);
3689 mapper.users(trans, userSet, users);
3690 return Result.ok(users);
3693 /***********************************
3695 ***********************************/
3697 public Result<HISTORY> getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) {
3698 final Validator v = new ServiceValidator();
3699 if(v.nullOrBlank("User",user).err()) {
3700 return Result.err(Status.ERR_BadData,v.errs());
3703 Result<NsDAO.Data> rnd;
3704 // Users may look at their own data
3705 if(trans.user().equals(user)) {
3706 // Users may look at their own data
3708 int at = user.indexOf('@');
3709 if(at>=0 && trans.org().getRealm().equals(user.substring(at+1))) {
3710 NsDAO.Data nsd = new NsDAO.Data();
3711 nsd.name = Question.domain2ns(user);
3712 rnd = ques.mayUser(trans, trans.user(), nsd, Access.read);
3714 return Result.err(rnd);
3717 rnd = ques.validNSOfDomain(trans, user);
3719 return Result.err(rnd);
3722 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3724 return Result.err(rnd);
3728 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readByUser(trans, user, yyyymm);
3730 return Result.err(resp);
3732 return mapper.history(trans, resp.value,sort);
3736 public Result<HISTORY> getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) {
3737 final Validator v = new ServiceValidator();
3738 if(v.nullOrBlank("Role",role).err()) {
3739 return Result.err(Status.ERR_BadData,v.errs());
3742 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3744 return Result.err(rrdd);
3747 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
3749 return Result.err(rnd);
3751 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, role, "role", yyyymm);
3753 return Result.err(resp);
3755 return mapper.history(trans, resp.value,sort);
3759 public Result<HISTORY> getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) {
3760 final Validator v = new ServiceValidator();
3761 if(v.nullOrBlank("Type",type)
3763 return Result.err(Status.ERR_BadData,v.errs());
3766 // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
3767 Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
3769 return Result.err(rnd);
3772 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3774 return Result.err(rnd);
3776 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, type, "perm", yyyymm);
3778 return Result.err(resp);
3780 return mapper.history(trans, resp.value,sort);
3784 public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
3785 final Validator v = new ServiceValidator();
3786 if(v.nullOrBlank("NS",ns)
3788 return Result.err(Status.ERR_BadData,v.errs());
3791 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
3793 return Result.err(rnd);
3795 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3797 return Result.err(rnd);
3800 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, ns, "ns", yyyymm);
3802 return Result.err(resp);
3804 return mapper.history(trans, resp.value,sort);
3807 /***********************************
3809 ***********************************/
3811 public Result<Void> createDelegate(final AuthzTrans trans, REQUEST base) {
3812 return createOrUpdateDelegate(trans, base, Question.Access.create);
3816 public Result<Void> updateDelegate(AuthzTrans trans, REQUEST base) {
3817 return createOrUpdateDelegate(trans, base, Question.Access.write);
3821 private Result<Void> createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) {
3822 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3823 final ServiceValidator v = new ServiceValidator();
3824 if(v.delegate(trans.org(),rd).err()) {
3825 return Result.err(Status.ERR_BadData,v.errs());
3828 final DelegateDAO.Data dd = rd.value;
3830 Result<List<DelegateDAO.Data>> ddr = ques.delegateDAO.read(trans, dd);
3831 if(access==Access.create && ddr.isOKhasData()) {
3832 return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate);
3833 } else if(access!=Access.create && ddr.notOKorIsEmpty()) {
3834 return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name());
3836 Result<Void> rv = ques.mayUser(trans, dd, access);
3841 Result<FutureDAO.Data> fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false,
3844 public String get() {
3845 StringBuilder sb = new StringBuilder();
3846 sb.append(access.name());
3847 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
3848 sb.append("Delegate ");
3849 sb.append(access==Access.create?"[":"to [");
3850 sb.append(rd.value.delegate);
3851 sb.append("] for [");
3852 sb.append(rd.value.user);
3854 return sb.toString();
3859 public Result<?> mayChange() {
3860 return Result.ok(); // Validate in code above
3866 Result<String> rfc = func.createFuture(trans, fd.value,
3867 dd.user, trans.user(),null, access==Access.create?FUTURE_OP.C:FUTURE_OP.U);
3869 return Result.err(Status.ACC_Future, "Delegate for [%s]",
3872 return Result.err(rfc);
3874 case Status.ACC_Now:
3875 if(access==Access.create) {
3876 Result<DelegateDAO.Data> rdr = ques.delegateDAO.create(trans, dd);
3880 return Result.err(rdr);
3883 return ques.delegateDAO.update(trans, dd);
3886 return Result.err(fd);
3891 public Result<Void> deleteDelegate(AuthzTrans trans, REQUEST base) {
3892 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3893 final Validator v = new ServiceValidator();
3894 if(v.notOK(rd).nullOrBlank("User", rd.value.user).err()) {
3895 return Result.err(Status.ERR_BadData,v.errs());
3898 Result<List<DelegateDAO.Data>> ddl;
3899 if((ddl=ques.delegateDAO.read(trans, rd.value)).notOKorIsEmpty()) {
3900 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3902 final DelegateDAO.Data dd = ddl.value.get(0);
3903 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3908 return ques.delegateDAO.delete(trans, dd, false);
3912 public Result<Void> deleteDelegate(AuthzTrans trans, String userName) {
3913 DelegateDAO.Data dd = new DelegateDAO.Data();
3914 final Validator v = new ServiceValidator();
3915 if(v.nullOrBlank("User", userName).err()) {
3916 return Result.err(Status.ERR_BadData,v.errs());
3919 Result<List<DelegateDAO.Data>> ddl;
3920 if((ddl=ques.delegateDAO.read(trans, dd)).notOKorIsEmpty()) {
3921 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3923 dd = ddl.value.get(0);
3924 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3929 return ques.delegateDAO.delete(trans, dd, false);
3933 public Result<DELGS> getDelegatesByUser(AuthzTrans trans, String user) {
3934 final Validator v = new ServiceValidator();
3935 if(v.nullOrBlank("User", user).err()) {
3936 return Result.err(Status.ERR_BadData,v.errs());
3939 DelegateDAO.Data ddd = new DelegateDAO.Data();
3941 ddd.delegate = null;
3942 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3944 return Result.err(rv);
3947 TimeTaken tt = trans.start("Get delegates for a user", Env.SUB);
3949 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO.read(trans, user);
3951 if (dbDelgs.isOKhasData()) {
3952 return mapper.delegate(dbDelgs.value);
3954 return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user);
3962 public Result<DELGS> getDelegatesByDelegate(AuthzTrans trans, String delegate) {
3963 final Validator v = new ServiceValidator();
3964 if(v.nullOrBlank("Delegate", delegate).err()) {
3965 return Result.err(Status.ERR_BadData,v.errs());
3968 DelegateDAO.Data ddd = new DelegateDAO.Data();
3969 ddd.user = delegate;
3970 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3972 return Result.err(rv);
3975 TimeTaken tt = trans.start("Get users for a delegate", Env.SUB);
3977 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO.readByDelegate(trans, delegate);
3979 if (dbDelgs.isOKhasData()) {
3980 return mapper.delegate(dbDelgs.value);
3982 return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate);
3989 /***********************************
3991 ***********************************/
3992 private static final String APPR_FMT = "actor=%s, action=%s, operation=\"%s\", requestor=%s, delegator=%s";
3994 public Result<Void> updateApproval(AuthzTrans trans, APPROVALS approvals) {
3995 Result<List<ApprovalDAO.Data>> rlad = mapper.approvals(approvals);
3997 return Result.err(rlad);
3999 int numApprs = rlad.value.size();
4001 return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating");
4003 int numProcessed = 0;
4004 String user = trans.user();
4006 Result<List<ApprovalDAO.Data>> curr;
4007 Lookup<List<ApprovalDAO.Data>> apprByTicket=null;
4008 for(ApprovalDAO.Data updt : rlad.value) {
4009 if(updt.ticket!=null) {
4010 curr = ques.approvalDAO.readByTicket(trans, updt.ticket);
4011 if(curr.isOKhasData()) {
4012 final List<ApprovalDAO.Data> add = curr.value;
4013 apprByTicket = new Lookup<List<ApprovalDAO.Data>>() { // Store a Pre-Lookup
4015 public List<ApprovalDAO.Data> get(AuthzTrans trans, Object ... noop) {
4020 } else if(updt.id!=null) {
4021 curr = ques.approvalDAO.read(trans, updt);
4022 } else if(updt.approver!=null) {
4023 curr = ques.approvalDAO.readByApprover(trans, updt.approver);
4025 return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update");
4028 if(curr.isOKhasData()) {
4029 Map<String, Result<List<DelegateDAO.Data>>> delegateCache = new HashMap<String, Result<List<DelegateDAO.Data>>>();
4030 Map<UUID, FutureDAO.Data> futureCache = new HashMap<UUID, FutureDAO.Data>();
4031 FutureDAO.Data hasDeleted = new FutureDAO.Data();
4033 for(ApprovalDAO.Data cd : curr.value) {
4034 if("pending".equals(cd.status)) {
4035 // Check for right record. Need ID, or (Ticket&Trans.User==Appr)
4037 boolean delegatedAction = ques.isDelegated(trans, user, cd.approver, delegateCache);
4038 String delegator = cd.approver;
4040 (updt.ticket!=null && user.equals(cd.approver)) ||
4041 (updt.ticket!=null && delegatedAction)) {
4042 if(updt.ticket.equals(cd.ticket)) {
4043 Changed ch = new Changed();
4044 cd.id = ch.changed(cd.id,updt.id);
4045 // cd.ticket = changed(cd.ticket,updt.ticket);
4046 cd.user = ch.changed(cd.user,updt.user);
4047 cd.approver = ch.changed(cd.approver,updt.approver);
4048 cd.type = ch.changed(cd.type,updt.type);
4049 cd.status = ch.changed(cd.status,updt.status);
4050 cd.memo = ch.changed(cd.memo,updt.memo);
4051 cd.operation = ch.changed(cd.operation,updt.operation);
4052 cd.updated = ch.changed(cd.updated,updt.updated==null?new Date():updt.updated);
4053 if(updt.status.equals("denied")) {
4054 cd.last_notified = null;
4056 if(cd.ticket!=null) {
4057 FutureDAO.Data fdd = futureCache.get(cd.ticket);
4058 if(fdd==null) { // haven't processed ticket yet
4059 Result<FutureDAO.Data> rfdd = ques.futureDAO.readPrimKey(trans, cd.ticket);
4061 fdd = rfdd.value; // null is ok
4065 futureCache.put(cd.ticket, fdd); // processed this Ticket... don't do others on this ticket
4067 if(fdd==hasDeleted) { // YES, by Object
4069 cd.status = "ticketDeleted";
4070 ch.hasChanged(true);
4072 FUTURE_OP fop = FUTURE_OP.toFO(cd.operation);
4074 trans.info().printf("Approval Status %s is not actionable",cd.status);
4075 } else if(apprByTicket!=null) {
4076 Result<OP_STATUS> rv = func.performFutureOp(trans, fop, fdd, apprByTicket,func.urDBLookup);
4080 if (delegatedAction) {
4081 trans.audit().printf(APPR_FMT,user,updt.status,cd.memo,cd.user,delegator);
4083 futureCache.put(cd.ticket, hasDeleted);
4087 ch.hasChanged(true);
4088 trans.audit().printf(APPR_FMT,user,rv.value.desc(),cd.memo,cd.user,delegator);
4089 futureCache.put(cd.ticket, hasDeleted);
4094 trans.info().log(rv.toString());
4101 if(ch.hasChanged()) {
4102 ques.approvalDAO.update(trans, cd, true);
4111 if(numApprs==numProcessed) {
4114 return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed");
4118 private static class Changed {
4119 private boolean hasChanged = false;
4121 public<T> T changed(T src, T proposed) {
4122 if(proposed==null || (src!=null && src.equals(proposed))) {
4129 public void hasChanged(boolean b) {
4133 public boolean hasChanged() {
4139 public Result<APPROVALS> getApprovalsByUser(AuthzTrans trans, String user) {
4140 final Validator v = new ServiceValidator();
4141 if(v.nullOrBlank("User", user).err()) {
4142 return Result.err(Status.ERR_BadData,v.errs());
4145 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByUser(trans, user);
4147 return mapper.approvals(rapd.value);
4149 return Result.err(rapd);
4154 public Result<APPROVALS> getApprovalsByTicket(AuthzTrans trans, String ticket) {
4155 final Validator v = new ServiceValidator();
4156 if(v.nullOrBlank("Ticket", ticket).err()) {
4157 return Result.err(Status.ERR_BadData,v.errs());
4161 uuid = UUID.fromString(ticket);
4162 } catch (IllegalArgumentException e) {
4163 return Result.err(Status.ERR_BadData,e.getMessage());
4166 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByTicket(trans, uuid);
4168 return mapper.approvals(rapd.value);
4170 return Result.err(rapd);
4175 public Result<APPROVALS> getApprovalsByApprover(AuthzTrans trans, String approver) {
4176 final Validator v = new ServiceValidator();
4177 if(v.nullOrBlank("Approver", approver).err()) {
4178 return Result.err(Status.ERR_BadData,v.errs());
4181 List<ApprovalDAO.Data> listRapds = new ArrayList<ApprovalDAO.Data>();
4183 Result<List<ApprovalDAO.Data>> myRapd = ques.approvalDAO.readByApprover(trans, approver);
4184 if(myRapd.notOK()) {
4185 return Result.err(myRapd);
4188 listRapds.addAll(myRapd.value);
4190 Result<List<DelegateDAO.Data>> delegatedFor = ques.delegateDAO.readByDelegate(trans, approver);
4191 if (delegatedFor.isOK()) {
4192 for (DelegateDAO.Data dd : delegatedFor.value) {
4193 if (dd.expires.after(new Date())) {
4194 String delegator = dd.user;
4195 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByApprover(trans, delegator);
4197 for (ApprovalDAO.Data d : rapd.value) {
4198 if (!d.user.equals(trans.user())) {
4207 return mapper.approvals(listRapds);
4211 * @see org.onap.aaf.auth.service.AuthzService#clearCache(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
4214 public Result<Void> cacheClear(AuthzTrans trans, String cname) {
4215 if(ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4216 return ques.clearCache(trans,cname);
4218 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4219 trans.user(),ROOT_NS,CACHE,cname);
4223 * @see org.onap.aaf.auth.service.AuthzService#cacheClear(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.Integer)
4226 public Result<Void> cacheClear(AuthzTrans trans, String cname, int[] segment) {
4227 if(ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4228 Result<Void> v=null;
4229 for(int i: segment) {
4230 v=ques.cacheClear(trans,cname,i);
4236 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4237 trans.user(),ROOT_NS,CACHE,cname);
4241 * @see org.onap.aaf.auth.service.AuthzService#dbReset(org.onap.aaf.auth.env.test.AuthzTrans)
4244 public void dbReset(AuthzTrans trans) {
4245 ques.historyDAO.reportPerhapsReset(trans, null);