1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
23 package org.onap.aaf.authz.service;
\r
25 import static org.onap.aaf.authz.layer.Result.OK;
\r
26 import static org.onap.aaf.cssa.rserv.HttpMethods.DELETE;
\r
27 import static org.onap.aaf.cssa.rserv.HttpMethods.GET;
\r
28 import static org.onap.aaf.cssa.rserv.HttpMethods.POST;
\r
29 import static org.onap.aaf.cssa.rserv.HttpMethods.PUT;
\r
31 import java.io.IOException;
\r
32 import java.util.ArrayList;
\r
33 import java.util.Collection;
\r
34 import java.util.Collections;
\r
35 import java.util.Comparator;
\r
36 import java.util.Date;
\r
37 import java.util.GregorianCalendar;
\r
38 import java.util.HashMap;
\r
39 import java.util.HashSet;
\r
40 import java.util.List;
\r
41 import java.util.Map;
\r
42 import java.util.Set;
\r
43 import java.util.TreeMap;
\r
44 import java.util.UUID;
\r
46 import javax.servlet.http.HttpServletRequest;
\r
48 import org.onap.aaf.authz.common.Define;
\r
49 import org.onap.aaf.authz.env.AuthzTrans;
\r
50 import org.onap.aaf.authz.layer.Result;
\r
51 import org.onap.aaf.authz.org.Executor;
\r
52 import org.onap.aaf.authz.org.Organization;
\r
53 import org.onap.aaf.authz.org.Organization.Expiration;
\r
54 import org.onap.aaf.authz.org.Organization.Identity;
\r
55 import org.onap.aaf.authz.org.Organization.Policy;
\r
56 import org.onap.aaf.authz.service.mapper.Mapper;
\r
57 import org.onap.aaf.authz.service.mapper.Mapper.API;
\r
58 import org.onap.aaf.authz.service.validation.Validator;
\r
59 import org.onap.aaf.cssa.rserv.doc.ApiDoc;
\r
60 import org.onap.aaf.dao.DAOException;
\r
61 import org.onap.aaf.dao.aaf.cass.ApprovalDAO;
\r
62 import org.onap.aaf.dao.aaf.cass.CertDAO;
\r
63 import org.onap.aaf.dao.aaf.cass.CredDAO;
\r
64 import org.onap.aaf.dao.aaf.cass.DelegateDAO;
\r
65 import org.onap.aaf.dao.aaf.cass.FutureDAO;
\r
66 import org.onap.aaf.dao.aaf.cass.HistoryDAO;
\r
67 import org.onap.aaf.dao.aaf.cass.Namespace;
\r
68 import org.onap.aaf.dao.aaf.cass.NsDAO;
\r
69 import org.onap.aaf.dao.aaf.cass.NsSplit;
\r
70 import org.onap.aaf.dao.aaf.cass.NsType;
\r
71 import org.onap.aaf.dao.aaf.cass.PermDAO;
\r
72 import org.onap.aaf.dao.aaf.cass.RoleDAO;
\r
73 import org.onap.aaf.dao.aaf.cass.Status;
\r
74 import org.onap.aaf.dao.aaf.cass.UserRoleDAO;
\r
75 import org.onap.aaf.dao.aaf.cass.NsDAO.Data;
\r
76 import org.onap.aaf.dao.aaf.hl.CassExecutor;
\r
77 import org.onap.aaf.dao.aaf.hl.Function;
\r
78 import org.onap.aaf.dao.aaf.hl.Question;
\r
79 import org.onap.aaf.dao.aaf.hl.Question.Access;
\r
81 import org.onap.aaf.cadi.principal.BasicPrincipal;
\r
82 import org.onap.aaf.inno.env.Env;
\r
83 import org.onap.aaf.inno.env.TimeTaken;
\r
84 import org.onap.aaf.inno.env.util.Chrono;
\r
85 import org.onap.aaf.inno.env.util.Split;
\r
87 import aaf.v2_0.CredRequest;
\r
90 * AuthzCassServiceImpl implements AuthzCassService for
\r
102 * @param <APPROVALS>
\r
104 public class AuthzCassServiceImpl <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS>
\r
105 implements AuthzService <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> {
\r
107 private Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
\r
109 public Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper() {return mapper;}
\r
111 private static final String ASTERIX = "*";
\r
112 private static final String CACHE = "cache";
\r
114 private final Question ques;
\r
115 private final Function func;
\r
117 public AuthzCassServiceImpl(AuthzTrans trans, Mapper<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper,Question question) {
\r
118 this.ques = question;
\r
119 func = new Function(trans, question);
\r
120 this.mapper = mapper;
\r
124 /***********************************
\r
126 ***********************************/
\r
129 * @throws DAOException
\r
130 * @see org.onap.aaf.authz.service.AuthzService#createNS(org.onap.aaf.authz.env.AuthzTrans, java.lang.String, java.lang.String)
\r
134 path = "/authz/ns",
\r
136 expectedCode = 201,
\r
137 errorCodes = { 403,404,406,409 },
\r
138 text = { "Namespace consists of: ",
\r
139 "<ul><li>name - What you want to call this Namespace</li>",
\r
140 "<li>responsible(s) - Person(s) who receive Notifications and approves Requests ",
\r
141 "regarding this Namespace. Companies have Policies as to who may take on ",
\r
142 "this Responsibility. Separate multiple identities with commas</li>",
\r
143 "<li>admin(s) - Person(s) who are allowed to make changes on the namespace, ",
\r
144 "including creating Roles, Permissions and Credentials. Separate multiple ",
\r
145 "identities with commas</li></ul>",
\r
146 "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ",
\r
147 "created with parent credentials (i.e. To create com.myCompany.myApp, you must ",
\r
148 "be an admin of com.myCompany or com"
\r
152 public Result<Void> createNS(final AuthzTrans trans, REQUEST from, NsType type) {
\r
153 final Result<Namespace> rnamespace = mapper.ns(trans, from);
\r
154 final Validator v = new Validator();
\r
155 if(v.ns(rnamespace).err()) {
\r
156 return Result.err(Status.ERR_BadData,v.errs());
\r
158 final Namespace namespace = rnamespace.value;
\r
159 final Result<NsDAO.Data> parentNs = ques.deriveNs(trans,namespace.name);
\r
160 if(parentNs.notOK()) {
\r
161 return Result.err(parentNs);
\r
164 if(namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed
\r
165 return func.createNS(trans, namespace, false);
\r
168 Result<FutureDAO.Data> fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true,
\r
169 new Mapper.Memo() {
\r
171 public String get() {
\r
172 return "Create Namespace [" + namespace.name + ']';
\r
176 private Result<NsDAO.Data> rnd;
\r
178 public Result<?> mayChange() {
\r
180 rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write);
\r
185 switch(fd.status) {
\r
187 Result<List<Identity>> rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, "C");
\r
189 return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name);
\r
191 return Result.err(rfc);
\r
193 case Status.ACC_Now:
\r
194 return func.createNS(trans, namespace, false);
\r
196 return Result.err(fd);
\r
202 path = "/authz/ns/:ns/admin/:id",
\r
203 params = { "ns|string|true",
\r
206 expectedCode = 201,
\r
207 errorCodes = { 403,404,406,409 },
\r
208 text = { "Add an Identity :id to the list of Admins for the Namespace :ns",
\r
209 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" }
\r
212 public Result<Void> addAdminNS(AuthzTrans trans, String ns, String id) {
\r
213 return func.addUserRole(trans, id, ns,Question.ADMIN);
\r
218 path = "/authz/ns/:ns/admin/:id",
\r
219 params = { "ns|string|true",
\r
222 expectedCode = 200,
\r
223 errorCodes = { 403,404 },
\r
224 text = { "Remove an Identity :id from the list of Admins for the Namespace :ns",
\r
225 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" }
\r
228 public Result<Void> delAdminNS(AuthzTrans trans, String ns, String id) {
\r
229 return func.delAdmin(trans,ns,id);
\r
234 path = "/authz/ns/:ns/responsible/:id",
\r
235 params = { "ns|string|true",
\r
238 expectedCode = 201,
\r
239 errorCodes = { 403,404,406,409 },
\r
240 text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns",
\r
241 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" }
\r
244 public Result<Void> addResponsibleNS(AuthzTrans trans, String ns, String id) {
\r
245 return func.addUserRole(trans,id,ns,Question.OWNER);
\r
250 path = "/authz/ns/:ns/responsible/:id",
\r
251 params = { "ns|string|true",
\r
254 expectedCode = 200,
\r
255 errorCodes = { 403,404 },
\r
256 text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns",
\r
257 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)",
\r
258 "Note: A namespace must have at least 1 responsible party"
\r
262 public Result<Void> delResponsibleNS(AuthzTrans trans, String ns, String id) {
\r
263 return func.delOwner(trans,ns,id);
\r
267 * @see org.onap.aaf.authz.service.AuthzService#applyModel(org.onap.aaf.authz.env.AuthzTrans, java.lang.Object)
\r
271 path = "/authz/ns/:ns/attrib/:key/:value",
\r
272 params = { "ns|string|true",
\r
274 "value|string|true"},
\r
275 expectedCode = 201,
\r
276 errorCodes = { 403,404,406,409 },
\r
278 "Create an attribute in the Namespace",
\r
279 "You must be given direct permission for key by AAF"
\r
283 public Result<Void> createNsAttrib(AuthzTrans trans, String ns, String key, String value) {
\r
284 TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
\r
287 final Validator v = new Validator();
\r
288 if(v.ns(ns).err() ||
\r
289 v.key(key).err() ||
\r
290 v.value(value).err()) {
\r
291 return Result.err(Status.ERR_BadData,v.errs());
\r
294 // Check if exists already
\r
295 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
\r
296 if(rlnsd.notOKorIsEmpty()) {
\r
297 return Result.err(rlnsd);
\r
299 NsDAO.Data nsd = rlnsd.value.get(0);
\r
301 // Check for Existence
\r
302 if(nsd.attrib.get(key)!=null) {
\r
303 return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key);
\r
306 // Check if User may put
\r
307 if(!ques.isGranted(trans, trans.user(), Define.ROOT_NS, Question.ATTRIB,
\r
308 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
\r
309 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
\r
313 nsd.attrib.put(key, value);
\r
314 ques.nsDAO.dao().attribAdd(trans,ns,key,value);
\r
315 return Result.ok();
\r
323 path = "/authz/ns/attrib/:key",
\r
324 params = { "key|string|true" },
\r
325 expectedCode = 200,
\r
326 errorCodes = { 403,404 },
\r
328 "Read Attributes for Namespace"
\r
332 public Result<KEYS> readNsByAttrib(AuthzTrans trans, String key) {
\r
334 final Validator v = new Validator();
\r
335 if(v.nullOrBlank("Key",key).err()) {
\r
336 return Result.err(Status.ERR_BadData,v.errs());
\r
340 if(!ques.isGranted(trans, trans.user(), Define.ROOT_NS, Question.ATTRIB,
\r
341 ":"+trans.org().getDomain()+".*:"+key, Question.READ)) {
\r
342 return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key);
\r
345 Result<Set<String>> rsd = ques.nsDAO.dao().readNsByAttrib(trans, key);
\r
347 return Result.err(rsd);
\r
349 return mapper().keys(rsd.value);
\r
355 path = "/authz/ns/:ns/attrib/:key/:value",
\r
356 params = { "ns|string|true",
\r
357 "key|string|true"},
\r
358 expectedCode = 200,
\r
359 errorCodes = { 403,404 },
\r
361 "Update Value on an existing attribute in the Namespace",
\r
362 "You must be given direct permission for key by AAF"
\r
366 public Result<?> updateNsAttrib(AuthzTrans trans, String ns, String key, String value) {
\r
367 TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
\r
370 final Validator v = new Validator();
\r
371 if(v.ns(ns).err() ||
\r
372 v.key(key).err() ||
\r
373 v.value(value).err()) {
\r
374 return Result.err(Status.ERR_BadData,v.errs());
\r
377 // Check if exists already (NS must exist)
\r
378 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
\r
379 if(rlnsd.notOKorIsEmpty()) {
\r
380 return Result.err(rlnsd);
\r
382 NsDAO.Data nsd = rlnsd.value.get(0);
\r
384 // Check for Existence
\r
385 if(nsd.attrib.get(key)==null) {
\r
386 return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key);
\r
389 // Check if User may put
\r
390 if(!ques.isGranted(trans, trans.user(), Define.ROOT_NS, Question.ATTRIB,
\r
391 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
\r
392 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
\r
396 nsd.attrib.put(key, value);
\r
398 return ques.nsDAO.update(trans,nsd);
\r
407 path = "/authz/ns/:ns/attrib/:key",
\r
408 params = { "ns|string|true",
\r
409 "key|string|true"},
\r
410 expectedCode = 200,
\r
411 errorCodes = { 403,404 },
\r
413 "Delete an attribute in the Namespace",
\r
414 "You must be given direct permission for key by AAF"
\r
418 public Result<Void> deleteNsAttrib(AuthzTrans trans, String ns, String key) {
\r
419 TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB);
\r
422 final Validator v = new Validator();
\r
423 if(v.nullOrBlank("NS",ns).err() ||
\r
424 v.nullOrBlank("Key",key).err()) {
\r
425 return Result.err(Status.ERR_BadData,v.errs());
\r
428 // Check if exists already
\r
429 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
\r
430 if(rlnsd.notOKorIsEmpty()) {
\r
431 return Result.err(rlnsd);
\r
433 NsDAO.Data nsd = rlnsd.value.get(0);
\r
435 // Check for Existence
\r
436 if(nsd.attrib.get(key)==null) {
\r
437 return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key);
\r
440 // Check if User may del
\r
441 if(!ques.isGranted(trans, trans.user(), Define.ROOT_NS, "attrib", ":com.att.*:"+key, Access.write.name())) {
\r
442 return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key);
\r
446 nsd.attrib.remove(key);
\r
447 ques.nsDAO.dao().attribRemove(trans,ns,key);
\r
448 return Result.ok();
\r
456 path = "/authz/nss/:id",
\r
457 params = { "id|string|true" },
\r
458 expectedCode = 200,
\r
459 errorCodes = { 404,406 },
\r
461 "Lists the Admin(s), Responsible Party(s), Role(s), Permission(s)",
\r
462 "Credential(s) and Expiration of Credential(s) in Namespace :id",
\r
466 public Result<NSS> getNSbyName(AuthzTrans trans, String ns) {
\r
467 final Validator v = new Validator();
\r
468 if(v.nullOrBlank("NS", ns).err()) {
\r
469 return Result.err(Status.ERR_BadData,v.errs());
\r
472 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.read(trans, ns);
\r
474 if(rlnd.isEmpty()) {
\r
475 return Result.err(Status.ERR_NotFound, "No data found for %s",ns);
\r
477 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read);
\r
479 return Result.err(rnd);
\r
483 Namespace namespace = new Namespace(rnd.value);
\r
484 Result<List<String>> rd = func.getOwners(trans, namespace.name, false);
\r
486 namespace.owner = rd.value;
\r
488 rd = func.getAdmins(trans, namespace.name, false);
\r
490 namespace.admin = rd.value;
\r
493 NSS nss = mapper.newInstance(API.NSS);
\r
494 return mapper.nss(trans, namespace, nss);
\r
496 return Result.err(rlnd);
\r
502 path = "/authz/nss/admin/:id",
\r
503 params = { "id|string|true" },
\r
504 expectedCode = 200,
\r
505 errorCodes = { 403,404 },
\r
506 text = { "Lists all Namespaces where Identity :id is an Admin",
\r
507 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)"
\r
511 public Result<NSS> getNSbyAdmin(AuthzTrans trans, String user, boolean full) {
\r
512 final Validator v = new Validator();
\r
513 if (v.nullOrBlank("User", user).err()) {
\r
514 return Result.err(Status.ERR_BadData, v.errs());
\r
517 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".admin", full);
\r
519 return Result.err(rn);
\r
521 if (rn.isEmpty()) {
\r
522 return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user);
\r
524 NSS nss = mapper.newInstance(API.NSS);
\r
525 // Note: "loadNamespace" already validates view of Namespace
\r
526 return mapper.nss(trans, rn.value, nss);
\r
532 path = "/authz/nss/either/:id",
\r
533 params = { "id|string|true" },
\r
534 expectedCode = 200,
\r
535 errorCodes = { 403,404 },
\r
536 text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner",
\r
537 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)"
\r
541 public Result<NSS> getNSbyEither(AuthzTrans trans, String user, boolean full) {
\r
542 final Validator v = new Validator();
\r
543 if (v.nullOrBlank("User", user).err()) {
\r
544 return Result.err(Status.ERR_BadData, v.errs());
\r
547 Result<Collection<Namespace>> rn = loadNamepace(trans, user, null, full);
\r
549 return Result.err(rn);
\r
551 if (rn.isEmpty()) {
\r
552 return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user);
\r
554 NSS nss = mapper.newInstance(API.NSS);
\r
555 // Note: "loadNamespace" already validates view of Namespace
\r
556 return mapper.nss(trans, rn.value, nss);
\r
559 private Result<Collection<Namespace>> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) {
\r
560 Result<List<UserRoleDAO.Data>> urd = ques.userRoleDAO.readByUser(trans, user);
\r
561 if(urd.notOKorIsEmpty()) {
\r
562 return Result.err(urd);
\r
564 Map<String, Namespace> lm = new HashMap<String,Namespace>();
\r
565 Map<String, Namespace> other = full || endsWith==null?null:new TreeMap<String,Namespace>();
\r
566 for(UserRoleDAO.Data urdd : urd.value) {
\r
568 if(endsWith==null || urdd.role.endsWith(endsWith)) {
\r
569 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
\r
570 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
\r
572 Namespace namespace = lm.get(nsd.value.name);
\r
573 if(namespace==null) {
\r
574 namespace = new Namespace(nsd.value);
\r
575 lm.put(namespace.name,namespace);
\r
577 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
\r
579 namespace.admin=rls.value;
\r
582 rls = func.getOwners(trans, namespace.name, false);
\r
584 namespace.owner=rls.value;
\r
588 } else { // Shortened version. Only Namespace Info available from Role.
\r
589 if(Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) {
\r
590 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
\r
591 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
\r
593 Namespace namespace = lm.get(nsd.value.name);
\r
594 if(namespace==null) {
\r
596 namespace = other.remove(nsd.value.name);
\r
598 if(namespace==null) {
\r
599 namespace = new Namespace(nsd.value);
\r
600 namespace.admin=new ArrayList<String>();
\r
601 namespace.owner=new ArrayList<String>();
\r
603 if(endsWith==null || urdd.role.endsWith(endsWith)) {
\r
604 lm.put(namespace.name,namespace);
\r
606 other.put(namespace.name,namespace);
\r
609 if(Question.OWNER.equals(urdd.rname)) {
\r
610 namespace.owner.add(urdd.user);
\r
612 namespace.admin.add(urdd.user);
\r
618 return Result.ok(lm.values());
\r
623 path = "/authz/nss/responsible/:id",
\r
624 params = { "id|string|true" },
\r
625 expectedCode = 200,
\r
626 errorCodes = { 403,404 },
\r
627 text = { "Lists all Namespaces where Identity :id is a Responsible Party",
\r
628 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)"
\r
632 public Result<NSS> getNSbyResponsible(AuthzTrans trans, String user, boolean full) {
\r
633 final Validator v = new Validator();
\r
634 if (v.nullOrBlank("User", user).err()) {
\r
635 return Result.err(Status.ERR_BadData, v.errs());
\r
637 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".owner",full);
\r
639 return Result.err(rn);
\r
641 if (rn.isEmpty()) {
\r
642 return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user);
\r
644 NSS nss = mapper.newInstance(API.NSS);
\r
645 // Note: "loadNamespace" prevalidates
\r
646 return mapper.nss(trans, rn.value, nss);
\r
651 path = "/authz/nss/children/:id",
\r
652 params = { "id|string|true" },
\r
653 expectedCode = 200,
\r
654 errorCodes = { 403,404 },
\r
655 text = { "Lists all Child Namespaces of Namespace :id",
\r
656 "Note: This is not a cached read"
\r
660 public Result<NSS> getNSsChildren(AuthzTrans trans, String parent) {
\r
661 final Validator v = new Validator();
\r
662 if(v.nullOrBlank("NS", parent).err()) {
\r
663 return Result.err(Status.ERR_BadData,v.errs());
\r
666 Result<NsDAO.Data> rnd = ques.deriveNs(trans, parent);
\r
668 return Result.err(rnd);
\r
670 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
672 return Result.err(rnd);
\r
675 Set<Namespace> lm = new HashSet<Namespace>();
\r
676 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.dao().getChildren(trans, parent);
\r
678 if(rlnd.isEmpty()) {
\r
679 return Result.err(Status.ERR_NotFound, "No data found for %s",parent);
\r
681 for(NsDAO.Data ndd : rlnd.value) {
\r
682 Namespace namespace = new Namespace(ndd);
\r
683 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
\r
685 namespace.admin=rls.value;
\r
688 rls = func.getOwners(trans, namespace.name, false);
\r
690 namespace.owner=rls.value;
\r
695 NSS nss = mapper.newInstance(API.NSS);
\r
696 return mapper.nss(trans,lm, nss);
\r
698 return Result.err(rlnd);
\r
705 path = "/authz/ns",
\r
707 expectedCode = 200,
\r
708 errorCodes = { 403,404,406 },
\r
709 text = { "Replace the Current Description of a Namespace with a new one"
\r
713 public Result<Void> updateNsDescription(AuthzTrans trans, REQUEST from) {
\r
714 final Result<Namespace> nsd = mapper.ns(trans, from);
\r
715 final Validator v = new Validator();
\r
716 if(v.ns(nsd).err()) {
\r
717 return Result.err(Status.ERR_BadData,v.errs());
\r
719 if(v.nullOrBlank("description", nsd.value.description).err()) {
\r
720 return Result.err(Status.ERR_BadData,v.errs());
\r
723 Namespace namespace = nsd.value;
\r
724 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.read(trans, namespace.name);
\r
726 if(rlnd.notOKorIsEmpty()) {
\r
727 return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name);
\r
730 if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) {
\r
731 return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name);
\r
734 Result<Void> rdr = ques.nsDAO.dao().addDescription(trans, namespace.name, namespace.description);
\r
736 return Result.ok();
\r
738 return Result.err(rdr);
\r
744 * @throws DAOException
\r
745 * @see org.onap.aaf.authz.service.AuthzService#deleteNS(org.onap.aaf.authz.env.AuthzTrans, java.lang.String, java.lang.String)
\r
749 path = "/authz/ns/:ns",
\r
750 params = { "ns|string|true" },
\r
751 expectedCode = 200,
\r
752 errorCodes = { 403,404,424 },
\r
753 text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ",
\r
754 "are still credentials associated with them, but they can be deleted by setting ",
\r
755 "the \"force\" property. To do this: Add 'force=true' as a query parameter",
\r
756 "<p>WARNING: Using force will delete all credentials attached to this namespace. Use with care.</p>"
\r
757 + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted,"
\r
758 + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted "
\r
759 + "at or below Application Scope"
\r
763 public Result<Void> deleteNS(AuthzTrans trans, String ns) {
\r
764 return func.deleteNS(trans, ns);
\r
768 /***********************************
\r
770 ***********************************/
\r
774 * @see org.onap.aaf.authz.service.AuthzService#createOrUpdatePerm(org.onap.aaf.authz.env.AuthzTrans, java.lang.Object, boolean, java.lang.String, java.lang.String, java.lang.String, java.util.List, java.util.List)
\r
778 path = "/authz/perm",
\r
780 expectedCode = 201,
\r
781 errorCodes = {403,404,406,409},
\r
782 text = { "Permission consists of:",
\r
783 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
\r
784 + "is being protected</li>",
\r
785 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
\r
786 + " instance of the type</li>",
\r
787 "<li>action - what kind of action is allowed</li></ul>",
\r
788 "Note: instance and action can be an *"
\r
792 public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {
\r
793 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
\r
794 final Validator v = new Validator(trans);
\r
795 if(v.perm(newPd).err()) {
\r
796 return Result.err(Status.ERR_BadData,v.errs());
\r
799 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
\r
800 new Mapper.Memo() {
\r
802 public String get() {
\r
803 return "Create Permission [" +
\r
804 newPd.value.fullType() + '|' +
\r
805 newPd.value.instance + '|' +
\r
806 newPd.value.action + ']';
\r
810 private Result<NsDAO.Data> nsd;
\r
812 public Result<?> mayChange() {
\r
814 nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
\r
819 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, newPd.value.ns);
\r
820 if(nsr.notOKorIsEmpty()) {
\r
821 return Result.err(nsr);
\r
823 switch(fd.status) {
\r
825 Result<List<Identity>> rfc = func.createFuture(trans,fd.value,
\r
826 newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
\r
831 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
\r
834 newPd.value.instance,
\r
835 newPd.value.action);
\r
837 return Result.err(rfc);
\r
839 case Status.ACC_Now:
\r
840 return func.createPerm(trans, newPd.value, true);
\r
842 return Result.err(fd);
\r
848 path = "/authz/perms/:type",
\r
849 params = {"type|string|true"},
\r
850 expectedCode = 200,
\r
851 errorCodes = { 404,406 },
\r
852 text = { "List All Permissions that match the :type element of the key" }
\r
855 public Result<PERMS> getPermsByType(AuthzTrans trans, final String permType) {
\r
856 final Validator v = new Validator();
\r
857 if(v.nullOrBlank("PermType", permType).err()) {
\r
858 return Result.err(Status.ERR_BadData,v.errs());
\r
861 Result<List<PermDAO.Data>> rlpd = ques.getPermsByType(trans, permType);
\r
863 return Result.err(rlpd);
\r
866 // We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper?
\r
867 // Result<NsDAO.Data> r;
\r
868 // if((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r);
\r
870 PERMS perms = mapper.newInstance(API.PERMS);
\r
871 if(!rlpd.isEmpty()) {
\r
872 // Note: Mapper will restrict what can be viewed
\r
873 return mapper.perms(trans, rlpd.value, perms, true);
\r
875 return Result.ok(perms);
\r
880 path = "/authz/perms/:type/:instance/:action",
\r
881 params = {"type|string|true",
\r
882 "instance|string|true",
\r
883 "action|string|true"},
\r
884 expectedCode = 200,
\r
885 errorCodes = { 404,406 },
\r
886 text = { "List Permissions that match key; :type, :instance and :action" }
\r
889 public Result<PERMS> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
\r
890 final Validator v = new Validator();
\r
891 if(v.nullOrBlank("PermType", type).err()
\r
892 || v.nullOrBlank("PermInstance", instance).err()
\r
893 || v.nullOrBlank("PermAction", action).err()) {
\r
894 return Result.err(Status.ERR_BadData,v.errs());
\r
897 Result<List<PermDAO.Data>> rlpd = ques.getPermsByName(trans, type, instance, action);
\r
899 return Result.err(rlpd);
\r
902 PERMS perms = mapper.newInstance(API.PERMS);
\r
903 if(!rlpd.isEmpty()) {
\r
904 // Note: Mapper will restrict what can be viewed
\r
905 return mapper.perms(trans, rlpd.value, perms, true);
\r
907 return Result.ok(perms);
\r
912 path = "/authz/perms/user/:user",
\r
913 params = {"user|string|true"},
\r
914 expectedCode = 200,
\r
915 errorCodes = { 404,406 },
\r
916 text = { "List All Permissions that match user :user",
\r
917 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>"}
\r
920 public Result<PERMS> getPermsByUser(AuthzTrans trans, String user) {
\r
921 final Validator v = new Validator();
\r
922 if(v.nullOrBlank("User", user).err()) {
\r
923 return Result.err(Status.ERR_BadData,v.errs());
\r
926 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user, trans.forceRequested());
\r
928 return Result.err(rlpd);
\r
931 PERMS perms = mapper.newInstance(API.PERMS);
\r
933 if(rlpd.isEmpty()) {
\r
934 return Result.ok(perms);
\r
936 // Note: Mapper will restrict what can be viewed
\r
937 // if user is the same as that which is looked up, no filtering is required
\r
938 return mapper.perms(trans, rlpd.value,
\r
940 !user.equals(trans.user()));
\r
945 path = "/authz/perms/user/:user",
\r
946 params = {"user|string|true"},
\r
947 expectedCode = 200,
\r
948 errorCodes = { 404,406 },
\r
949 text = { "List All Permissions that match user :user",
\r
950 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
\r
952 "Present Queries as one or more Permissions (see ContentType Links below for format).",
\r
954 "If the Caller is Granted this specific Permission, and the Permission is valid",
\r
955 " for the User, it will be included in response Permissions, along with",
\r
956 " all the normal permissions on the 'GET' version of this call. If it is not",
\r
957 " valid, or Caller does not have permission to see, it will be removed from the list",
\r
959 " *Note: This design allows you to make one call for all expected permissions",
\r
960 " The permission to be included MUST be:",
\r
961 " <user namespace>.access|:<ns|role|perm>[:key]|<create|read|write>",
\r
963 " com.att.myns.access|:ns|write",
\r
964 " com.att.myns.access|:role:myrole|create",
\r
965 " com.att.myns.access|:perm:mytype:myinstance:myaction|read",
\r
970 public Result<PERMS> getPermsByUser(AuthzTrans trans, PERMS _perms, String user) {
\r
971 PERMS perms = _perms;
\r
972 final Validator v = new Validator();
\r
973 if(v.nullOrBlank("User", user).err()) {
\r
974 return Result.err(Status.ERR_BadData,v.errs());
\r
978 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,trans.forceRequested());
\r
980 return Result.err(rlpd);
\r
984 1) See if allowed to query
\r
985 2) See if User is allowed
\r
987 Result<List<PermDAO.Data>> in = mapper.perms(trans, perms);
\r
988 if(in.isOKhasData()) {
\r
989 List<PermDAO.Data> out = rlpd.value;
\r
991 for(PermDAO.Data pdd : in.value) {
\r
993 if("access".equals(pdd.type)) {
\r
994 Access access = Access.valueOf(pdd.action);
\r
995 String[] mdkey = Split.splitTrim(':',pdd.instance);
\r
996 if(mdkey.length>1) {
\r
997 String type = mdkey[1];
\r
998 if("role".equals(type)) {
\r
999 if(mdkey.length>2) {
\r
1000 RoleDAO.Data rdd = new RoleDAO.Data();
\r
1002 rdd.name=mdkey[2];
\r
1003 ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK();
\r
1005 } else if("perm".equals(type)) {
\r
1006 if(mdkey.length>4) { // also need instance/action
\r
1007 PermDAO.Data p = new PermDAO.Data();
\r
1010 p.instance=mdkey[3];
\r
1011 p.action=mdkey[4];
\r
1012 ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK();
\r
1014 } else if("ns".equals(type)) {
\r
1015 NsDAO.Data ndd = new NsDAO.Data();
\r
1017 ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK();
\r
1027 perms = mapper.newInstance(API.PERMS);
\r
1028 if(rlpd.isEmpty()) {
\r
1029 return Result.ok(perms);
\r
1031 // Note: Mapper will restrict what can be viewed
\r
1032 // if user is the same as that which is looked up, no filtering is required
\r
1033 return mapper.perms(trans, rlpd.value,
\r
1035 !user.equals(trans.user()));
\r
1040 path = "/authz/perms/role/:role",
\r
1041 params = {"role|string|true"},
\r
1042 expectedCode = 200,
\r
1043 errorCodes = { 404,406 },
\r
1044 text = { "List All Permissions that are granted to :role" }
\r
1047 public Result<PERMS> getPermsByRole(AuthzTrans trans,String role) {
\r
1048 final Validator v = new Validator();
\r
1049 if(v.nullOrBlank("Role", role).err()) {
\r
1050 return Result.err(Status.ERR_BadData,v.errs());
\r
1053 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques,role);
\r
1054 if(rrdd.notOK()) {
\r
1055 return Result.err(rrdd);
\r
1058 Result<NsDAO.Data> r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
\r
1060 return Result.err(r);
\r
1063 PERMS perms = mapper.newInstance(API.PERMS);
\r
1065 Result<List<PermDAO.Data>> rlpd = ques.getPermsByRole(trans, role, trans.forceRequested());
\r
1066 if(rlpd.isOKhasData()) {
\r
1067 // Note: Mapper will restrict what can be viewed
\r
1068 return mapper.perms(trans, rlpd.value, perms, true);
\r
1070 return Result.ok(perms);
\r
1075 path = "/authz/perms/ns/:ns",
\r
1076 params = {"ns|string|true"},
\r
1077 expectedCode = 200,
\r
1078 errorCodes = { 404,406 },
\r
1079 text = { "List All Permissions that are in Namespace :ns" }
\r
1082 public Result<PERMS> getPermsByNS(AuthzTrans trans,String ns) {
\r
1083 final Validator v = new Validator();
\r
1084 if(v.nullOrBlank("NS", ns).err()) {
\r
1085 return Result.err(Status.ERR_BadData,v.errs());
\r
1088 Result<NsDAO.Data> rnd = ques.deriveNs(trans, ns);
\r
1090 return Result.err(rnd);
\r
1093 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
1095 return Result.err(rnd);
\r
1098 Result<List<PermDAO.Data>> rlpd = ques.permDAO.readNS(trans, ns);
\r
1099 if(rlpd.notOK()) {
\r
1100 return Result.err(rlpd);
\r
1103 PERMS perms = mapper.newInstance(API.PERMS);
\r
1104 if(!rlpd.isEmpty()) {
\r
1105 // Note: Mapper will restrict what can be viewed
\r
1106 return mapper.perms(trans, rlpd.value,perms, true);
\r
1108 return Result.ok(perms);
\r
1113 path = "/authz/perm/:type/:instance/:action",
\r
1114 params = {"type|string|true",
\r
1115 "instance|string|true",
\r
1116 "action|string|true"},
\r
1117 expectedCode = 200,
\r
1118 errorCodes = { 404,406, 409 },
\r
1119 text = { "Rename the Permission referenced by :type :instance :action, and "
\r
1120 + "rename (copy/delete) to the Permission described in PermRequest" }
\r
1123 public Result<Void> renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) {
\r
1124 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
\r
1125 final Validator v = new Validator(trans);
\r
1126 if(v.perm(newPd).err()) {
\r
1127 return Result.err(Status.ERR_BadData,v.errs());
\r
1130 if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) {
\r
1131 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
\r
1132 newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action);
\r
1135 Result<NsSplit> nss = ques.deriveNsSplit(trans, origType);
\r
1136 Result<List<PermDAO.Data>> origRlpd = ques.permDAO.read(trans, nss.value.ns, nss.value.name, origInstance, origAction);
\r
1138 if(origRlpd.notOKorIsEmpty()) {
\r
1139 return Result.err(Status.ERR_PermissionNotFound,
\r
1140 "Permission [%s|%s|%s] does not exist",
\r
1141 origType,origInstance,origAction);
\r
1144 PermDAO.Data origPd = origRlpd.value.get(0);
\r
1146 if (!origPd.ns.equals(newPd.value.ns)) {
\r
1147 return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " +
\r
1148 "<new type> must start with [" + origPd.ns + "]");
\r
1151 if ( origPd.type.equals(newPd.value.type) &&
\r
1152 origPd.action.equals(newPd.value.action) &&
\r
1153 origPd.instance.equals(newPd.value.instance) ) {
\r
1154 return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission");
\r
1157 Set<String> origRoles = origPd.roles(false);
\r
1158 if (!origRoles.isEmpty()) {
\r
1159 Set<String> roles = newPd.value.roles(true);
\r
1160 for (String role : origPd.roles) {
\r
1165 newPd.value.description = origPd.description;
\r
1167 Result<Void> rv = null;
\r
1169 rv = func.createPerm(trans, newPd.value, false);
\r
1171 rv = func.deletePerm(trans, origPd, true, false);
\r
1178 path = "/authz/perm",
\r
1180 expectedCode = 200,
\r
1181 errorCodes = { 404,406 },
\r
1182 text = { "Add Description Data to Perm" }
\r
1185 public Result<Void> updatePermDescription(AuthzTrans trans, REQUEST from) {
\r
1186 final Result<PermDAO.Data> pd = mapper.perm(trans, from);
\r
1187 final Validator v = new Validator(trans);
\r
1188 if(v.perm(pd).err()) {
\r
1189 return Result.err(Status.ERR_BadData,v.errs());
\r
1191 if(v.nullOrBlank("description", pd.value.description).err()) {
\r
1192 return Result.err(Status.ERR_BadData,v.errs());
\r
1194 final PermDAO.Data perm = pd.value;
\r
1195 if(ques.permDAO.read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) {
\r
1196 return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist",
\r
1197 perm.ns,perm.type,perm.instance,perm.action);
\r
1200 if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) {
\r
1201 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
\r
1202 perm.ns,perm.type,perm.instance,perm.action);
\r
1205 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, pd.value.ns);
\r
1206 if(nsr.notOKorIsEmpty()) {
\r
1207 return Result.err(nsr);
\r
1210 Result<Void> rdr = ques.permDAO.addDescription(trans, perm.ns, perm.type, perm.instance,
\r
1211 perm.action, perm.description);
\r
1213 return Result.ok();
\r
1215 return Result.err(rdr);
\r
1222 path = "/authz/role/perm",
\r
1224 expectedCode = 201,
\r
1225 errorCodes = {403,404,406,409},
\r
1226 text = { "Set a permission's roles to roles given" }
\r
1230 public Result<Void> resetPermRoles(final AuthzTrans trans, REQUEST rreq) {
\r
1231 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
\r
1232 if(updt.notOKorIsEmpty()) {
\r
1233 return Result.err(updt);
\r
1236 final Validator v = new Validator(trans);
\r
1237 if(v.perm(updt).err()) {
\r
1238 return Result.err(Status.ERR_BadData,v.errs());
\r
1241 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
\r
1242 if (nsd.notOK()) {
\r
1243 return Result.err(nsd);
\r
1246 // Read full set to get CURRENT values
\r
1247 Result<List<PermDAO.Data>> rcurr = ques.permDAO.read(trans,
\r
1250 updt.value.instance,
\r
1251 updt.value.action);
\r
1253 if(rcurr.notOKorIsEmpty()) {
\r
1254 return Result.err(Status.ERR_PermissionNotFound,
\r
1255 "Permission [%s.%s|%s|%s] does not exist",
\r
1256 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
\r
1259 // Create a set of Update Roles, which are in Internal Format
\r
1260 Set<String> updtRoles = new HashSet<String>();
\r
1261 Result<NsSplit> nss;
\r
1262 for(String role : updt.value.roles(false)) {
\r
1263 nss = ques.deriveNsSplit(trans, role);
\r
1265 updtRoles.add(nss.value.ns + '|' + nss.value.name);
\r
1267 trans.error().log(nss.errorString());
\r
1271 Result<Void> rv = null;
\r
1273 for(PermDAO.Data curr : rcurr.value) {
\r
1274 Set<String> currRoles = curr.roles(false);
\r
1275 // must add roles to this perm, and add this perm to each role
\r
1276 // in the update, but not in the current
\r
1277 for (String role : updtRoles) {
\r
1278 if (!currRoles.contains(role)) {
\r
1279 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
\r
1280 if(key.isOKhasData()) {
\r
1281 Result<List<RoleDAO.Data>> rrd = ques.roleDAO.read(trans, key.value);
\r
1282 if(rrd.isOKhasData()) {
\r
1283 for(RoleDAO.Data r : rrd.value) {
\r
1284 rv = func.addPermToRole(trans, r, curr, false);
\r
1285 if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) {
\r
1286 return Result.err(rv);
\r
1290 return Result.err(rrd);
\r
1295 // similarly, must delete roles from this perm, and delete this perm from each role
\r
1296 // in the update, but not in the current
\r
1297 for (String role : currRoles) {
\r
1298 if (!updtRoles.contains(role)) {
\r
1299 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
\r
1300 if(key.isOKhasData()) {
\r
1301 Result<List<RoleDAO.Data>> rdd = ques.roleDAO.read(trans, key.value);
\r
1302 if(rdd.isOKhasData()) {
\r
1303 for(RoleDAO.Data r : rdd.value) {
\r
1304 rv = func.delPermFromRole(trans, r, curr, true);
\r
1305 if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) {
\r
1306 return Result.err(rv);
\r
1314 return rv==null?Result.ok():rv;
\r
1319 path = "/authz/perm",
\r
1321 expectedCode = 200,
\r
1322 errorCodes = { 404,406 },
\r
1323 text = { "Delete the Permission referenced by PermKey.",
\r
1324 "You cannot normally delete a permission which is still granted to roles,",
\r
1325 "however the \"force\" property allows you to do just that. To do this: Add",
\r
1326 "'force=true' as a query parameter.",
\r
1327 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>" }
\r
1330 public Result<Void> deletePerm(final AuthzTrans trans, REQUEST from) {
\r
1331 Result<PermDAO.Data> pd = mapper.perm(trans, from);
\r
1333 return Result.err(pd);
\r
1335 final Validator v = new Validator(trans);
\r
1336 if(v.nullOrBlank(pd.value).err()) {
\r
1337 return Result.err(Status.ERR_BadData,v.errs());
\r
1339 final PermDAO.Data perm = pd.value;
\r
1340 if (ques.permDAO.read(trans, perm).notOKorIsEmpty()) {
\r
1341 return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
\r
1342 perm.ns,perm.type,perm.instance,perm.action );
\r
1345 Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
\r
1346 new Mapper.Memo() {
\r
1348 public String get() {
\r
1349 return "Delete Permission [" + perm.fullPerm() + ']';
\r
1353 private Result<NsDAO.Data> nsd;
\r
1355 public Result<?> mayChange() {
\r
1357 nsd = ques.mayUser(trans, trans.user(), perm, Access.write);
\r
1363 switch(fd.status) {
\r
1365 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, perm.ns);
\r
1366 if(nsr.notOKorIsEmpty()) {
\r
1367 return Result.err(nsr);
\r
1370 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
1371 perm.encode(), trans.user(),nsr.value.get(0),"D");
\r
1373 return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode());
\r
1375 return Result.err(rfc);
\r
1377 case Status.ACC_Now:
\r
1378 return func.deletePerm(trans,perm,trans.forceRequested(), false);
\r
1380 return Result.err(fd);
\r
1386 path = "/authz/perm/:name/:type/:action",
\r
1387 params = {"type|string|true",
\r
1388 "instance|string|true",
\r
1389 "action|string|true"},
\r
1390 expectedCode = 200,
\r
1391 errorCodes = { 404,406 },
\r
1392 text = { "Delete the Permission referenced by :type :instance :action",
\r
1393 "You cannot normally delete a permission which is still granted to roles,",
\r
1394 "however the \"force\" property allows you to do just that. To do this: Add",
\r
1395 "'force=true' as a query parameter",
\r
1396 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>"}
\r
1399 public Result<Void> deletePerm(AuthzTrans trans, String type, String instance, String action) {
\r
1400 final Validator v = new Validator(trans);
\r
1401 if(v.nullOrBlank("Type",type)
\r
1402 .nullOrBlank("Instance",instance)
\r
1403 .nullOrBlank("Action",action)
\r
1405 return Result.err(Status.ERR_BadData,v.errs());
\r
1408 Result<PermDAO.Data> pd = ques.permFrom(trans, type, instance, action);
\r
1410 return func.deletePerm(trans, pd.value, trans.forceRequested(), false);
\r
1412 return Result.err(pd);
\r
1416 /***********************************
\r
1418 ***********************************/
\r
1421 path = "/authz/role",
\r
1423 expectedCode = 201,
\r
1424 errorCodes = {403,404,406,409},
\r
1427 "Roles are part of Namespaces",
\r
1429 "<ul><li> org.osaaf - A Possible root Namespace for maintaining AAF</li>",
\r
1430 "Roles do not include implied permissions for an App. Instead, they contain explicit Granted Permissions by any Namespace in AAF (See Permissions)",
\r
1431 "Restrictions on Role Names:",
\r
1432 "<ul><li>Must start with valid Namespace name, terminated by . (dot/period)</li>",
\r
1433 "<li>Allowed Characters are a-zA-Z0-9._-</li>",
\r
1434 "<li>role names are Case Sensitive</li></ul>",
\r
1435 "The right questions to ask for defining and populating a Role in AAF, therefore, are:",
\r
1436 "<ul><li>'What Job Function does this represent?'</li>",
\r
1437 "<li>'Does this person perform this Job Function?'</li></ul>" }
\r
1441 public Result<Void> createRole(final AuthzTrans trans, REQUEST from) {
\r
1442 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
\r
1443 final Validator v = new Validator(trans);
\r
1444 if(v.role(rd).err()) {
\r
1445 return Result.err(Status.ERR_BadData,v.errs());
\r
1447 final RoleDAO.Data role = rd.value;
\r
1448 if(ques.roleDAO.read(trans, role.ns, role.name).isOKhasData()) {
\r
1449 return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists");
\r
1452 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
\r
1453 new Mapper.Memo() {
\r
1455 public String get() {
\r
1456 return "Create Role [" +
\r
1457 rd.value.fullName() +
\r
1462 private Result<NsDAO.Data> nsd;
\r
1464 public Result<?> mayChange() {
\r
1466 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
\r
1472 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
\r
1473 if(nsr.notOKorIsEmpty()) {
\r
1474 return Result.err(nsr);
\r
1477 switch(fd.status) {
\r
1479 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
1480 role.encode(), trans.user(),nsr.value.get(0),"C");
\r
1482 return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing",
\r
1486 return Result.err(rfc);
\r
1488 case Status.ACC_Now:
\r
1489 Result<RoleDAO.Data> rdr = ques.roleDAO.create(trans, role);
\r
1491 return Result.ok();
\r
1493 return Result.err(rdr);
\r
1496 return Result.err(fd);
\r
1501 * @see org.onap.aaf.authz.service.AuthzService#getRolesByName(org.onap.aaf.authz.env.AuthzTrans, java.lang.String)
\r
1505 path = "/authz/roles/:role",
\r
1506 params = {"role|string|true"},
\r
1507 expectedCode = 200,
\r
1508 errorCodes = {404,406},
\r
1509 text = { "List Roles that match :role",
\r
1510 "Note: You must have permission to see any given role"
\r
1514 public Result<ROLES> getRolesByName(AuthzTrans trans, String role) {
\r
1515 final Validator v = new Validator();
\r
1516 if(v.nullOrBlank("Role", role).err()) {
\r
1517 return Result.err(Status.ERR_BadData,v.errs());
\r
1520 // Determine if User can ask this question
\r
1521 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
1522 if(rrdd.isOKhasData()) {
\r
1523 Result<NsDAO.Data> r;
\r
1524 if((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) {
\r
1525 return Result.err(r);
\r
1528 return Result.err(rrdd);
\r
1532 Result<List<RoleDAO.Data>> rlrd = ques.getRolesByName(trans, role);
\r
1534 // Note: Mapper will restrict what can be viewed
\r
1535 ROLES roles = mapper.newInstance(API.ROLES);
\r
1536 return mapper.roles(trans, rlrd.value, roles, true);
\r
1538 return Result.err(rlrd);
\r
1543 * @see org.onap.aaf.authz.service.AuthzService#getRolesByUser(org.onap.aaf.authz.env.AuthzTrans, java.lang.String)
\r
1547 path = "/authz/roles/user/:name",
\r
1548 params = {"name|string|true"},
\r
1549 expectedCode = 200,
\r
1550 errorCodes = {404,406},
\r
1551 text = { "List all Roles that match user :name",
\r
1552 "'user' must be expressed as full identity (ex: id@full.domain.com)",
\r
1553 "Note: You must have permission to see any given role"
\r
1558 public Result<ROLES> getRolesByUser(AuthzTrans trans, String user) {
\r
1559 final Validator v = new Validator();
\r
1560 if(v.nullOrBlank("User", user).err()) {
\r
1561 return Result.err(Status.ERR_BadData,v.errs());
\r
1564 ROLES roles = mapper.newInstance(API.ROLES);
\r
1565 // Get list of roles per user, then add to Roles as we go
\r
1566 Result<List<RoleDAO.Data>> rlrd;
\r
1567 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, user);
\r
1568 if(rlurd.isOKhasData()) {
\r
1569 for(UserRoleDAO.Data urd : rlurd.value ) {
\r
1570 rlrd = ques.roleDAO.read(trans, urd.ns,urd.rname);
\r
1571 // Note: Mapper will restrict what can be viewed
\r
1572 // if user is the same as that which is looked up, no filtering is required
\r
1573 if(rlrd.isOKhasData()) {
\r
1574 mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user()));
\r
1578 return Result.ok(roles);
\r
1583 * @see org.onap.aaf.authz.service.AuthzService#getRolesByNS(org.onap.aaf.authz.env.AuthzTrans, java.lang.String)
\r
1587 path = "/authz/roles/ns/:ns",
\r
1588 params = {"ns|string|true"},
\r
1589 expectedCode = 200,
\r
1590 errorCodes = {404,406},
\r
1591 text = { "List all Roles for the Namespace :ns",
\r
1592 "Note: You must have permission to see any given role"
\r
1597 public Result<ROLES> getRolesByNS(AuthzTrans trans, String ns) {
\r
1598 final Validator v = new Validator();
\r
1599 if(v.nullOrBlank("NS", ns).err()) {
\r
1600 return Result.err(Status.ERR_BadData,v.errs());
\r
1603 // check if user is allowed to view NS
\r
1604 Result<NsDAO.Data> rnsd = ques.deriveNs(trans, ns);
\r
1605 if(rnsd.notOK()) {
\r
1606 return Result.err(rnsd);
\r
1608 rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read);
\r
1609 if(rnsd.notOK()) {
\r
1610 return Result.err(rnsd);
\r
1613 TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB);
\r
1615 ROLES roles = mapper.newInstance(API.ROLES);
\r
1616 // Get list of roles per user, then add to Roles as we go
\r
1617 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.readNS(trans, ns);
\r
1619 if(!rlrd.isEmpty()) {
\r
1620 // Note: Mapper doesn't need to restrict what can be viewed, because we did it already.
\r
1621 mapper.roles(trans,rlrd.value,roles,false);
\r
1623 return Result.ok(roles);
\r
1625 return Result.err(rlrd);
\r
1634 * @see org.onap.aaf.authz.service.AuthzService#getRolesByNS(org.onap.aaf.authz.env.AuthzTrans, java.lang.String)
\r
1638 path = "/authz/roles/name/:name",
\r
1639 params = {"name|string|true"},
\r
1640 expectedCode = 200,
\r
1641 errorCodes = {404,406},
\r
1642 text = { "List all Roles for only the Name of Role (without Namespace)",
\r
1643 "Note: You must have permission to see any given role"
\r
1647 public Result<ROLES> getRolesByNameOnly(AuthzTrans trans, String name) {
\r
1648 final Validator v = new Validator();
\r
1649 if(v.nullOrBlank("Name", name).err()) {
\r
1650 return Result.err(Status.ERR_BadData,v.errs());
\r
1653 // User Mapper to make sure user is allowed to view NS
\r
1655 TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB);
\r
1657 ROLES roles = mapper.newInstance(API.ROLES);
\r
1658 // Get list of roles per user, then add to Roles as we go
\r
1659 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.readName(trans, name);
\r
1661 if(!rlrd.isEmpty()) {
\r
1662 // Note: Mapper will restrict what can be viewed
\r
1663 mapper.roles(trans,rlrd.value,roles,true);
\r
1665 return Result.ok(roles);
\r
1667 return Result.err(rlrd);
\r
1676 path = "/authz/roles/perm/:type/:instance/:action",
\r
1677 params = {"type|string|true",
\r
1678 "instance|string|true",
\r
1679 "action|string|true"},
\r
1680 expectedCode = 200,
\r
1681 errorCodes = {404,406},
\r
1682 text = { "Find all Roles containing the given Permission." +
\r
1683 "Permission consists of:",
\r
1684 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
\r
1685 + "is being protected</li>",
\r
1686 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
\r
1687 + " instance of the type</li>",
\r
1688 "<li>action - what kind of action is allowed</li></ul>",
\r
1689 "Notes: instance and action can be an *",
\r
1690 " You must have permission to see any given role"
\r
1695 public Result<ROLES> getRolesByPerm(AuthzTrans trans, String type, String instance, String action) {
\r
1696 final Validator v = new Validator(trans);
\r
1697 if(v.permType(type,null)
\r
1698 .permInstance(instance)
\r
1699 .permAction(action)
\r
1701 return Result.err(Status.ERR_BadData,v.errs());
\r
1704 TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB);
\r
1706 ROLES roles = mapper.newInstance(API.ROLES);
\r
1707 // Get list of roles per user, then add to Roles as we go
\r
1708 Result<NsSplit> nsSplit = ques.deriveNsSplit(trans, type);
\r
1709 if(nsSplit.isOK()) {
\r
1710 PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action);
\r
1712 if((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) {
\r
1713 return Result.err(res);
\r
1716 Result<List<PermDAO.Data>> pdlr = ques.permDAO.read(trans, pdd);
\r
1717 if(pdlr.isOK())for(PermDAO.Data pd : pdlr.value) {
\r
1718 Result<List<RoleDAO.Data>> rlrd;
\r
1719 for(String r : pd.roles) {
\r
1720 Result<String[]> rs = RoleDAO.Data.decodeToArray(trans, ques, r);
\r
1722 rlrd = ques.roleDAO.read(trans, rs.value[0],rs.value[1]);
\r
1723 // Note: Mapper will restrict what can be viewed
\r
1724 if(rlrd.isOKhasData()) {
\r
1725 mapper.roles(trans,rlrd.value,roles,true);
\r
1731 return Result.ok(roles);
\r
1739 path = "/authz/role",
\r
1741 expectedCode = 200,
\r
1742 errorCodes = {404,406},
\r
1743 text = { "Add Description Data to a Role" }
\r
1747 public Result<Void> updateRoleDescription(AuthzTrans trans, REQUEST from) {
\r
1748 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
\r
1749 final Validator v = new Validator(trans);
\r
1750 if(v.role(rd).err()) {
\r
1751 return Result.err(Status.ERR_BadData,v.errs());
\r
1753 if(v.nullOrBlank("description", rd.value.description).err()) {
\r
1754 return Result.err(Status.ERR_BadData,v.errs());
\r
1757 final RoleDAO.Data role = rd.value;
\r
1758 if(ques.roleDAO.read(trans, role.ns, role.name).notOKorIsEmpty()) {
\r
1759 return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist");
\r
1762 if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) {
\r
1763 return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName());
\r
1766 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
\r
1767 if(nsr.notOKorIsEmpty()) {
\r
1768 return Result.err(nsr);
\r
1771 Result<Void> rdr = ques.roleDAO.addDescription(trans, role.ns, role.name, role.description);
\r
1773 return Result.ok();
\r
1775 return Result.err(rdr);
\r
1782 path = "/authz/role/perm",
\r
1784 expectedCode = 201,
\r
1785 errorCodes = {403,404,406,409},
\r
1786 text = { "Grant a Permission to a Role",
\r
1787 "Permission consists of:",
\r
1788 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
\r
1789 + "is being protected</li>",
\r
1790 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
\r
1791 + " instance of the type</li>",
\r
1792 "<li>action - what kind of action is allowed</li></ul>",
\r
1793 "Note: instance and action can be an *",
\r
1794 "Note: Using the \"force\" property will create the Permission, if it doesn't exist AND the requesting " +
\r
1795 " ID is allowed to create. It will then grant",
\r
1796 " the permission to the role in one step. To do this: add 'force=true' as a query parameter."
\r
1801 public Result<Void> addPermToRole(final AuthzTrans trans, REQUEST rreq) {
\r
1802 // Translate Request into Perm and Role Objects
\r
1803 final Result<PermDAO.Data> rpd = mapper.permFromRPRequest(trans, rreq);
\r
1804 if(rpd.notOKorIsEmpty()) {
\r
1805 return Result.err(rpd);
\r
1807 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
\r
1808 if(rrd.notOKorIsEmpty()) {
\r
1809 return Result.err(rrd);
\r
1812 // Validate Role and Perm values
\r
1813 final Validator v = new Validator(trans);
\r
1814 if(v.perm(rpd.value)
\r
1817 return Result.err(Status.ERR_BadData,v.errs());
\r
1820 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.read(trans, rrd.value.ns, rrd.value.name);
\r
1821 if(rlrd.notOKorIsEmpty()) {
\r
1822 return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName());
\r
1825 // Check Status of Data in DB (does it exist)
\r
1826 Result<List<PermDAO.Data>> rlpd = ques.permDAO.read(trans, rpd.value.ns,
\r
1827 rpd.value.type, rpd.value.instance, rpd.value.action);
\r
1828 PermDAO.Data createPerm = null; // if not null, create first
\r
1829 if(rlpd.notOKorIsEmpty()) { // Permission doesn't exist
\r
1830 if(trans.forceRequested()) {
\r
1831 // Remove roles from perm data object so we just create the perm here
\r
1832 createPerm = rpd.value;
\r
1833 createPerm.roles.clear();
\r
1835 return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist",
\r
1836 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action);
\r
1839 if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) {
\r
1840 return Result.err(Status.ERR_ConflictAlreadyExists,
\r
1841 "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]",
\r
1842 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action,
\r
1843 rrd.value.ns,rrd.value.name
\r
1849 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals
\r
1850 new Mapper.Memo() {
\r
1852 public String get() {
\r
1853 return "Grant Permission [" + rpd.value.fullPerm() + ']' +
\r
1854 " to Role [" + rrd.value.fullName() + "]";
\r
1858 private Result<NsDAO.Data> nsd;
\r
1860 public Result<?> mayChange() {
\r
1862 nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
\r
1867 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rpd.value.ns);
\r
1868 if(nsr.notOKorIsEmpty()) {
\r
1869 return Result.err(nsr);
\r
1871 switch(fd.status) {
\r
1873 Result<List<Identity>> rfc = func.createFuture(trans,fd.value,
\r
1874 rpd.value.fullPerm(),
\r
1879 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
\r
1882 rpd.value.instance,
\r
1883 rpd.value.action);
\r
1885 return Result.err(rfc);
\r
1887 case Status.ACC_Now:
\r
1888 Result<Void> rv = null;
\r
1889 if(createPerm!=null) {// has been validated for creating
\r
1890 rv = func.createPerm(trans, createPerm, false);
\r
1892 if(rv==null || rv.isOK()) {
\r
1893 rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
\r
1897 return Result.err(fd);
\r
1903 * Create a RoleDAO.Data
\r
1905 * @param roleFullName
\r
1910 path = "/authz/role/:role/perm",
\r
1911 params = {"role|string|true"},
\r
1912 expectedCode = 200,
\r
1913 errorCodes = {404,406},
\r
1914 text = { "Ungrant a permission from Role :role" }
\r
1918 public Result<Void> delPermFromRole(final AuthzTrans trans, REQUEST rreq) {
\r
1919 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
\r
1920 if(updt.notOKorIsEmpty()) {
\r
1921 return Result.err(updt);
\r
1923 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
\r
1924 if(rrd.notOKorIsEmpty()) {
\r
1925 return Result.err(rrd);
\r
1928 final Validator v = new Validator(trans);
\r
1929 if(v.nullOrBlank(updt.value)
\r
1930 .nullOrBlank(rrd.value)
\r
1932 return Result.err(Status.ERR_BadData,v.errs());
\r
1935 Result<List<PermDAO.Data>> rlpd = ques.permDAO.read(trans, updt.value.ns, updt.value.type,
\r
1936 updt.value.instance, updt.value.action);
\r
1938 if(rlpd.notOKorIsEmpty()) {
\r
1939 return Result.err(Status.ERR_PermissionNotFound,
\r
1940 "Permission [%s.%s|%s|%s] does not exist",
\r
1941 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
\r
1944 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, updt.value,true, // allow ungrants requests
\r
1945 new Mapper.Memo() {
\r
1947 public String get() {
\r
1948 return "Ungrant Permission [" + updt.value.fullPerm() + ']' +
\r
1949 " from Role [" + rrd.value.fullName() + "]";
\r
1953 private Result<NsDAO.Data> nsd;
\r
1955 public Result<?> mayChange() {
\r
1957 nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
\r
1962 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, updt.value.ns);
\r
1963 if(nsr.notOKorIsEmpty()) {
\r
1964 return Result.err(nsr);
\r
1966 switch(fd.status) {
\r
1968 Result<List<Identity>> rfc = func.createFuture(trans,fd.value,
\r
1969 updt.value.fullPerm(),
\r
1975 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
\r
1978 updt.value.instance,
\r
1979 updt.value.action);
\r
1981 return Result.err(rfc);
\r
1983 case Status.ACC_Now:
\r
1984 return func.delPermFromRole(trans, rrd.value, updt.value, false);
\r
1986 return Result.err(fd);
\r
1992 path = "/authz/role/:role",
\r
1993 params = {"role|string|true"},
\r
1994 expectedCode = 200,
\r
1995 errorCodes = {404,406},
\r
1996 text = { "Delete the Role named :role"}
\r
2000 public Result<Void> deleteRole(AuthzTrans trans, String role) {
\r
2001 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
\r
2002 if(rrdd.isOKhasData()) {
\r
2003 final Validator v = new Validator(trans);
\r
2004 if(v.nullOrBlank(rrdd.value).err()) {
\r
2005 return Result.err(Status.ERR_BadData,v.errs());
\r
2007 return func.deleteRole(trans, rrdd.value, false, false);
\r
2009 return Result.err(rrdd);
\r
2015 path = "/authz/role",
\r
2017 expectedCode = 200,
\r
2018 errorCodes = { 404,406 },
\r
2019 text = { "Delete the Role referenced by RoleKey",
\r
2020 "You cannot normally delete a role which still has permissions granted or users assigned to it,",
\r
2021 "however the \"force\" property allows you to do just that. To do this: Add 'force=true'",
\r
2022 "as a query parameter.",
\r
2023 "<p>WARNING: Using force will remove all users and permission from this role. Use with care.</p>"}
\r
2027 public Result<Void> deleteRole(final AuthzTrans trans, REQUEST from) {
\r
2028 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
\r
2029 final Validator v = new Validator(trans);
\r
2031 return Result.err(Status.ERR_BadData,"Request does not contain Role");
\r
2033 if(v.nullOrBlank(rd.value).err()) {
\r
2034 return Result.err(Status.ERR_BadData,v.errs());
\r
2036 final RoleDAO.Data role = rd.value;
\r
2037 if(ques.roleDAO.read(trans, role).notOKorIsEmpty() && !trans.forceRequested()) {
\r
2038 return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist");
\r
2041 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
\r
2042 new Mapper.Memo() {
\r
2044 public String get() {
\r
2045 return "Delete Role [" + role.fullName() + ']'
\r
2046 + " and all attached user roles";
\r
2050 private Result<NsDAO.Data> nsd;
\r
2052 public Result<?> mayChange() {
\r
2054 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
\r
2060 switch(fd.status) {
\r
2062 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
\r
2063 if(nsr.notOKorIsEmpty()) {
\r
2064 return Result.err(nsr);
\r
2067 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
2068 role.encode(), trans.user(),nsr.value.get(0),"D");
\r
2070 return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing",
\r
2074 return Result.err(rfc);
\r
2076 case Status.ACC_Now:
\r
2077 return func.deleteRole(trans,role,trans.forceRequested(), true /*preapproved*/);
\r
2079 return Result.err(fd);
\r
2084 /***********************************
\r
2086 ***********************************/
\r
2087 private class MayCreateCred implements MayChange {
\r
2088 private Result<NsDAO.Data> nsd;
\r
2089 private AuthzTrans trans;
\r
2090 private CredDAO.Data cred;
\r
2091 private Executor exec;
\r
2093 public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) {
\r
2094 this.trans = trans;
\r
2100 public Result<?> mayChange() {
\r
2102 nsd = ques.validNSOfDomain(trans, cred.id);
\r
2104 // is Ns of CredID valid?
\r
2107 // Check Org Policy
\r
2108 if(trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) {
\r
2109 return Result.ok();
\r
2111 Result<?> rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write);
\r
2112 if(rmc.isOKhasData()) {
\r
2116 } catch (Exception e) {
\r
2117 trans.warn().log(e);
\r
2120 trans.warn().log(nsd.errorString());
\r
2122 return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns);
\r
2126 private class MayChangeCred implements MayChange {
\r
2128 private Result<NsDAO.Data> nsd;
\r
2129 private AuthzTrans trans;
\r
2130 private CredDAO.Data cred;
\r
2131 public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) {
\r
2132 this.trans = trans;
\r
2137 public Result<?> mayChange() {
\r
2138 // User can change himself (but not create)
\r
2139 if(trans.user().equals(cred.id)) {
\r
2140 return Result.ok();
\r
2143 nsd = ques.validNSOfDomain(trans, cred.id);
\r
2145 // Get the Namespace
\r
2147 if(ques.mayUser(trans, trans.user(), nsd.value,Access.write).isOK()) {
\r
2148 return Result.ok();
\r
2150 String user[] = Split.split('.',trans.user());
\r
2151 if(user.length>2) {
\r
2152 String company = user[user.length-1] + '.' + user[user.length-2];
\r
2153 if(ques.isGranted(trans, trans.user(), Define.ROOT_NS,"password",company,"reset")) {
\r
2154 return Result.ok();
\r
2158 return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns);
\r
2163 private final long DAY_IN_MILLIS = 24*3600*1000;
\r
2167 path = "/authn/cred",
\r
2169 expectedCode = 201,
\r
2170 errorCodes = {403,404,406,409},
\r
2171 text = { "A credential consists of:",
\r
2172 "<ul><li>id - the ID to create within AAF. The domain is in reverse",
\r
2173 "order of Namespace (i.e. Users of Namespace com.att.myapp would be",
\r
2174 "AB1234@myapp.att.com</li>",
\r
2175 "<li>password - Company Policy Compliant Password</li></ul>",
\r
2176 "Note: AAF does support multiple credentials with the same ID.",
\r
2177 "Check with your organization if you have this implemented."
\r
2181 public Result<Void> createUserCred(final AuthzTrans trans, REQUEST from) {
\r
2182 final String cmdDescription = ("Create User Credential");
\r
2183 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
\r
2186 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
\r
2187 if(rcred.isOKhasData()) {
\r
2188 rcred = ques.userCredSetup(trans, rcred.value);
\r
2190 final Validator v = new Validator();
\r
2192 if(v.cred(trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations
\r
2193 return Result.err(Status.ERR_BadData,v.errs());
\r
2197 // 2016-4 JG, New Behavior - If MechID is not registered with Org, deny creation
\r
2198 Identity mechID = null;
\r
2199 Organization org = trans.org();
\r
2201 mechID = org.getIdentity(trans, rcred.value.id);
\r
2202 } catch (Exception e1) {
\r
2203 trans.error().log(e1,rcred.value.id,"cannot be validated at this time");
\r
2205 if(mechID==null || !mechID.isFound()) {
\r
2206 return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName());
\r
2209 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rcred.value.ns);
\r
2210 if(nsr.notOKorIsEmpty()) {
\r
2211 return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns);
\r
2214 boolean firstID = false;
\r
2217 CassExecutor exec = new CassExecutor(trans, func);
\r
2218 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, rcred.value.id);
\r
2219 if (rlcd.isOKhasData()) {
\r
2220 if (!org.canHaveMultipleCreds(rcred.value.id)) {
\r
2221 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists");
\r
2223 for (CredDAO.Data curr : rlcd.value) {
\r
2224 if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) {
\r
2225 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'");
\r
2230 // 2016-04-12 JG If Caller is the Sponsor and is also an Owner of NS, allow without special Perm
\r
2231 String theMechID = rcred.value.id;
\r
2232 Boolean otherMechIDs = false;
\r
2233 // find out if this is the only mechID. other MechIDs mean special handling (not automated)
\r
2234 for(CredDAO.Data cd : ques.credDAO.readNS(trans,nsr.value.get(0).name).value) {
\r
2235 if(!cd.id.equals(theMechID)) {
\r
2236 otherMechIDs = true;
\r
2241 // We can say "ID does not exist" here
\r
2242 if((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) {
\r
2243 return Result.err(Status.ERR_Denied, reason);
\r
2246 } catch (Exception e) {
\r
2247 return Result.err(e);
\r
2251 mc = new MayCreateCred(trans, rcred.value, exec);
\r
2253 final CredDAO.Data cdd = rcred.value;
\r
2254 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future.
\r
2255 new Mapper.Memo() {
\r
2257 public String get() {
\r
2258 return cmdDescription + " [" +
\r
2261 + cdd.expires + ']';
\r
2266 switch(fd.status) {
\r
2268 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
2269 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
\r
2270 trans.user(), nsr.value.get(0), "C");
\r
2272 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing",
\r
2274 Integer.toString(rcred.value.type),
\r
2275 rcred.value.expires.toString());
\r
2277 return Result.err(rfc);
\r
2279 case Status.ACC_Now:
\r
2282 // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) {
\r
2283 Result<List<String>> admins = func.getAdmins(trans, nsr.value.get(0).name, false);
\r
2284 // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length
\r
2285 // Note, we only do this on First time, because of possibility of
\r
2286 // prematurely expiring a production id
\r
2287 if(admins.isOKhasData() && !admins.value.contains(trans.user())) {
\r
2288 rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime();
\r
2291 } catch (Exception e) {
\r
2292 trans.error().log(e, "While setting expiration to TempPassword");
\r
2294 Result<?>udr = ques.credDAO.create(trans, rcred.value);
\r
2296 return Result.ok();
\r
2298 return Result.err(udr);
\r
2300 return Result.err(fd);
\r
2304 return Result.err(rcred);
\r
2313 path = "/authn/creds/ns/:ns",
\r
2314 params = {"ns|string|true"},
\r
2315 expectedCode = 200,
\r
2316 errorCodes = {403,404,406},
\r
2317 text = { "Return all IDs in Namespace :ns"
\r
2321 public Result<USERS> getCredsByNS(AuthzTrans trans, String ns) {
\r
2322 final Validator v = new Validator();
\r
2323 if(v.ns(ns).err()) {
\r
2324 return Result.err(Status.ERR_BadData,v.errs());
\r
2327 // check if user is allowed to view NS
\r
2328 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
\r
2330 return Result.err(rnd);
\r
2332 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
2334 return Result.err(rnd);
\r
2337 TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB);
\r
2339 USERS users = mapper.newInstance(API.USERS);
\r
2340 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readNS(trans, ns);
\r
2343 if(!rlcd.isEmpty()) {
\r
2344 return mapper.cred(rlcd.value, users);
\r
2346 return Result.ok(users);
\r
2348 return Result.err(rlcd);
\r
2358 path = "/authn/creds/id/:ns",
\r
2359 params = {"id|string|true"},
\r
2360 expectedCode = 200,
\r
2361 errorCodes = {403,404,406},
\r
2362 text = { "Return all IDs in for ID"
\r
2363 ,"(because IDs are multiple, due to multiple Expiration Dates)"
\r
2367 public Result<USERS> getCredsByID(AuthzTrans trans, String id) {
\r
2368 final Validator v = new Validator();
\r
2369 if(v.nullOrBlank("ID",id).err()) {
\r
2370 return Result.err(Status.ERR_BadData,v.errs());
\r
2373 String ns = Question.domain2ns(id);
\r
2374 // check if user is allowed to view NS
\r
2375 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
\r
2377 return Result.err(rnd);
\r
2379 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
2381 return Result.err(rnd);
\r
2384 TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB);
\r
2386 USERS users = mapper.newInstance(API.USERS);
\r
2387 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, id);
\r
2390 if(!rlcd.isEmpty()) {
\r
2391 return mapper.cred(rlcd.value, users);
\r
2393 return Result.ok(users);
\r
2395 return Result.err(rlcd);
\r
2405 path = "/authn/certs/id/:id",
\r
2406 params = {"id|string|true"},
\r
2407 expectedCode = 200,
\r
2408 errorCodes = {403,404,406},
\r
2409 text = { "Return Cert Info for ID"
\r
2413 public Result<CERTS> getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) {
\r
2414 TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB);
\r
2416 CERTS certs = mapper.newInstance(API.CERTS);
\r
2417 Result<List<CertDAO.Data>> rlcd = ques.certDAO.readID(trans, id);
\r
2420 if(!rlcd.isEmpty()) {
\r
2421 return mapper.cert(rlcd.value, certs);
\r
2423 return Result.ok(certs);
\r
2425 return Result.err(rlcd);
\r
2435 path = "/authn/cred",
\r
2437 expectedCode = 200,
\r
2438 errorCodes = {300,403,404,406},
\r
2439 text = { "Reset a Credential Password. If multiple credentials exist for this",
\r
2440 "ID, you will need to specify which entry you are resetting in the",
\r
2441 "CredRequest object"
\r
2445 public Result<Void> changeUserCred(final AuthzTrans trans, REQUEST from) {
\r
2446 final String cmdDescription = "Update User Credential";
\r
2447 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
\r
2449 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
\r
2450 if(rcred.isOKhasData()) {
\r
2451 rcred = ques.userCredSetup(trans, rcred.value);
\r
2453 final Validator v = new Validator();
\r
2455 if(v.cred(trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations
\r
2456 return Result.err(Status.ERR_BadData,v.errs());
\r
2458 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, rcred.value.id);
\r
2459 if(rlcd.notOKorIsEmpty()) {
\r
2460 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
\r
2463 MayChange mc = new MayChangeCred(trans, rcred.value);
\r
2464 Result<?> rmc = mc.mayChange();
\r
2465 if (rmc.notOK()) {
\r
2466 return Result.err(rmc);
\r
2469 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
\r
2471 return Result.err(ri);
\r
2473 int entry = ri.value;
\r
2476 final CredDAO.Data cred = rcred.value;
\r
2478 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false,
\r
2479 new Mapper.Memo() {
\r
2481 public String get() {
\r
2482 return cmdDescription + " [" +
\r
2484 + cred.type + '|'
\r
2485 + cred.expires + ']';
\r
2490 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rcred.value.ns);
\r
2491 if(nsr.notOKorIsEmpty()) {
\r
2492 return Result.err(nsr);
\r
2495 switch(fd.status) {
\r
2497 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
2498 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
\r
2499 trans.user(), nsr.value.get(0), "U");
\r
2501 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]",
\r
2503 Integer.toString(rcred.value.type),
\r
2504 rcred.value.expires.toString());
\r
2506 return Result.err(rfc);
\r
2508 case Status.ACC_Now:
\r
2509 Result<?>udr = null;
\r
2510 // If we are Resetting Password on behalf of someone else (am not the Admin)
\r
2511 // use TempPassword Expiration time.
\r
2513 if(ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) {
\r
2514 exp = Expiration.Password;
\r
2516 exp = Expiration.TempPassword;
\r
2519 Organization org = trans.org();
\r
2520 // If user resets password in same day, we will have a primary key conflict, so subtract 1 day
\r
2521 if (rlcd.value.get(entry).expires.equals(rcred.value.expires)
\r
2522 && rlcd.value.get(entry).type==rcred.value.type) {
\r
2523 GregorianCalendar gc = org.expiration(null, exp,rcred.value.id);
\r
2524 gc = Chrono.firstMomentOfDay(gc);
\r
2525 gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay());
\r
2526 rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS);
\r
2528 rcred.value.expires = org.expiration(null,exp).getTime();
\r
2531 udr = ques.credDAO.create(trans, rcred.value);
\r
2533 udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false);
\r
2536 return Result.ok();
\r
2539 return Result.err(udr);
\r
2541 return Result.err(fd);
\r
2544 return Result.err(rcred);
\r
2552 * Codify the way to get Either Choice Needed or actual Integer from Credit Request
\r
2554 private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd) {
\r
2556 if (lcd.size() > 1) {
\r
2557 String inputOption = cr.getEntry();
\r
2558 if (inputOption == null) {
\r
2559 String message = selectCredFromList(lcd, false);
\r
2560 String[] variables = buildVariables(lcd);
\r
2561 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
\r
2563 entry = Integer.parseInt(inputOption) - 1;
\r
2565 if (entry < 0 || entry >= lcd.size()) {
\r
2566 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
\r
2569 return Result.ok(entry);
\r
2574 path = "/authn/cred/:days",
\r
2575 params = {"days|string|true"},
\r
2576 expectedCode = 200,
\r
2577 errorCodes = {300,403,404,406},
\r
2578 text = { "Extend a Credential Expiration Date. The intention of this API is",
\r
2579 "to avoid an outage in PROD due to a Credential expiring before it",
\r
2580 "can be configured correctly. Measures are being put in place ",
\r
2581 "so that this is not abused."
\r
2585 public Result<Void> extendUserCred(final AuthzTrans trans, REQUEST from, String days) {
\r
2586 TimeTaken tt = trans.start("Extend User Credential", Env.SUB);
\r
2588 Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
\r
2589 Organization org = trans.org();
\r
2590 final Validator v = new Validator();
\r
2591 if(v.notOK(cred).err() ||
\r
2592 v.nullOrBlank(cred.value.id, "Invalid ID").err() ||
\r
2593 v.user(org,cred.value.id).err()) {
\r
2594 return Result.err(Status.ERR_BadData,v.errs());
\r
2599 if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) {
\r
2600 return Result.err(Status.ERR_Policy,reason);
\r
2602 } catch (Exception e) {
\r
2604 trans.error().log(e, msg="Could not contact Organization for User Validation");
\r
2605 return Result.err(Status.ERR_Denied, msg);
\r
2608 // Get the list of Cred Entries
\r
2609 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, cred.value.id);
\r
2610 if(rlcd.notOKorIsEmpty()) {
\r
2611 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
\r
2614 //Need to do the "Pick Entry" mechanism
\r
2615 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
\r
2617 return Result.err(ri);
\r
2620 CredDAO.Data found = rlcd.value.get(ri.value);
\r
2621 CredDAO.Data cd = cred.value;
\r
2622 // Copy over the cred
\r
2623 cd.cred = found.cred;
\r
2624 cd.type = found.type;
\r
2625 cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime();
\r
2627 cred = ques.credDAO.create(trans, cd);
\r
2629 return Result.ok();
\r
2631 return Result.err(cred);
\r
2637 private String[] buildVariables(List<CredDAO.Data> value) {
\r
2638 // ensure credentials are sorted so we can fully automate Cred regression test
\r
2639 Collections.sort(value, new Comparator<CredDAO.Data>() {
\r
2641 public int compare(CredDAO.Data cred1, CredDAO.Data cred2) {
\r
2642 return cred1.expires.compareTo(cred2.expires);
\r
2645 String [] vars = new String[value.size()+1];
\r
2647 for (int i = 0; i < value.size(); i++) {
\r
2648 vars[i+1] = value.get(i).id + " " + value.get(i).type
\r
2649 + " |" + value.get(i).expires;
\r
2654 private String selectCredFromList(List<CredDAO.Data> value, boolean isDelete) {
\r
2655 StringBuilder errMessage = new StringBuilder();
\r
2656 String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:";
\r
2657 int numSpaces = value.get(0).id.length() - "Id".length();
\r
2659 errMessage.append(userPrompt + '\n');
\r
2660 errMessage.append(" Id");
\r
2661 for (int i = 0; i < numSpaces; i++) {
\r
2662 errMessage.append(' ');
\r
2664 errMessage.append(" Type Expires" + '\n');
\r
2665 for(int i=0;i<value.size();++i) {
\r
2666 errMessage.append(" %s\n");
\r
2668 errMessage.append("Run same command again with chosen entry as last parameter");
\r
2670 return errMessage.toString();
\r
2676 path = "/authn/cred",
\r
2678 expectedCode = 200,
\r
2679 errorCodes = {300,403,404,406},
\r
2680 text = { "Delete a Credential. If multiple credentials exist for this",
\r
2681 "ID, you will need to specify which entry you are deleting in the",
\r
2682 "CredRequest object."
\r
2686 public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from) {
\r
2687 final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
\r
2688 final Validator v = new Validator();
\r
2689 if(v.nullOrBlank("cred", cred.value.id).err()) {
\r
2690 return Result.err(Status.ERR_BadData,v.errs());
\r
2693 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, cred.value.id);
\r
2694 if(rlcd.notOKorIsEmpty()) {
\r
2695 // Empty Creds should have no user_roles.
\r
2696 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id);
\r
2697 if(rlurd.isOK()) {
\r
2698 for(UserRoleDAO.Data data : rlurd.value) {
\r
2699 ques.userRoleDAO.delete(trans, data, false);
\r
2702 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
\r
2704 boolean isLastCred = rlcd.value.size()==1;
\r
2706 MayChange mc = new MayChangeCred(trans,cred.value);
\r
2707 Result<?> rmc = mc.mayChange();
\r
2708 if (rmc.notOK()) {
\r
2709 return Result.err(rmc);
\r
2713 if(!trans.forceRequested()) {
\r
2714 if (rlcd.value.size() > 1) {
\r
2715 CredRequest cr = (CredRequest)from;
\r
2716 String inputOption = cr.getEntry();
\r
2717 if (inputOption == null) {
\r
2718 String message = selectCredFromList(rlcd.value, true);
\r
2719 String[] variables = buildVariables(rlcd.value);
\r
2720 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
\r
2723 entry = Integer.parseInt(inputOption) - 1;
\r
2724 } catch(NumberFormatException e) {
\r
2725 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
\r
2728 isLastCred = (entry==-1)?true:false;
\r
2730 isLastCred = true;
\r
2732 if (entry < -1 || entry >= rlcd.value.size()) {
\r
2733 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
\r
2737 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
\r
2738 new Mapper.Memo() {
\r
2740 public String get() {
\r
2741 return "Delete Credential [" +
\r
2748 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, cred.value.ns);
\r
2749 if(nsr.notOKorIsEmpty()) {
\r
2750 return Result.err(nsr);
\r
2753 switch(fd.status) {
\r
2755 Result<List<Identity>> rfc = func.createFuture(trans, fd.value, cred.value.id,
\r
2756 trans.user(), nsr.value.get(0),"D");
\r
2759 return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
\r
2761 return Result.err(rfc);
\r
2763 case Status.ACC_Now:
\r
2764 Result<?>udr = null;
\r
2765 if (!trans.forceRequested()) {
\r
2766 if(entry<0 || entry >= rlcd.value.size()) {
\r
2767 return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
\r
2769 udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false);
\r
2771 for (CredDAO.Data curr : rlcd.value) {
\r
2772 udr = ques.credDAO.delete(trans, curr, false);
\r
2773 if (udr.notOK()) {
\r
2774 return Result.err(udr);
\r
2779 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id);
\r
2780 if(rlurd.isOK()) {
\r
2781 for(UserRoleDAO.Data data : rlurd.value) {
\r
2782 ques.userRoleDAO.delete(trans, data, false);
\r
2787 return Result.ok();
\r
2789 return Result.err(udr);
\r
2791 return Result.err(fd);
\r
2798 public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
\r
2799 TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
\r
2801 // Note: Mapper assigns RAW type
\r
2802 Result<CredDAO.Data> data = mapper.cred(trans, credReq,false);
\r
2803 if(data.notOKorIsEmpty()) {
\r
2804 return Result.err(data);
\r
2806 CredDAO.Data cred = data.value; // of the Mapped Cred
\r
2807 return ques.doesUserCredMatch(trans, cred.id, cred.cred.array());
\r
2809 } catch (DAOException e) {
\r
2810 trans.error().log(e,"Error looking up cred");
\r
2811 return Result.err(Status.ERR_Denied,"Credential does not match");
\r
2819 path = "/authn/basicAuth",
\r
2821 expectedCode = 200,
\r
2822 errorCodes = { 403 },
\r
2823 text = { "Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
\r
2824 + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
\r
2825 + "security, and 403 if it does not." }
\r
2827 private void basicAuth() {
\r
2828 // This is a place holder for Documentation. The real BasicAuth API does not call Service.
\r
2833 path = "/authn/validate",
\r
2835 expectedCode = 200,
\r
2836 errorCodes = { 403 },
\r
2837 text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can "
\r
2838 + "do more than BasicAuth as Credential types exp" }
\r
2841 public Result<Date> validateBasicAuth(AuthzTrans trans, String basicAuth) {
\r
2842 //TODO how to make sure people don't use this in browsers? Do we care?
\r
2843 TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB);
\r
2845 BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm());
\r
2846 Result<Date> rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred());
\r
2847 // Note: Only want to log problem, don't want to send back to end user
\r
2851 trans.audit().log(rq.errorString());
\r
2853 } catch (Exception e) {
\r
2854 trans.warn().log(e);
\r
2858 return Result.err(Status.ERR_Denied,"Bad Basic Auth");
\r
2861 /***********************************
\r
2863 ***********************************/
\r
2866 path = "/authz/userRole",
\r
2868 expectedCode = 201,
\r
2869 errorCodes = {403,404,406,409},
\r
2870 text = { "Create a UserRole relationship (add User to Role)",
\r
2871 "A UserRole is an object Representation of membership of a Role for limited time.",
\r
2872 "If a shorter amount of time for Role ownership is required, use the 'End' field.",
\r
2873 "** Note: Owners of Namespaces will be required to revalidate users in these roles ",
\r
2874 "before Expirations expire. Namespace owners will be notified by email."
\r
2878 public Result<Void> createUserRole(final AuthzTrans trans, REQUEST from) {
\r
2879 TimeTaken tt = trans.start("Create UserRole", Env.SUB);
\r
2881 Result<UserRoleDAO.Data> urr = mapper.userRole(trans, from);
\r
2882 if(urr.notOKorIsEmpty()) {
\r
2883 return Result.err(urr);
\r
2885 final UserRoleDAO.Data userRole = urr.value;
\r
2887 final Validator v = new Validator();
\r
2888 if(v.user_role(userRole).err() ||
\r
2889 v.user(trans.org(), userRole.user).err()) {
\r
2890 return Result.err(Status.ERR_BadData,v.errs());
\r
2895 // Check if user can change first
\r
2896 Result<FutureDAO.Data> fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals
\r
2897 new Mapper.Memo() {
\r
2899 public String get() {
\r
2900 return "Add User [" + userRole.user + "] to Role [" +
\r
2906 private Result<NsDAO.Data> nsd;
\r
2908 public Result<?> mayChange() {
\r
2910 RoleDAO.Data r = RoleDAO.Data.decode(userRole);
\r
2911 nsd = ques.mayUser(trans, trans.user(), r, Access.write);
\r
2916 Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
\r
2917 if(nsr.notOKorIsEmpty()) {
\r
2918 return Result.err(nsr);
\r
2921 switch(fd.status) {
\r
2923 Result<List<Identity>> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname,
\r
2924 userRole.user, nsr.value, "C");
\r
2926 return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
\r
2931 return Result.err(rfc);
\r
2933 case Status.ACC_Now:
\r
2934 return func.addUserRole(trans, userRole);
\r
2936 return Result.err(fd);
\r
2944 * getUserRolesByRole
\r
2948 path = "/authz/userRoles/role/:role",
\r
2949 params = {"role|string|true"},
\r
2950 expectedCode = 200,
\r
2951 errorCodes = {404,406},
\r
2952 text = { "List all Users that are attached to Role specified in :role",
\r
2956 public Result<USERROLES> getUserRolesByRole(AuthzTrans trans, String role) {
\r
2957 final Validator v = new Validator(trans);
\r
2958 if(v.nullOrBlank("Role",role).err()) {
\r
2959 return Result.err(Status.ERR_BadData,v.errs());
\r
2962 Result<RoleDAO.Data> rrdd;
\r
2963 rrdd = RoleDAO.Data.decode(trans,ques,role);
\r
2964 if(rrdd.notOK()) {
\r
2965 return Result.err(rrdd);
\r
2967 // May Requester see result?
\r
2968 Result<NsDAO.Data> ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read);
\r
2970 return Result.err(ns);
\r
2973 // boolean filter = true;
\r
2974 // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user()))
\r
2975 // filter = false;
\r
2977 // Get list of roles per user, then add to Roles as we go
\r
2978 HashSet<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
\r
2979 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role);
\r
2980 if(rlurd.isOK()) {
\r
2981 for(UserRoleDAO.Data data : rlurd.value) {
\r
2982 userSet.add(data);
\r
2986 @SuppressWarnings("unchecked")
\r
2987 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
\r
2988 // Checked for permission
\r
2989 mapper.userRoles(trans, userSet, users);
\r
2990 return Result.ok(users);
\r
2993 * getUserRolesByRole
\r
2997 path = "/authz/userRoles/user/:user",
\r
2998 params = {"role|string|true"},
\r
2999 expectedCode = 200,
\r
3000 errorCodes = {404,406},
\r
3001 text = { "List all UserRoles for :user",
\r
3005 public Result<USERROLES> getUserRolesByUser(AuthzTrans trans, String user) {
\r
3006 final Validator v = new Validator(trans);
\r
3007 if(v.nullOrBlank("User",user).err()) {
\r
3008 return Result.err(Status.ERR_BadData,v.errs());
\r
3011 // Get list of roles per user, then add to Roles as we go
\r
3012 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, user);
\r
3013 if(rlurd.notOK()) {
\r
3014 return Result.err(rlurd);
\r
3016 @SuppressWarnings("unchecked")
\r
3017 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
\r
3018 // Checked for permission
\r
3019 mapper.userRoles(trans, rlurd.value, users);
\r
3020 return Result.ok(users);
\r
3026 path = "/authz/userRole/user",
\r
3028 expectedCode = 200,
\r
3029 errorCodes = {403,404,406},
\r
3030 text = { "Set a User's roles to the roles specified in the UserRoleRequest object.",
\r
3031 "WARNING: Roles supplied will be the ONLY roles attached to this user",
\r
3032 "If no roles are supplied, user's roles are reset."
\r
3036 public Result<Void> resetRolesForUser(AuthzTrans trans, REQUEST rreq) {
\r
3037 Result<UserRoleDAO.Data> rurdd = mapper.userRole(trans, rreq);
\r
3038 final Validator v = new Validator();
\r
3039 if(rurdd.notOKorIsEmpty()) {
\r
3040 return Result.err(rurdd);
\r
3042 if (v.user(trans.org(), rurdd.value.user).err()) {
\r
3043 return Result.err(Status.ERR_BadData,v.errs());
\r
3046 Set<String> currRoles = new HashSet<String>();
\r
3047 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, rurdd.value.user);
\r
3048 if(rlurd.isOK()) {
\r
3049 for(UserRoleDAO.Data data : rlurd.value) {
\r
3050 currRoles.add(data.role);
\r
3054 Result<Void> rv = null;
\r
3056 if(rurdd.value.role==null) {
\r
3057 roles = new String[0];
\r
3059 roles = rurdd.value.role.split(",");
\r
3062 for (String role : roles) {
\r
3063 if (v.role(role).err()) {
\r
3064 return Result.err(Status.ERR_BadData,v.errs());
\r
3066 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
3067 if(rrdd.notOK()) {
\r
3068 return Result.err(rrdd);
\r
3071 rurdd.value.role(rrdd.value);
\r
3073 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), rrdd.value,Access.write);
\r
3074 if (nsd.notOK()) {
\r
3075 return Result.err(nsd);
\r
3077 Result<NsDAO.Data> nsr = ques.deriveNs(trans, role);
\r
3078 if(nsr.notOKorIsEmpty()) {
\r
3079 return Result.err(nsr);
\r
3082 if(currRoles.contains(role)) {
\r
3083 currRoles.remove(role);
\r
3085 rv = func.addUserRole(trans, rurdd.value);
\r
3092 for (String role : currRoles) {
\r
3093 rurdd.value.role(trans,ques,role);
\r
3094 rv = ques.userRoleDAO.delete(trans, rurdd.value, true);
\r
3096 trans.info().log(rurdd.value.user,"/",rurdd.value.role, "expected to be deleted, but does not exist");
\r
3097 // return rv; // if it doesn't exist, don't error out
\r
3102 return Result.ok();
\r
3108 path = "/authz/userRole/role",
\r
3110 expectedCode = 200,
\r
3111 errorCodes = {403,404,406},
\r
3112 text = { "Set a Role's users to the users specified in the UserRoleRequest object.",
\r
3113 "WARNING: Users supplied will be the ONLY users attached to this role",
\r
3114 "If no users are supplied, role's users are reset."
\r
3118 public Result<Void> resetUsersForRole(AuthzTrans trans, REQUEST rreq) {
\r
3119 Result<UserRoleDAO.Data> rurdd = mapper.userRole(trans, rreq);
\r
3120 if(rurdd.notOKorIsEmpty()) {
\r
3121 return Result.err(rurdd);
\r
3123 final Validator v = new Validator();
\r
3124 if (v.user_role(rurdd.value).err()) {
\r
3125 return Result.err(Status.ERR_BadData,v.errs());
\r
3128 RoleDAO.Data rd = RoleDAO.Data.decode(rurdd.value);
\r
3130 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), rd, Access.write);
\r
3131 if (nsd.notOK()) {
\r
3132 return Result.err(nsd);
\r
3135 Result<NsDAO.Data> nsr = ques.deriveNs(trans, rurdd.value.role);
\r
3136 if(nsr.notOKorIsEmpty()) {
\r
3137 return Result.err(nsr);
\r
3140 Set<String> currUsers = new HashSet<String>();
\r
3141 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, rurdd.value.role);
\r
3142 if(rlurd.isOK()) {
\r
3143 for(UserRoleDAO.Data data : rlurd.value) {
\r
3144 currUsers.add(data.user);
\r
3148 // found when connected remotely to DEVL, can't replicate locally
\r
3149 // inconsistent errors with cmd: role user setTo [nothing]
\r
3150 // deleteUserRole --> read --> get --> cacheIdx(?)
\r
3151 // sometimes returns idx for last added user instead of user passed in
\r
3155 Result<Void> rv = null;
\r
3156 String[] users = {};
\r
3157 if (rurdd.value.user != null) {
\r
3158 users = rurdd.value.user.split(",");
\r
3161 for (String user : users) {
\r
3162 if (v.user(trans.org(), user).err()) {
\r
3163 return Result.err(Status.ERR_BadData,v.errs());
\r
3165 rurdd.value.user = user;
\r
3167 if(currUsers.contains(user)) {
\r
3168 currUsers.remove(user);
\r
3170 rv = func.addUserRole(trans, rurdd.value);
\r
3171 if (rv.notOK()) {
\r
3177 for (String user : currUsers) {
\r
3178 rurdd.value.user = user;
\r
3179 rv = ques.userRoleDAO.delete(trans, rurdd.value, true);
\r
3181 trans.info().log(rurdd.value, "expected to be deleted, but not exists");
\r
3186 return Result.ok();
\r
3191 path = "/authz/userRole/extend/:user/:role",
\r
3192 params = { "user|string|true",
\r
3193 "role|string|true"
\r
3195 expectedCode = 200,
\r
3196 errorCodes = {403,404,406},
\r
3197 text = { "Extend the Expiration of this User Role by the amount set by Organization",
\r
3198 "Requestor must be allowed to modify the role"
\r
3202 public Result<Void> extendUserRole(AuthzTrans trans, String user, String role) {
\r
3203 Organization org = trans.org();
\r
3204 final Validator v = new Validator();
\r
3205 if(v.user(org, user)
\r
3208 return Result.err(Status.ERR_BadData,v.errs());
\r
3211 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
\r
3212 if(rrdd.notOK()) {
\r
3213 return Result.err(rrdd);
\r
3216 Result<NsDAO.Data> rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write);
\r
3217 boolean mayNotChange;
\r
3218 if((mayNotChange = rcr.notOK()) && !trans.futureRequested()) {
\r
3219 return Result.err(rcr);
\r
3222 Result<List<UserRoleDAO.Data>> rr = ques.userRoleDAO.read(trans, user,role);
\r
3224 return Result.err(rr);
\r
3226 for(UserRoleDAO.Data userRole : rr.value) {
\r
3227 if(mayNotChange) { // Function exited earlier if !trans.futureRequested
\r
3228 FutureDAO.Data fto = new FutureDAO.Data();
\r
3229 fto.target=UserRoleDAO.TABLE;
\r
3230 fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]";
\r
3231 GregorianCalendar now = new GregorianCalendar();
\r
3232 fto.start = now.getTime();
\r
3233 fto.expires = org.expiration(now, Expiration.Future).getTime();
\r
3235 fto.construct = userRole.bytify();
\r
3236 } catch (IOException e) {
\r
3237 trans.error().log(e, "Error while bytifying UserRole for Future");
\r
3238 return Result.err(e);
\r
3241 Result<List<Identity>> rfc = func.createFuture(trans, fto,
\r
3242 userRole.user+'|'+userRole.role, userRole.user, rcr.value, "U");
\r
3244 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
\r
3248 return Result.err(rfc);
\r
3251 return func.extendUserRole(trans, userRole, false);
\r
3254 return Result.err(Result.ERR_NotFound,"This user and role doesn't exist");
\r
3259 path = "/authz/userRole/:user/:role",
\r
3260 params = { "user|string|true",
\r
3261 "role|string|true"
\r
3263 expectedCode = 200,
\r
3264 errorCodes = {403,404,406},
\r
3265 text = { "Remove Role :role from User :user."
\r
3269 public Result<Void> deleteUserRole(AuthzTrans trans, String usr, String role) {
\r
3270 Validator val = new Validator();
\r
3271 if(val.nullOrBlank("User", usr)
\r
3272 .nullOrBlank("Role", role).err()) {
\r
3273 return Result.err(Status.ERR_BadData, val.errs());
\r
3276 boolean mayNotChange;
\r
3277 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
\r
3278 if(rrdd.notOK()) {
\r
3279 return Result.err(rrdd);
\r
3282 RoleDAO.Data rdd = rrdd.value;
\r
3283 // Make sure we don't delete the last owner
\r
3284 if(Question.OWNER.equals(rdd.name) && ques.countOwner(trans, usr, rdd.ns)<=1) {
\r
3285 return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns );
\r
3288 Result<NsDAO.Data> rns = ques.mayUser(trans, trans.user(), rdd, Access.write);
\r
3289 if(mayNotChange=rns.notOK()) {
\r
3290 if(!trans.futureRequested()) {
\r
3291 return Result.err(rns);
\r
3295 Result<List<UserRoleDAO.Data>> rulr;
\r
3296 if((rulr=ques.userRoleDAO.read(trans, usr, role)).notOKorIsEmpty()) {
\r
3297 return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not "
\r
3298 + "Assigned to the Role [ " + role + " ]");
\r
3301 UserRoleDAO.Data userRole = rulr.value.get(0);
\r
3302 if(mayNotChange) { // Function exited earlier if !trans.futureRequested
\r
3303 FutureDAO.Data fto = new FutureDAO.Data();
\r
3304 fto.target=UserRoleDAO.TABLE;
\r
3305 fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]";
\r
3306 GregorianCalendar now = new GregorianCalendar();
\r
3307 fto.start = now.getTime();
\r
3308 fto.expires = trans.org().expiration(now, Expiration.Future).getTime();
\r
3310 Result<List<Identity>> rfc = func.createFuture(trans, fto,
\r
3311 userRole.user+'|'+userRole.role, userRole.user, rns.value, "D");
\r
3313 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
\r
3317 return Result.err(rfc);
\r
3320 return ques.userRoleDAO.delete(trans, rulr.value.get(0), false);
\r
3326 path = "/authz/userRole/:user/:role",
\r
3327 params = {"user|string|true",
\r
3328 "role|string|true"},
\r
3329 expectedCode = 200,
\r
3330 errorCodes = {403,404,406},
\r
3331 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
\r
3335 public Result<USERS> getUserInRole(AuthzTrans trans, String user, String role) {
\r
3336 final Validator v = new Validator();
\r
3337 if(v.role(role).nullOrBlank("User", user).err()) {
\r
3338 return Result.err(Status.ERR_BadData,v.errs());
\r
3341 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
\r
3342 // if (ns.notOK()) return Result.err(ns);
\r
3344 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
\r
3345 // May calling user see by virtue of the Role
\r
3346 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
3347 if(rrdd.notOK()) {
\r
3348 return Result.err(rrdd);
\r
3350 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
\r
3352 return Result.err(rnd);
\r
3355 HashSet<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
\r
3356 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readUserInRole(trans, user, role);
\r
3357 if(rlurd.isOK()) {
\r
3358 for(UserRoleDAO.Data data : rlurd.value) {
\r
3359 userSet.add(data);
\r
3363 @SuppressWarnings("unchecked")
\r
3364 USERS users = (USERS) mapper.newInstance(API.USERS);
\r
3365 mapper.users(trans, userSet, users);
\r
3366 return Result.ok(users);
\r
3371 path = "/authz/users/role/:role",
\r
3372 params = {"user|string|true",
\r
3373 "role|string|true"},
\r
3374 expectedCode = 200,
\r
3375 errorCodes = {403,404,406},
\r
3376 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
\r
3380 public Result<USERS> getUsersByRole(AuthzTrans trans, String role) {
\r
3381 final Validator v = new Validator();
\r
3382 if(v.nullOrBlank("Role",role).err()) {
\r
3383 return Result.err(Status.ERR_BadData,v.errs());
\r
3386 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
\r
3387 // if (ns.notOK()) return Result.err(ns);
\r
3389 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
\r
3390 // May calling user see by virtue of the Role
\r
3391 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
3392 if(rrdd.notOK()) {
\r
3393 return Result.err(rrdd);
\r
3395 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
\r
3397 return Result.err(rnd);
\r
3400 HashSet<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
\r
3401 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role);
\r
3402 if(rlurd.isOK()) {
\r
3403 for(UserRoleDAO.Data data : rlurd.value) {
\r
3404 userSet.add(data);
\r
3408 @SuppressWarnings("unchecked")
\r
3409 USERS users = (USERS) mapper.newInstance(API.USERS);
\r
3410 mapper.users(trans, userSet, users);
\r
3411 return Result.ok(users);
\r
3415 * getUsersByPermission
\r
3419 path = "/authz/users/perm/:type/:instance/:action",
\r
3420 params = { "type|string|true",
\r
3421 "instance|string|true",
\r
3422 "action|string|true"
\r
3424 expectedCode = 200,
\r
3425 errorCodes = {404,406},
\r
3426 text = { "List all Users that have Permission specified by :type :instance :action",
\r
3430 public Result<USERS> getUsersByPermission(AuthzTrans trans, String type, String instance, String action) {
\r
3431 final Validator v = new Validator(trans);
\r
3432 if(v.nullOrBlank("Type",type)
\r
3433 .nullOrBlank("Instance",instance)
\r
3434 .nullOrBlank("Action",action)
\r
3436 return Result.err(Status.ERR_BadData,v.errs());
\r
3439 Result<NsSplit> nss = ques.deriveNsSplit(trans, type);
\r
3441 return Result.err(nss);
\r
3444 Result<List<NsDAO.Data>> nsd = ques.nsDAO.read(trans, nss.value.ns);
\r
3445 if (nsd.notOK()) {
\r
3446 return Result.err(nsd);
\r
3449 boolean allInstance = ASTERIX.equals(instance);
\r
3450 boolean allAction = ASTERIX.equals(action);
\r
3451 // Get list of roles per Permission,
\r
3452 // Then loop through Roles to get Users
\r
3453 // Note: Use Sets to avoid processing or responding with Duplicates
\r
3454 Set<String> roleUsed = new HashSet<String>();
\r
3455 Set<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
\r
3457 if(!nss.isEmpty()) {
\r
3458 Result<List<PermDAO.Data>> rlp = ques.permDAO.readByType(trans, nss.value.ns, nss.value.name);
\r
3459 if(rlp.isOKhasData()) {
\r
3460 for(PermDAO.Data pd : rlp.value) {
\r
3461 if((allInstance || pd.instance.equals(instance)) &&
\r
3462 (allAction || pd.action.equals(action))) {
\r
3463 if(ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) {
\r
3464 for(String role : pd.roles) {
\r
3465 if(!roleUsed.contains(role)) { // avoid evaluating Role many times
\r
3466 roleUsed.add(role);
\r
3467 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role.replace('|', '.'));
\r
3468 if(rlurd.isOKhasData()) {
\r
3469 for(UserRoleDAO.Data urd : rlurd.value) {
\r
3480 @SuppressWarnings("unchecked")
\r
3481 USERS users = (USERS) mapper.newInstance(API.USERS);
\r
3482 mapper.users(trans, userSet, users);
\r
3483 return Result.ok(users);
\r
3486 /***********************************
\r
3488 ***********************************/
\r
3490 public Result<HISTORY> getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) {
\r
3491 final Validator v = new Validator(trans);
\r
3492 if(v.nullOrBlank("User",user).err()) {
\r
3493 return Result.err(Status.ERR_BadData,v.errs());
\r
3496 Result<NsDAO.Data> rnd;
\r
3497 // Users may look at their own data
\r
3498 if(trans.user().equals(user)) {
\r
3499 // Users may look at their own data
\r
3501 int at = user.indexOf('@');
\r
3502 if(at>=0 && trans.org().getRealm().equals(user.substring(at+1))) {
\r
3503 NsDAO.Data nsd = new NsDAO.Data();
\r
3504 nsd.name = Question.domain2ns(user);
\r
3505 rnd = ques.mayUser(trans, trans.user(), nsd, Access.read);
\r
3507 return Result.err(rnd);
\r
3510 rnd = ques.validNSOfDomain(trans, user);
\r
3512 return Result.err(rnd);
\r
3515 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
3517 return Result.err(rnd);
\r
3521 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readByUser(trans, user, yyyymm);
\r
3522 if(resp.notOK()) {
\r
3523 return Result.err(resp);
\r
3525 return mapper.history(trans, resp.value,sort);
\r
3529 public Result<HISTORY> getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) {
\r
3530 final Validator v = new Validator(trans);
\r
3531 if(v.nullOrBlank("Role",role).err()) {
\r
3532 return Result.err(Status.ERR_BadData,v.errs());
\r
3535 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
3536 if(rrdd.notOK()) {
\r
3537 return Result.err(rrdd);
\r
3540 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
\r
3542 return Result.err(rnd);
\r
3544 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, role, "role", yyyymm);
\r
3545 if(resp.notOK()) {
\r
3546 return Result.err(resp);
\r
3548 return mapper.history(trans, resp.value,sort);
\r
3552 public Result<HISTORY> getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) {
\r
3553 final Validator v = new Validator(trans);
\r
3554 if(v.nullOrBlank("Type",type)
\r
3556 return Result.err(Status.ERR_BadData,v.errs());
\r
3559 // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
\r
3560 Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
\r
3562 return Result.err(rnd);
\r
3565 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
3567 return Result.err(rnd);
\r
3569 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, type, "perm", yyyymm);
\r
3570 if(resp.notOK()) {
\r
3571 return Result.err(resp);
\r
3573 return mapper.history(trans, resp.value,sort);
\r
3577 public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
\r
3578 final Validator v = new Validator(trans);
\r
3579 if(v.nullOrBlank("NS",ns)
\r
3581 return Result.err(Status.ERR_BadData,v.errs());
\r
3584 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
\r
3586 return Result.err(rnd);
\r
3588 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
3590 return Result.err(rnd);
\r
3593 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, ns, "ns", yyyymm);
\r
3594 if(resp.notOK()) {
\r
3595 return Result.err(resp);
\r
3597 return mapper.history(trans, resp.value,sort);
\r
3600 /***********************************
\r
3602 ***********************************/
\r
3604 public Result<Void> createDelegate(final AuthzTrans trans, REQUEST base) {
\r
3605 return createOrUpdateDelegate(trans, base, Question.Access.create);
\r
3609 public Result<Void> updateDelegate(AuthzTrans trans, REQUEST base) {
\r
3610 return createOrUpdateDelegate(trans, base, Question.Access.write);
\r
3614 private Result<Void> createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) {
\r
3615 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
\r
3616 final Validator v = new Validator();
\r
3617 if(v.delegate(trans.org(),rd).err()) {
\r
3618 return Result.err(Status.ERR_BadData,v.errs());
\r
3621 final DelegateDAO.Data dd = rd.value;
\r
3623 Result<List<DelegateDAO.Data>> ddr = ques.delegateDAO.read(trans, dd);
\r
3624 if(access==Access.create && ddr.isOKhasData()) {
\r
3625 return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate);
\r
3626 } else if(access!=Access.create && ddr.notOKorIsEmpty()) {
\r
3627 return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name());
\r
3629 Result<Void> rv = ques.mayUser(trans, dd, access);
\r
3634 Result<FutureDAO.Data> fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false,
\r
3635 new Mapper.Memo() {
\r
3637 public String get() {
\r
3638 StringBuilder sb = new StringBuilder();
\r
3639 sb.append(access.name());
\r
3640 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
\r
3641 sb.append("Delegate ");
\r
3642 sb.append(access==Access.create?"[":"to [");
\r
3643 sb.append(rd.value.delegate);
\r
3644 sb.append("] for [");
\r
3645 sb.append(rd.value.user);
\r
3647 return sb.toString();
\r
3652 public Result<?> mayChange() {
\r
3653 return Result.ok(); // Validate in code above
\r
3657 switch(fd.status) {
\r
3659 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
3660 dd.user, trans.user(),null, access==Access.create?"C":"U");
\r
3662 return Result.err(Status.ACC_Future, "Delegate for [%s]",
\r
3665 return Result.err(rfc);
\r
3667 case Status.ACC_Now:
\r
3668 if(access==Access.create) {
\r
3669 Result<DelegateDAO.Data> rdr = ques.delegateDAO.create(trans, dd);
\r
3671 return Result.ok();
\r
3673 return Result.err(rdr);
\r
3676 return ques.delegateDAO.update(trans, dd);
\r
3679 return Result.err(fd);
\r
3684 public Result<Void> deleteDelegate(AuthzTrans trans, REQUEST base) {
\r
3685 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
\r
3686 final Validator v = new Validator();
\r
3687 if(v.notOK(rd).nullOrBlank("User", rd.value.user).err()) {
\r
3688 return Result.err(Status.ERR_BadData,v.errs());
\r
3691 Result<List<DelegateDAO.Data>> ddl;
\r
3692 if((ddl=ques.delegateDAO.read(trans, rd.value)).notOKorIsEmpty()) {
\r
3693 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
\r
3695 final DelegateDAO.Data dd = ddl.value.get(0);
\r
3696 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
\r
3701 return ques.delegateDAO.delete(trans, dd, false);
\r
3705 public Result<Void> deleteDelegate(AuthzTrans trans, String userName) {
\r
3706 DelegateDAO.Data dd = new DelegateDAO.Data();
\r
3707 final Validator v = new Validator();
\r
3708 if(v.nullOrBlank("User", userName).err()) {
\r
3709 return Result.err(Status.ERR_BadData,v.errs());
\r
3711 dd.user = userName;
\r
3712 Result<List<DelegateDAO.Data>> ddl;
\r
3713 if((ddl=ques.delegateDAO.read(trans, dd)).notOKorIsEmpty()) {
\r
3714 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
\r
3716 dd = ddl.value.get(0);
\r
3717 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
\r
3722 return ques.delegateDAO.delete(trans, dd, false);
\r
3726 public Result<DELGS> getDelegatesByUser(AuthzTrans trans, String user) {
\r
3727 final Validator v = new Validator();
\r
3728 if(v.nullOrBlank("User", user).err()) {
\r
3729 return Result.err(Status.ERR_BadData,v.errs());
\r
3732 DelegateDAO.Data ddd = new DelegateDAO.Data();
\r
3734 ddd.delegate = null;
\r
3735 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
\r
3737 return Result.err(rv);
\r
3740 TimeTaken tt = trans.start("Get delegates for a user", Env.SUB);
\r
3742 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO.read(trans, user);
\r
3744 if (dbDelgs.isOKhasData()) {
\r
3745 return mapper.delegate(dbDelgs.value);
\r
3747 return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user);
\r
3755 public Result<DELGS> getDelegatesByDelegate(AuthzTrans trans, String delegate) {
\r
3756 final Validator v = new Validator();
\r
3757 if(v.nullOrBlank("Delegate", delegate).err()) {
\r
3758 return Result.err(Status.ERR_BadData,v.errs());
\r
3761 DelegateDAO.Data ddd = new DelegateDAO.Data();
\r
3762 ddd.user = delegate;
\r
3763 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
\r
3765 return Result.err(rv);
\r
3768 TimeTaken tt = trans.start("Get users for a delegate", Env.SUB);
\r
3770 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO.readByDelegate(trans, delegate);
\r
3772 if (dbDelgs.isOKhasData()) {
\r
3773 return mapper.delegate(dbDelgs.value);
\r
3775 return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate);
\r
3782 /***********************************
\r
3784 ***********************************/
\r
3786 public Result<Void> updateApproval(AuthzTrans trans, APPROVALS approvals) {
\r
3787 Result<List<ApprovalDAO.Data>> rlad = mapper.approvals(approvals);
\r
3788 if(rlad.notOK()) {
\r
3789 return Result.err(rlad);
\r
3791 int numApprs = rlad.value.size();
\r
3793 return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating");
\r
3795 int numProcessed = 0;
\r
3796 String user = trans.user();
\r
3798 Result<List<ApprovalDAO.Data>> curr;
\r
3799 for(ApprovalDAO.Data updt : rlad.value) {
\r
3800 if(updt.ticket!=null) {
\r
3801 curr = ques.approvalDAO.readByTicket(trans, updt.ticket);
\r
3802 } else if(updt.id!=null) {
\r
3803 curr = ques.approvalDAO.read(trans, updt);
\r
3804 } else if(updt.approver!=null) {
\r
3805 curr = ques.approvalDAO.readByApprover(trans, updt.approver);
\r
3807 return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update");
\r
3809 if(curr.isOKhasData()) {
\r
3810 for(ApprovalDAO.Data cd : curr.value){
\r
3811 // Check for right record. Need ID, or (Ticket&Trans.User==Appr)
\r
3813 boolean delegatedAction = ques.isDelegated(trans, user, cd.approver);
\r
3814 String delegator = cd.approver;
\r
3815 if(updt.id!=null ||
\r
3816 (updt.ticket!=null && user.equals(cd.approver)) ||
\r
3817 (updt.ticket!=null && delegatedAction)) {
\r
3818 if(updt.ticket.equals(cd.ticket)) {
\r
3819 cd.id = changed(updt.id,cd.id);
\r
3820 cd.ticket = changed(updt.ticket,cd.ticket);
\r
3821 cd.user = changed(updt.user,cd.user);
\r
3822 cd.approver = changed(updt.approver,cd.approver);
\r
3823 cd.type = changed(updt.type,cd.type);
\r
3824 cd.status = changed(updt.status,cd.status);
\r
3825 cd.memo = changed(updt.memo,cd.memo);
\r
3826 cd.operation = changed(updt.operation,cd.operation);
\r
3827 cd.updated = changed(updt.updated,cd.updated);
\r
3828 ques.approvalDAO.update(trans, cd);
\r
3829 Result<Void> rv = func.performFutureOp(trans, cd);
\r
3831 if (delegatedAction) {
\r
3832 trans.audit().log("actor=",user,",action=",updt.status,",operation=\"",cd.memo,
\r
3833 '"',",requestor=",cd.user,",delegator=",delegator);
\r
3835 if (!delegatedAction && cd.status.equalsIgnoreCase("denied")) {
\r
3836 trans.audit().log("actor=",trans.user(),",action=denied,operation=\"",cd.memo,'"',",requestor=",cd.user);
\r
3838 rv = ques.approvalDAO.delete(trans, cd, false);
\r
3848 if(numApprs==numProcessed) {
\r
3849 return Result.ok();
\r
3851 return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed");
\r
3855 private<T> T changed(T src, T dflt) {
\r
3863 public Result<APPROVALS> getApprovalsByUser(AuthzTrans trans, String user) {
\r
3864 final Validator v = new Validator();
\r
3865 if(v.nullOrBlank("User", user).err()) {
\r
3866 return Result.err(Status.ERR_BadData,v.errs());
\r
3869 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByUser(trans, user);
\r
3871 return mapper.approvals(rapd.value);
\r
3873 return Result.err(rapd);
\r
3878 public Result<APPROVALS> getApprovalsByTicket(AuthzTrans trans, String ticket) {
\r
3879 final Validator v = new Validator();
\r
3880 if(v.nullOrBlank("Ticket", ticket).err()) {
\r
3881 return Result.err(Status.ERR_BadData,v.errs());
\r
3885 uuid = UUID.fromString(ticket);
\r
3886 } catch (IllegalArgumentException e) {
\r
3887 return Result.err(Status.ERR_BadData,e.getMessage());
\r
3890 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByTicket(trans, uuid);
\r
3892 return mapper.approvals(rapd.value);
\r
3894 return Result.err(rapd);
\r
3899 public Result<APPROVALS> getApprovalsByApprover(AuthzTrans trans, String approver) {
\r
3900 final Validator v = new Validator();
\r
3901 if(v.nullOrBlank("Approver", approver).err()) {
\r
3902 return Result.err(Status.ERR_BadData,v.errs());
\r
3905 List<ApprovalDAO.Data> listRapds = new ArrayList<ApprovalDAO.Data>();
\r
3907 Result<List<ApprovalDAO.Data>> myRapd = ques.approvalDAO.readByApprover(trans, approver);
\r
3908 if(myRapd.notOK()) {
\r
3909 return Result.err(myRapd);
\r
3912 listRapds.addAll(myRapd.value);
\r
3914 Result<List<DelegateDAO.Data>> delegatedFor = ques.delegateDAO.readByDelegate(trans, approver);
\r
3915 if (delegatedFor.isOK()) {
\r
3916 for (DelegateDAO.Data dd : delegatedFor.value) {
\r
3917 if (dd.expires.after(new Date())) {
\r
3918 String delegator = dd.user;
\r
3919 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByApprover(trans, delegator);
\r
3920 if (rapd.isOK()) {
\r
3921 for (ApprovalDAO.Data d : rapd.value) {
\r
3922 if (!d.user.equals(trans.user())) {
\r
3931 return mapper.approvals(listRapds);
\r
3935 * @see org.onap.aaf.authz.service.AuthzService#clearCache(org.onap.aaf.authz.env.AuthzTrans, java.lang.String)
\r
3938 public Result<Void> cacheClear(AuthzTrans trans, String cname) {
\r
3939 if(ques.isGranted(trans,trans.user(),Define.ROOT_NS,CACHE,cname,"clear")) {
\r
3940 return ques.clearCache(trans,cname);
\r
3942 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.cache|%s|clear",
\r
3943 trans.user(),Define.ROOT_NS,cname);
\r
3947 * @see org.onap.aaf.authz.service.AuthzService#cacheClear(org.onap.aaf.authz.env.AuthzTrans, java.lang.String, java.lang.Integer)
\r
3950 public Result<Void> cacheClear(AuthzTrans trans, String cname, int[] segment) {
\r
3951 if(ques.isGranted(trans,trans.user(),Define.ROOT_NS,CACHE,cname,"clear")) {
\r
3952 Result<Void> v=null;
\r
3953 for(int i: segment) {
\r
3954 v=ques.cacheClear(trans,cname,i);
\r
3960 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.cache|%s|clear",
\r
3961 trans.user(),Define.ROOT_NS,cname);
\r
3965 * @see org.onap.aaf.authz.service.AuthzService#dbReset(org.onap.aaf.authz.env.AuthzTrans)
\r
3968 public void dbReset(AuthzTrans trans) {
\r
3969 ques.historyDAO.reportPerhapsReset(trans, null);
\r