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 com.att.authz.service;
\r
25 import static com.att.authz.layer.Result.OK;
\r
26 import static com.att.cssa.rserv.HttpMethods.DELETE;
\r
27 import static com.att.cssa.rserv.HttpMethods.GET;
\r
28 import static com.att.cssa.rserv.HttpMethods.POST;
\r
29 import static com.att.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 com.att.authz.common.Define;
\r
49 import com.att.authz.env.AuthzTrans;
\r
50 import com.att.authz.layer.Result;
\r
51 import com.att.authz.org.Executor;
\r
52 import com.att.authz.org.Organization;
\r
53 import com.att.authz.org.Organization.Expiration;
\r
54 import com.att.authz.org.Organization.Identity;
\r
55 import com.att.authz.org.Organization.Policy;
\r
56 import com.att.authz.service.mapper.Mapper;
\r
57 import com.att.authz.service.mapper.Mapper.API;
\r
58 import com.att.authz.service.validation.Validator;
\r
59 import com.att.cadi.principal.BasicPrincipal;
\r
60 import com.att.cssa.rserv.doc.ApiDoc;
\r
61 import com.att.dao.DAOException;
\r
62 import com.att.dao.aaf.cass.ApprovalDAO;
\r
63 import com.att.dao.aaf.cass.CertDAO;
\r
64 import com.att.dao.aaf.cass.CredDAO;
\r
65 import com.att.dao.aaf.cass.DelegateDAO;
\r
66 import com.att.dao.aaf.cass.FutureDAO;
\r
67 import com.att.dao.aaf.cass.HistoryDAO;
\r
68 import com.att.dao.aaf.cass.Namespace;
\r
69 import com.att.dao.aaf.cass.NsDAO;
\r
70 import com.att.dao.aaf.cass.NsDAO.Data;
\r
71 import com.att.dao.aaf.cass.NsSplit;
\r
72 import com.att.dao.aaf.cass.NsType;
\r
73 import com.att.dao.aaf.cass.PermDAO;
\r
74 import com.att.dao.aaf.cass.RoleDAO;
\r
75 import com.att.dao.aaf.cass.Status;
\r
76 import com.att.dao.aaf.cass.UserRoleDAO;
\r
77 import com.att.dao.aaf.hl.CassExecutor;
\r
78 import com.att.dao.aaf.hl.Function;
\r
79 import com.att.dao.aaf.hl.Question;
\r
80 import com.att.dao.aaf.hl.Question.Access;
\r
81 import com.att.inno.env.Env;
\r
82 import com.att.inno.env.TimeTaken;
\r
83 import com.att.inno.env.util.Chrono;
\r
84 import com.att.inno.env.util.Split;
\r
86 import aaf.v2_0.CredRequest;
\r
89 * AuthzCassServiceImpl implements AuthzCassService for
\r
101 * @param <APPROVALS>
\r
103 public class AuthzCassServiceImpl <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS>
\r
104 implements AuthzService <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> {
\r
106 private Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
\r
108 public Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper() {return mapper;}
\r
110 private static final String ASTERIX = "*";
\r
111 private static final String CACHE = "cache";
\r
113 private final Question ques;
\r
114 private final Function func;
\r
116 public AuthzCassServiceImpl(AuthzTrans trans, Mapper<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper,Question question) {
\r
117 this.ques = question;
\r
118 func = new Function(trans, question);
\r
119 this.mapper = mapper;
\r
123 /***********************************
\r
125 ***********************************/
\r
128 * @throws DAOException
\r
129 * @see com.att.authz.service.AuthzService#createNS(com.att.authz.env.AuthzTrans, java.lang.String, java.lang.String)
\r
133 path = "/authz/ns",
\r
135 expectedCode = 201,
\r
136 errorCodes = { 403,404,406,409 },
\r
137 text = { "Namespace consists of: ",
\r
138 "<ul><li>name - What you want to call this Namespace</li>",
\r
139 "<li>responsible(s) - Person(s) who receive Notifications and approves Requests ",
\r
140 "regarding this Namespace. Companies have Policies as to who may take on ",
\r
141 "this Responsibility. Separate multiple identities with commas</li>",
\r
142 "<li>admin(s) - Person(s) who are allowed to make changes on the namespace, ",
\r
143 "including creating Roles, Permissions and Credentials. Separate multiple ",
\r
144 "identities with commas</li></ul>",
\r
145 "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ",
\r
146 "created with parent credentials (i.e. To create com.myCompany.myApp, you must ",
\r
147 "be an admin of com.myCompany or com"
\r
151 public Result<Void> createNS(final AuthzTrans trans, REQUEST from, NsType type) {
\r
152 final Result<Namespace> rnamespace = mapper.ns(trans, from);
\r
153 final Validator v = new Validator();
\r
154 if(v.ns(rnamespace).err()) {
\r
155 return Result.err(Status.ERR_BadData,v.errs());
\r
157 final Namespace namespace = rnamespace.value;
\r
158 final Result<NsDAO.Data> parentNs = ques.deriveNs(trans,namespace.name);
\r
159 if(parentNs.notOK()) {
\r
160 return Result.err(parentNs);
\r
163 if(namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed
\r
164 return func.createNS(trans, namespace, false);
\r
167 Result<FutureDAO.Data> fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true,
\r
168 new Mapper.Memo() {
\r
170 public String get() {
\r
171 return "Create Namespace [" + namespace.name + ']';
\r
175 private Result<NsDAO.Data> rnd;
\r
177 public Result<?> mayChange() {
\r
179 rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write);
\r
184 switch(fd.status) {
\r
186 Result<List<Identity>> rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, "C");
\r
188 return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name);
\r
190 return Result.err(rfc);
\r
192 case Status.ACC_Now:
\r
193 return func.createNS(trans, namespace, false);
\r
195 return Result.err(fd);
\r
201 path = "/authz/ns/:ns/admin/:id",
\r
202 params = { "ns|string|true",
\r
205 expectedCode = 201,
\r
206 errorCodes = { 403,404,406,409 },
\r
207 text = { "Add an Identity :id to the list of Admins for the Namespace :ns",
\r
208 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" }
\r
211 public Result<Void> addAdminNS(AuthzTrans trans, String ns, String id) {
\r
212 return func.addUserRole(trans, id, ns,Question.ADMIN);
\r
217 path = "/authz/ns/:ns/admin/:id",
\r
218 params = { "ns|string|true",
\r
221 expectedCode = 200,
\r
222 errorCodes = { 403,404 },
\r
223 text = { "Remove an Identity :id from the list of Admins for the Namespace :ns",
\r
224 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" }
\r
227 public Result<Void> delAdminNS(AuthzTrans trans, String ns, String id) {
\r
228 return func.delAdmin(trans,ns,id);
\r
233 path = "/authz/ns/:ns/responsible/:id",
\r
234 params = { "ns|string|true",
\r
237 expectedCode = 201,
\r
238 errorCodes = { 403,404,406,409 },
\r
239 text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns",
\r
240 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" }
\r
243 public Result<Void> addResponsibleNS(AuthzTrans trans, String ns, String id) {
\r
244 return func.addUserRole(trans,id,ns,Question.OWNER);
\r
249 path = "/authz/ns/:ns/responsible/:id",
\r
250 params = { "ns|string|true",
\r
253 expectedCode = 200,
\r
254 errorCodes = { 403,404 },
\r
255 text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns",
\r
256 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)",
\r
257 "Note: A namespace must have at least 1 responsible party"
\r
261 public Result<Void> delResponsibleNS(AuthzTrans trans, String ns, String id) {
\r
262 return func.delOwner(trans,ns,id);
\r
266 * @see com.att.authz.service.AuthzService#applyModel(com.att.authz.env.AuthzTrans, java.lang.Object)
\r
270 path = "/authz/ns/:ns/attrib/:key/:value",
\r
271 params = { "ns|string|true",
\r
273 "value|string|true"},
\r
274 expectedCode = 201,
\r
275 errorCodes = { 403,404,406,409 },
\r
277 "Create an attribute in the Namespace",
\r
278 "You must be given direct permission for key by AAF"
\r
282 public Result<Void> createNsAttrib(AuthzTrans trans, String ns, String key, String value) {
\r
283 TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
\r
286 final Validator v = new Validator();
\r
287 if(v.ns(ns).err() ||
\r
288 v.key(key).err() ||
\r
289 v.value(value).err()) {
\r
290 return Result.err(Status.ERR_BadData,v.errs());
\r
293 // Check if exists already
\r
294 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
\r
295 if(rlnsd.notOKorIsEmpty()) {
\r
296 return Result.err(rlnsd);
\r
298 NsDAO.Data nsd = rlnsd.value.get(0);
\r
300 // Check for Existence
\r
301 if(nsd.attrib.get(key)!=null) {
\r
302 return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key);
\r
305 // Check if User may put
\r
306 if(!ques.isGranted(trans, trans.user(), Define.ROOT_NS, Question.ATTRIB,
\r
307 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
\r
308 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
\r
312 nsd.attrib.put(key, value);
\r
313 ques.nsDAO.dao().attribAdd(trans,ns,key,value);
\r
314 return Result.ok();
\r
322 path = "/authz/ns/attrib/:key",
\r
323 params = { "key|string|true" },
\r
324 expectedCode = 200,
\r
325 errorCodes = { 403,404 },
\r
327 "Read Attributes for Namespace"
\r
331 public Result<KEYS> readNsByAttrib(AuthzTrans trans, String key) {
\r
333 final Validator v = new Validator();
\r
334 if(v.nullOrBlank("Key",key).err()) {
\r
335 return Result.err(Status.ERR_BadData,v.errs());
\r
339 if(!ques.isGranted(trans, trans.user(), Define.ROOT_NS, Question.ATTRIB,
\r
340 ":"+trans.org().getDomain()+".*:"+key, Question.READ)) {
\r
341 return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key);
\r
344 Result<Set<String>> rsd = ques.nsDAO.dao().readNsByAttrib(trans, key);
\r
346 return Result.err(rsd);
\r
348 return mapper().keys(rsd.value);
\r
354 path = "/authz/ns/:ns/attrib/:key/:value",
\r
355 params = { "ns|string|true",
\r
356 "key|string|true"},
\r
357 expectedCode = 200,
\r
358 errorCodes = { 403,404 },
\r
360 "Update Value on an existing attribute in the Namespace",
\r
361 "You must be given direct permission for key by AAF"
\r
365 public Result<?> updateNsAttrib(AuthzTrans trans, String ns, String key, String value) {
\r
366 TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
\r
369 final Validator v = new Validator();
\r
370 if(v.ns(ns).err() ||
\r
371 v.key(key).err() ||
\r
372 v.value(value).err()) {
\r
373 return Result.err(Status.ERR_BadData,v.errs());
\r
376 // Check if exists already (NS must exist)
\r
377 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
\r
378 if(rlnsd.notOKorIsEmpty()) {
\r
379 return Result.err(rlnsd);
\r
381 NsDAO.Data nsd = rlnsd.value.get(0);
\r
383 // Check for Existence
\r
384 if(nsd.attrib.get(key)==null) {
\r
385 return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key);
\r
388 // Check if User may put
\r
389 if(!ques.isGranted(trans, trans.user(), Define.ROOT_NS, Question.ATTRIB,
\r
390 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
\r
391 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
\r
395 nsd.attrib.put(key, value);
\r
397 return ques.nsDAO.update(trans,nsd);
\r
406 path = "/authz/ns/:ns/attrib/:key",
\r
407 params = { "ns|string|true",
\r
408 "key|string|true"},
\r
409 expectedCode = 200,
\r
410 errorCodes = { 403,404 },
\r
412 "Delete an attribute in the Namespace",
\r
413 "You must be given direct permission for key by AAF"
\r
417 public Result<Void> deleteNsAttrib(AuthzTrans trans, String ns, String key) {
\r
418 TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB);
\r
421 final Validator v = new Validator();
\r
422 if(v.nullOrBlank("NS",ns).err() ||
\r
423 v.nullOrBlank("Key",key).err()) {
\r
424 return Result.err(Status.ERR_BadData,v.errs());
\r
427 // Check if exists already
\r
428 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
\r
429 if(rlnsd.notOKorIsEmpty()) {
\r
430 return Result.err(rlnsd);
\r
432 NsDAO.Data nsd = rlnsd.value.get(0);
\r
434 // Check for Existence
\r
435 if(nsd.attrib.get(key)==null) {
\r
436 return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key);
\r
439 // Check if User may del
\r
440 if(!ques.isGranted(trans, trans.user(), Define.ROOT_NS, "attrib", ":com.att.*:"+key, Access.write.name())) {
\r
441 return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key);
\r
445 nsd.attrib.remove(key);
\r
446 ques.nsDAO.dao().attribRemove(trans,ns,key);
\r
447 return Result.ok();
\r
455 path = "/authz/nss/:id",
\r
456 params = { "id|string|true" },
\r
457 expectedCode = 200,
\r
458 errorCodes = { 404,406 },
\r
460 "Lists the Admin(s), Responsible Party(s), Role(s), Permission(s)",
\r
461 "Credential(s) and Expiration of Credential(s) in Namespace :id",
\r
465 public Result<NSS> getNSbyName(AuthzTrans trans, String ns) {
\r
466 final Validator v = new Validator();
\r
467 if(v.nullOrBlank("NS", ns).err()) {
\r
468 return Result.err(Status.ERR_BadData,v.errs());
\r
471 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.read(trans, ns);
\r
473 if(rlnd.isEmpty()) {
\r
474 return Result.err(Status.ERR_NotFound, "No data found for %s",ns);
\r
476 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read);
\r
478 return Result.err(rnd);
\r
482 Namespace namespace = new Namespace(rnd.value);
\r
483 Result<List<String>> rd = func.getOwners(trans, namespace.name, false);
\r
485 namespace.owner = rd.value;
\r
487 rd = func.getAdmins(trans, namespace.name, false);
\r
489 namespace.admin = rd.value;
\r
492 NSS nss = mapper.newInstance(API.NSS);
\r
493 return mapper.nss(trans, namespace, nss);
\r
495 return Result.err(rlnd);
\r
501 path = "/authz/nss/admin/:id",
\r
502 params = { "id|string|true" },
\r
503 expectedCode = 200,
\r
504 errorCodes = { 403,404 },
\r
505 text = { "Lists all Namespaces where Identity :id is an Admin",
\r
506 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)"
\r
510 public Result<NSS> getNSbyAdmin(AuthzTrans trans, String user, boolean full) {
\r
511 final Validator v = new Validator();
\r
512 if (v.nullOrBlank("User", user).err()) {
\r
513 return Result.err(Status.ERR_BadData, v.errs());
\r
516 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".admin", full);
\r
518 return Result.err(rn);
\r
520 if (rn.isEmpty()) {
\r
521 return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user);
\r
523 NSS nss = mapper.newInstance(API.NSS);
\r
524 // Note: "loadNamespace" already validates view of Namespace
\r
525 return mapper.nss(trans, rn.value, nss);
\r
531 path = "/authz/nss/either/:id",
\r
532 params = { "id|string|true" },
\r
533 expectedCode = 200,
\r
534 errorCodes = { 403,404 },
\r
535 text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner",
\r
536 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)"
\r
540 public Result<NSS> getNSbyEither(AuthzTrans trans, String user, boolean full) {
\r
541 final Validator v = new Validator();
\r
542 if (v.nullOrBlank("User", user).err()) {
\r
543 return Result.err(Status.ERR_BadData, v.errs());
\r
546 Result<Collection<Namespace>> rn = loadNamepace(trans, user, null, full);
\r
548 return Result.err(rn);
\r
550 if (rn.isEmpty()) {
\r
551 return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user);
\r
553 NSS nss = mapper.newInstance(API.NSS);
\r
554 // Note: "loadNamespace" already validates view of Namespace
\r
555 return mapper.nss(trans, rn.value, nss);
\r
558 private Result<Collection<Namespace>> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) {
\r
559 Result<List<UserRoleDAO.Data>> urd = ques.userRoleDAO.readByUser(trans, user);
\r
560 if(urd.notOKorIsEmpty()) {
\r
561 return Result.err(urd);
\r
563 Map<String, Namespace> lm = new HashMap<String,Namespace>();
\r
564 Map<String, Namespace> other = full || endsWith==null?null:new TreeMap<String,Namespace>();
\r
565 for(UserRoleDAO.Data urdd : urd.value) {
\r
567 if(endsWith==null || urdd.role.endsWith(endsWith)) {
\r
568 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
\r
569 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
\r
571 Namespace namespace = lm.get(nsd.value.name);
\r
572 if(namespace==null) {
\r
573 namespace = new Namespace(nsd.value);
\r
574 lm.put(namespace.name,namespace);
\r
576 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
\r
578 namespace.admin=rls.value;
\r
581 rls = func.getOwners(trans, namespace.name, false);
\r
583 namespace.owner=rls.value;
\r
587 } else { // Shortened version. Only Namespace Info available from Role.
\r
588 if(Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) {
\r
589 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
\r
590 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
\r
592 Namespace namespace = lm.get(nsd.value.name);
\r
593 if(namespace==null) {
\r
595 namespace = other.remove(nsd.value.name);
\r
597 if(namespace==null) {
\r
598 namespace = new Namespace(nsd.value);
\r
599 namespace.admin=new ArrayList<String>();
\r
600 namespace.owner=new ArrayList<String>();
\r
602 if(endsWith==null || urdd.role.endsWith(endsWith)) {
\r
603 lm.put(namespace.name,namespace);
\r
605 other.put(namespace.name,namespace);
\r
608 if(Question.OWNER.equals(urdd.rname)) {
\r
609 namespace.owner.add(urdd.user);
\r
611 namespace.admin.add(urdd.user);
\r
617 return Result.ok(lm.values());
\r
622 path = "/authz/nss/responsible/:id",
\r
623 params = { "id|string|true" },
\r
624 expectedCode = 200,
\r
625 errorCodes = { 403,404 },
\r
626 text = { "Lists all Namespaces where Identity :id is a Responsible Party",
\r
627 "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)"
\r
631 public Result<NSS> getNSbyResponsible(AuthzTrans trans, String user, boolean full) {
\r
632 final Validator v = new Validator();
\r
633 if (v.nullOrBlank("User", user).err()) {
\r
634 return Result.err(Status.ERR_BadData, v.errs());
\r
636 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".owner",full);
\r
638 return Result.err(rn);
\r
640 if (rn.isEmpty()) {
\r
641 return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user);
\r
643 NSS nss = mapper.newInstance(API.NSS);
\r
644 // Note: "loadNamespace" prevalidates
\r
645 return mapper.nss(trans, rn.value, nss);
\r
650 path = "/authz/nss/children/:id",
\r
651 params = { "id|string|true" },
\r
652 expectedCode = 200,
\r
653 errorCodes = { 403,404 },
\r
654 text = { "Lists all Child Namespaces of Namespace :id",
\r
655 "Note: This is not a cached read"
\r
659 public Result<NSS> getNSsChildren(AuthzTrans trans, String parent) {
\r
660 final Validator v = new Validator();
\r
661 if(v.nullOrBlank("NS", parent).err()) {
\r
662 return Result.err(Status.ERR_BadData,v.errs());
\r
665 Result<NsDAO.Data> rnd = ques.deriveNs(trans, parent);
\r
667 return Result.err(rnd);
\r
669 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
671 return Result.err(rnd);
\r
674 Set<Namespace> lm = new HashSet<Namespace>();
\r
675 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.dao().getChildren(trans, parent);
\r
677 if(rlnd.isEmpty()) {
\r
678 return Result.err(Status.ERR_NotFound, "No data found for %s",parent);
\r
680 for(NsDAO.Data ndd : rlnd.value) {
\r
681 Namespace namespace = new Namespace(ndd);
\r
682 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
\r
684 namespace.admin=rls.value;
\r
687 rls = func.getOwners(trans, namespace.name, false);
\r
689 namespace.owner=rls.value;
\r
694 NSS nss = mapper.newInstance(API.NSS);
\r
695 return mapper.nss(trans,lm, nss);
\r
697 return Result.err(rlnd);
\r
704 path = "/authz/ns",
\r
706 expectedCode = 200,
\r
707 errorCodes = { 403,404,406 },
\r
708 text = { "Replace the Current Description of a Namespace with a new one"
\r
712 public Result<Void> updateNsDescription(AuthzTrans trans, REQUEST from) {
\r
713 final Result<Namespace> nsd = mapper.ns(trans, from);
\r
714 final Validator v = new Validator();
\r
715 if(v.ns(nsd).err()) {
\r
716 return Result.err(Status.ERR_BadData,v.errs());
\r
718 if(v.nullOrBlank("description", nsd.value.description).err()) {
\r
719 return Result.err(Status.ERR_BadData,v.errs());
\r
722 Namespace namespace = nsd.value;
\r
723 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.read(trans, namespace.name);
\r
725 if(rlnd.notOKorIsEmpty()) {
\r
726 return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name);
\r
729 if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) {
\r
730 return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name);
\r
733 Result<Void> rdr = ques.nsDAO.dao().addDescription(trans, namespace.name, namespace.description);
\r
735 return Result.ok();
\r
737 return Result.err(rdr);
\r
743 * @throws DAOException
\r
744 * @see com.att.authz.service.AuthzService#deleteNS(com.att.authz.env.AuthzTrans, java.lang.String, java.lang.String)
\r
748 path = "/authz/ns/:ns",
\r
749 params = { "ns|string|true" },
\r
750 expectedCode = 200,
\r
751 errorCodes = { 403,404,424 },
\r
752 text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ",
\r
753 "are still credentials associated with them, but they can be deleted by setting ",
\r
754 "the \"force\" property. To do this: Add 'force=true' as a query parameter",
\r
755 "<p>WARNING: Using force will delete all credentials attached to this namespace. Use with care.</p>"
\r
756 + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted,"
\r
757 + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted "
\r
758 + "at or below Application Scope"
\r
762 public Result<Void> deleteNS(AuthzTrans trans, String ns) {
\r
763 return func.deleteNS(trans, ns);
\r
767 /***********************************
\r
769 ***********************************/
\r
773 * @see com.att.authz.service.AuthzService#createOrUpdatePerm(com.att.authz.env.AuthzTrans, java.lang.Object, boolean, java.lang.String, java.lang.String, java.lang.String, java.util.List, java.util.List)
\r
777 path = "/authz/perm",
\r
779 expectedCode = 201,
\r
780 errorCodes = {403,404,406,409},
\r
781 text = { "Permission consists of:",
\r
782 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
\r
783 + "is being protected</li>",
\r
784 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
\r
785 + " instance of the type</li>",
\r
786 "<li>action - what kind of action is allowed</li></ul>",
\r
787 "Note: instance and action can be an *"
\r
791 public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {
\r
792 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
\r
793 final Validator v = new Validator(trans);
\r
794 if(v.perm(newPd).err()) {
\r
795 return Result.err(Status.ERR_BadData,v.errs());
\r
798 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
\r
799 new Mapper.Memo() {
\r
801 public String get() {
\r
802 return "Create Permission [" +
\r
803 newPd.value.fullType() + '|' +
\r
804 newPd.value.instance + '|' +
\r
805 newPd.value.action + ']';
\r
809 private Result<NsDAO.Data> nsd;
\r
811 public Result<?> mayChange() {
\r
813 nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
\r
818 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, newPd.value.ns);
\r
819 if(nsr.notOKorIsEmpty()) {
\r
820 return Result.err(nsr);
\r
822 switch(fd.status) {
\r
824 Result<List<Identity>> rfc = func.createFuture(trans,fd.value,
\r
825 newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
\r
830 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
\r
833 newPd.value.instance,
\r
834 newPd.value.action);
\r
836 return Result.err(rfc);
\r
838 case Status.ACC_Now:
\r
839 return func.createPerm(trans, newPd.value, true);
\r
841 return Result.err(fd);
\r
847 path = "/authz/perms/:type",
\r
848 params = {"type|string|true"},
\r
849 expectedCode = 200,
\r
850 errorCodes = { 404,406 },
\r
851 text = { "List All Permissions that match the :type element of the key" }
\r
854 public Result<PERMS> getPermsByType(AuthzTrans trans, final String permType) {
\r
855 final Validator v = new Validator();
\r
856 if(v.nullOrBlank("PermType", permType).err()) {
\r
857 return Result.err(Status.ERR_BadData,v.errs());
\r
860 Result<List<PermDAO.Data>> rlpd = ques.getPermsByType(trans, permType);
\r
862 return Result.err(rlpd);
\r
865 // We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper?
\r
866 // Result<NsDAO.Data> r;
\r
867 // if((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r);
\r
869 PERMS perms = mapper.newInstance(API.PERMS);
\r
870 if(!rlpd.isEmpty()) {
\r
871 // Note: Mapper will restrict what can be viewed
\r
872 return mapper.perms(trans, rlpd.value, perms, true);
\r
874 return Result.ok(perms);
\r
879 path = "/authz/perms/:type/:instance/:action",
\r
880 params = {"type|string|true",
\r
881 "instance|string|true",
\r
882 "action|string|true"},
\r
883 expectedCode = 200,
\r
884 errorCodes = { 404,406 },
\r
885 text = { "List Permissions that match key; :type, :instance and :action" }
\r
888 public Result<PERMS> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
\r
889 final Validator v = new Validator();
\r
890 if(v.nullOrBlank("PermType", type).err()
\r
891 || v.nullOrBlank("PermInstance", instance).err()
\r
892 || v.nullOrBlank("PermAction", action).err()) {
\r
893 return Result.err(Status.ERR_BadData,v.errs());
\r
896 Result<List<PermDAO.Data>> rlpd = ques.getPermsByName(trans, type, instance, action);
\r
898 return Result.err(rlpd);
\r
901 PERMS perms = mapper.newInstance(API.PERMS);
\r
902 if(!rlpd.isEmpty()) {
\r
903 // Note: Mapper will restrict what can be viewed
\r
904 return mapper.perms(trans, rlpd.value, perms, true);
\r
906 return Result.ok(perms);
\r
911 path = "/authz/perms/user/:user",
\r
912 params = {"user|string|true"},
\r
913 expectedCode = 200,
\r
914 errorCodes = { 404,406 },
\r
915 text = { "List All Permissions that match user :user",
\r
916 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>"}
\r
919 public Result<PERMS> getPermsByUser(AuthzTrans trans, String user) {
\r
920 final Validator v = new Validator();
\r
921 if(v.nullOrBlank("User", user).err()) {
\r
922 return Result.err(Status.ERR_BadData,v.errs());
\r
925 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user, trans.forceRequested());
\r
927 return Result.err(rlpd);
\r
930 PERMS perms = mapper.newInstance(API.PERMS);
\r
932 if(rlpd.isEmpty()) {
\r
933 return Result.ok(perms);
\r
935 // Note: Mapper will restrict what can be viewed
\r
936 // if user is the same as that which is looked up, no filtering is required
\r
937 return mapper.perms(trans, rlpd.value,
\r
939 !user.equals(trans.user()));
\r
944 path = "/authz/perms/user/:user",
\r
945 params = {"user|string|true"},
\r
946 expectedCode = 200,
\r
947 errorCodes = { 404,406 },
\r
948 text = { "List All Permissions that match user :user",
\r
949 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
\r
951 "Present Queries as one or more Permissions (see ContentType Links below for format).",
\r
953 "If the Caller is Granted this specific Permission, and the Permission is valid",
\r
954 " for the User, it will be included in response Permissions, along with",
\r
955 " all the normal permissions on the 'GET' version of this call. If it is not",
\r
956 " valid, or Caller does not have permission to see, it will be removed from the list",
\r
958 " *Note: This design allows you to make one call for all expected permissions",
\r
959 " The permission to be included MUST be:",
\r
960 " <user namespace>.access|:<ns|role|perm>[:key]|<create|read|write>",
\r
962 " com.att.myns.access|:ns|write",
\r
963 " com.att.myns.access|:role:myrole|create",
\r
964 " com.att.myns.access|:perm:mytype:myinstance:myaction|read",
\r
969 public Result<PERMS> getPermsByUser(AuthzTrans trans, PERMS _perms, String user) {
\r
970 PERMS perms = _perms;
\r
971 final Validator v = new Validator();
\r
972 if(v.nullOrBlank("User", user).err()) {
\r
973 return Result.err(Status.ERR_BadData,v.errs());
\r
977 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,trans.forceRequested());
\r
979 return Result.err(rlpd);
\r
983 1) See if allowed to query
\r
984 2) See if User is allowed
\r
986 Result<List<PermDAO.Data>> in = mapper.perms(trans, perms);
\r
987 if(in.isOKhasData()) {
\r
988 List<PermDAO.Data> out = rlpd.value;
\r
990 for(PermDAO.Data pdd : in.value) {
\r
992 if("access".equals(pdd.type)) {
\r
993 Access access = Access.valueOf(pdd.action);
\r
994 String[] mdkey = Split.splitTrim(':',pdd.instance);
\r
995 if(mdkey.length>1) {
\r
996 String type = mdkey[1];
\r
997 if("role".equals(type)) {
\r
998 if(mdkey.length>2) {
\r
999 RoleDAO.Data rdd = new RoleDAO.Data();
\r
1001 rdd.name=mdkey[2];
\r
1002 ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK();
\r
1004 } else if("perm".equals(type)) {
\r
1005 if(mdkey.length>4) { // also need instance/action
\r
1006 PermDAO.Data p = new PermDAO.Data();
\r
1009 p.instance=mdkey[3];
\r
1010 p.action=mdkey[4];
\r
1011 ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK();
\r
1013 } else if("ns".equals(type)) {
\r
1014 NsDAO.Data ndd = new NsDAO.Data();
\r
1016 ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK();
\r
1026 perms = mapper.newInstance(API.PERMS);
\r
1027 if(rlpd.isEmpty()) {
\r
1028 return Result.ok(perms);
\r
1030 // Note: Mapper will restrict what can be viewed
\r
1031 // if user is the same as that which is looked up, no filtering is required
\r
1032 return mapper.perms(trans, rlpd.value,
\r
1034 !user.equals(trans.user()));
\r
1039 path = "/authz/perms/role/:role",
\r
1040 params = {"role|string|true"},
\r
1041 expectedCode = 200,
\r
1042 errorCodes = { 404,406 },
\r
1043 text = { "List All Permissions that are granted to :role" }
\r
1046 public Result<PERMS> getPermsByRole(AuthzTrans trans,String role) {
\r
1047 final Validator v = new Validator();
\r
1048 if(v.nullOrBlank("Role", role).err()) {
\r
1049 return Result.err(Status.ERR_BadData,v.errs());
\r
1052 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques,role);
\r
1053 if(rrdd.notOK()) {
\r
1054 return Result.err(rrdd);
\r
1057 Result<NsDAO.Data> r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
\r
1059 return Result.err(r);
\r
1062 PERMS perms = mapper.newInstance(API.PERMS);
\r
1064 Result<List<PermDAO.Data>> rlpd = ques.getPermsByRole(trans, role, trans.forceRequested());
\r
1065 if(rlpd.isOKhasData()) {
\r
1066 // Note: Mapper will restrict what can be viewed
\r
1067 return mapper.perms(trans, rlpd.value, perms, true);
\r
1069 return Result.ok(perms);
\r
1074 path = "/authz/perms/ns/:ns",
\r
1075 params = {"ns|string|true"},
\r
1076 expectedCode = 200,
\r
1077 errorCodes = { 404,406 },
\r
1078 text = { "List All Permissions that are in Namespace :ns" }
\r
1081 public Result<PERMS> getPermsByNS(AuthzTrans trans,String ns) {
\r
1082 final Validator v = new Validator();
\r
1083 if(v.nullOrBlank("NS", ns).err()) {
\r
1084 return Result.err(Status.ERR_BadData,v.errs());
\r
1087 Result<NsDAO.Data> rnd = ques.deriveNs(trans, ns);
\r
1089 return Result.err(rnd);
\r
1092 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
1094 return Result.err(rnd);
\r
1097 Result<List<PermDAO.Data>> rlpd = ques.permDAO.readNS(trans, ns);
\r
1098 if(rlpd.notOK()) {
\r
1099 return Result.err(rlpd);
\r
1102 PERMS perms = mapper.newInstance(API.PERMS);
\r
1103 if(!rlpd.isEmpty()) {
\r
1104 // Note: Mapper will restrict what can be viewed
\r
1105 return mapper.perms(trans, rlpd.value,perms, true);
\r
1107 return Result.ok(perms);
\r
1112 path = "/authz/perm/:type/:instance/:action",
\r
1113 params = {"type|string|true",
\r
1114 "instance|string|true",
\r
1115 "action|string|true"},
\r
1116 expectedCode = 200,
\r
1117 errorCodes = { 404,406, 409 },
\r
1118 text = { "Rename the Permission referenced by :type :instance :action, and "
\r
1119 + "rename (copy/delete) to the Permission described in PermRequest" }
\r
1122 public Result<Void> renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) {
\r
1123 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
\r
1124 final Validator v = new Validator(trans);
\r
1125 if(v.perm(newPd).err()) {
\r
1126 return Result.err(Status.ERR_BadData,v.errs());
\r
1129 if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) {
\r
1130 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
\r
1131 newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action);
\r
1134 Result<NsSplit> nss = ques.deriveNsSplit(trans, origType);
\r
1135 Result<List<PermDAO.Data>> origRlpd = ques.permDAO.read(trans, nss.value.ns, nss.value.name, origInstance, origAction);
\r
1137 if(origRlpd.notOKorIsEmpty()) {
\r
1138 return Result.err(Status.ERR_PermissionNotFound,
\r
1139 "Permission [%s|%s|%s] does not exist",
\r
1140 origType,origInstance,origAction);
\r
1143 PermDAO.Data origPd = origRlpd.value.get(0);
\r
1145 if (!origPd.ns.equals(newPd.value.ns)) {
\r
1146 return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " +
\r
1147 "<new type> must start with [" + origPd.ns + "]");
\r
1150 if ( origPd.type.equals(newPd.value.type) &&
\r
1151 origPd.action.equals(newPd.value.action) &&
\r
1152 origPd.instance.equals(newPd.value.instance) ) {
\r
1153 return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission");
\r
1156 Set<String> origRoles = origPd.roles(false);
\r
1157 if (!origRoles.isEmpty()) {
\r
1158 Set<String> roles = newPd.value.roles(true);
\r
1159 for (String role : origPd.roles) {
\r
1164 newPd.value.description = origPd.description;
\r
1166 Result<Void> rv = null;
\r
1168 rv = func.createPerm(trans, newPd.value, false);
\r
1170 rv = func.deletePerm(trans, origPd, true, false);
\r
1177 path = "/authz/perm",
\r
1179 expectedCode = 200,
\r
1180 errorCodes = { 404,406 },
\r
1181 text = { "Add Description Data to Perm" }
\r
1184 public Result<Void> updatePermDescription(AuthzTrans trans, REQUEST from) {
\r
1185 final Result<PermDAO.Data> pd = mapper.perm(trans, from);
\r
1186 final Validator v = new Validator(trans);
\r
1187 if(v.perm(pd).err()) {
\r
1188 return Result.err(Status.ERR_BadData,v.errs());
\r
1190 if(v.nullOrBlank("description", pd.value.description).err()) {
\r
1191 return Result.err(Status.ERR_BadData,v.errs());
\r
1193 final PermDAO.Data perm = pd.value;
\r
1194 if(ques.permDAO.read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) {
\r
1195 return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist",
\r
1196 perm.ns,perm.type,perm.instance,perm.action);
\r
1199 if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) {
\r
1200 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
\r
1201 perm.ns,perm.type,perm.instance,perm.action);
\r
1204 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, pd.value.ns);
\r
1205 if(nsr.notOKorIsEmpty()) {
\r
1206 return Result.err(nsr);
\r
1209 Result<Void> rdr = ques.permDAO.addDescription(trans, perm.ns, perm.type, perm.instance,
\r
1210 perm.action, perm.description);
\r
1212 return Result.ok();
\r
1214 return Result.err(rdr);
\r
1221 path = "/authz/role/perm",
\r
1223 expectedCode = 201,
\r
1224 errorCodes = {403,404,406,409},
\r
1225 text = { "Set a permission's roles to roles given" }
\r
1229 public Result<Void> resetPermRoles(final AuthzTrans trans, REQUEST rreq) {
\r
1230 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
\r
1231 if(updt.notOKorIsEmpty()) {
\r
1232 return Result.err(updt);
\r
1235 final Validator v = new Validator(trans);
\r
1236 if(v.perm(updt).err()) {
\r
1237 return Result.err(Status.ERR_BadData,v.errs());
\r
1240 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
\r
1241 if (nsd.notOK()) {
\r
1242 return Result.err(nsd);
\r
1245 // Read full set to get CURRENT values
\r
1246 Result<List<PermDAO.Data>> rcurr = ques.permDAO.read(trans,
\r
1249 updt.value.instance,
\r
1250 updt.value.action);
\r
1252 if(rcurr.notOKorIsEmpty()) {
\r
1253 return Result.err(Status.ERR_PermissionNotFound,
\r
1254 "Permission [%s.%s|%s|%s] does not exist",
\r
1255 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
\r
1258 // Create a set of Update Roles, which are in Internal Format
\r
1259 Set<String> updtRoles = new HashSet<String>();
\r
1260 Result<NsSplit> nss;
\r
1261 for(String role : updt.value.roles(false)) {
\r
1262 nss = ques.deriveNsSplit(trans, role);
\r
1264 updtRoles.add(nss.value.ns + '|' + nss.value.name);
\r
1266 trans.error().log(nss.errorString());
\r
1270 Result<Void> rv = null;
\r
1272 for(PermDAO.Data curr : rcurr.value) {
\r
1273 Set<String> currRoles = curr.roles(false);
\r
1274 // must add roles to this perm, and add this perm to each role
\r
1275 // in the update, but not in the current
\r
1276 for (String role : updtRoles) {
\r
1277 if (!currRoles.contains(role)) {
\r
1278 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
\r
1279 if(key.isOKhasData()) {
\r
1280 Result<List<RoleDAO.Data>> rrd = ques.roleDAO.read(trans, key.value);
\r
1281 if(rrd.isOKhasData()) {
\r
1282 for(RoleDAO.Data r : rrd.value) {
\r
1283 rv = func.addPermToRole(trans, r, curr, false);
\r
1284 if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) {
\r
1285 return Result.err(rv);
\r
1289 return Result.err(rrd);
\r
1294 // similarly, must delete roles from this perm, and delete this perm from each role
\r
1295 // in the update, but not in the current
\r
1296 for (String role : currRoles) {
\r
1297 if (!updtRoles.contains(role)) {
\r
1298 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
\r
1299 if(key.isOKhasData()) {
\r
1300 Result<List<RoleDAO.Data>> rdd = ques.roleDAO.read(trans, key.value);
\r
1301 if(rdd.isOKhasData()) {
\r
1302 for(RoleDAO.Data r : rdd.value) {
\r
1303 rv = func.delPermFromRole(trans, r, curr, true);
\r
1304 if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) {
\r
1305 return Result.err(rv);
\r
1313 return rv==null?Result.ok():rv;
\r
1318 path = "/authz/perm",
\r
1320 expectedCode = 200,
\r
1321 errorCodes = { 404,406 },
\r
1322 text = { "Delete the Permission referenced by PermKey.",
\r
1323 "You cannot normally delete a permission which is still granted to roles,",
\r
1324 "however the \"force\" property allows you to do just that. To do this: Add",
\r
1325 "'force=true' as a query parameter.",
\r
1326 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>" }
\r
1329 public Result<Void> deletePerm(final AuthzTrans trans, REQUEST from) {
\r
1330 Result<PermDAO.Data> pd = mapper.perm(trans, from);
\r
1332 return Result.err(pd);
\r
1334 final Validator v = new Validator(trans);
\r
1335 if(v.nullOrBlank(pd.value).err()) {
\r
1336 return Result.err(Status.ERR_BadData,v.errs());
\r
1338 final PermDAO.Data perm = pd.value;
\r
1339 if (ques.permDAO.read(trans, perm).notOKorIsEmpty()) {
\r
1340 return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
\r
1341 perm.ns,perm.type,perm.instance,perm.action );
\r
1344 Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
\r
1345 new Mapper.Memo() {
\r
1347 public String get() {
\r
1348 return "Delete Permission [" + perm.fullPerm() + ']';
\r
1352 private Result<NsDAO.Data> nsd;
\r
1354 public Result<?> mayChange() {
\r
1356 nsd = ques.mayUser(trans, trans.user(), perm, Access.write);
\r
1362 switch(fd.status) {
\r
1364 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, perm.ns);
\r
1365 if(nsr.notOKorIsEmpty()) {
\r
1366 return Result.err(nsr);
\r
1369 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
1370 perm.encode(), trans.user(),nsr.value.get(0),"D");
\r
1372 return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode());
\r
1374 return Result.err(rfc);
\r
1376 case Status.ACC_Now:
\r
1377 return func.deletePerm(trans,perm,trans.forceRequested(), false);
\r
1379 return Result.err(fd);
\r
1385 path = "/authz/perm/:name/:type/:action",
\r
1386 params = {"type|string|true",
\r
1387 "instance|string|true",
\r
1388 "action|string|true"},
\r
1389 expectedCode = 200,
\r
1390 errorCodes = { 404,406 },
\r
1391 text = { "Delete the Permission referenced by :type :instance :action",
\r
1392 "You cannot normally delete a permission which is still granted to roles,",
\r
1393 "however the \"force\" property allows you to do just that. To do this: Add",
\r
1394 "'force=true' as a query parameter",
\r
1395 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>"}
\r
1398 public Result<Void> deletePerm(AuthzTrans trans, String type, String instance, String action) {
\r
1399 final Validator v = new Validator(trans);
\r
1400 if(v.nullOrBlank("Type",type)
\r
1401 .nullOrBlank("Instance",instance)
\r
1402 .nullOrBlank("Action",action)
\r
1404 return Result.err(Status.ERR_BadData,v.errs());
\r
1407 Result<PermDAO.Data> pd = ques.permFrom(trans, type, instance, action);
\r
1409 return func.deletePerm(trans, pd.value, trans.forceRequested(), false);
\r
1411 return Result.err(pd);
\r
1415 /***********************************
\r
1417 ***********************************/
\r
1420 path = "/authz/role",
\r
1422 expectedCode = 201,
\r
1423 errorCodes = {403,404,406,409},
\r
1426 "Roles are part of Namespaces",
\r
1428 "<ul><li> org.osaaf - A Possible root Namespace for maintaining AAF</li>",
\r
1429 "Roles do not include implied permissions for an App. Instead, they contain explicit Granted Permissions by any Namespace in AAF (See Permissions)",
\r
1430 "Restrictions on Role Names:",
\r
1431 "<ul><li>Must start with valid Namespace name, terminated by . (dot/period)</li>",
\r
1432 "<li>Allowed Characters are a-zA-Z0-9._-</li>",
\r
1433 "<li>role names are Case Sensitive</li></ul>",
\r
1434 "The right questions to ask for defining and populating a Role in AAF, therefore, are:",
\r
1435 "<ul><li>'What Job Function does this represent?'</li>",
\r
1436 "<li>'Does this person perform this Job Function?'</li></ul>" }
\r
1440 public Result<Void> createRole(final AuthzTrans trans, REQUEST from) {
\r
1441 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
\r
1442 final Validator v = new Validator(trans);
\r
1443 if(v.role(rd).err()) {
\r
1444 return Result.err(Status.ERR_BadData,v.errs());
\r
1446 final RoleDAO.Data role = rd.value;
\r
1447 if(ques.roleDAO.read(trans, role.ns, role.name).isOKhasData()) {
\r
1448 return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists");
\r
1451 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
\r
1452 new Mapper.Memo() {
\r
1454 public String get() {
\r
1455 return "Create Role [" +
\r
1456 rd.value.fullName() +
\r
1461 private Result<NsDAO.Data> nsd;
\r
1463 public Result<?> mayChange() {
\r
1465 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
\r
1471 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
\r
1472 if(nsr.notOKorIsEmpty()) {
\r
1473 return Result.err(nsr);
\r
1476 switch(fd.status) {
\r
1478 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
1479 role.encode(), trans.user(),nsr.value.get(0),"C");
\r
1481 return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing",
\r
1485 return Result.err(rfc);
\r
1487 case Status.ACC_Now:
\r
1488 Result<RoleDAO.Data> rdr = ques.roleDAO.create(trans, role);
\r
1490 return Result.ok();
\r
1492 return Result.err(rdr);
\r
1495 return Result.err(fd);
\r
1500 * @see com.att.authz.service.AuthzService#getRolesByName(com.att.authz.env.AuthzTrans, java.lang.String)
\r
1504 path = "/authz/roles/:role",
\r
1505 params = {"role|string|true"},
\r
1506 expectedCode = 200,
\r
1507 errorCodes = {404,406},
\r
1508 text = { "List Roles that match :role",
\r
1509 "Note: You must have permission to see any given role"
\r
1513 public Result<ROLES> getRolesByName(AuthzTrans trans, String role) {
\r
1514 final Validator v = new Validator();
\r
1515 if(v.nullOrBlank("Role", role).err()) {
\r
1516 return Result.err(Status.ERR_BadData,v.errs());
\r
1519 // Determine if User can ask this question
\r
1520 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
1521 if(rrdd.isOKhasData()) {
\r
1522 Result<NsDAO.Data> r;
\r
1523 if((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) {
\r
1524 return Result.err(r);
\r
1527 return Result.err(rrdd);
\r
1531 Result<List<RoleDAO.Data>> rlrd = ques.getRolesByName(trans, role);
\r
1533 // Note: Mapper will restrict what can be viewed
\r
1534 ROLES roles = mapper.newInstance(API.ROLES);
\r
1535 return mapper.roles(trans, rlrd.value, roles, true);
\r
1537 return Result.err(rlrd);
\r
1542 * @see com.att.authz.service.AuthzService#getRolesByUser(com.att.authz.env.AuthzTrans, java.lang.String)
\r
1546 path = "/authz/roles/user/:name",
\r
1547 params = {"name|string|true"},
\r
1548 expectedCode = 200,
\r
1549 errorCodes = {404,406},
\r
1550 text = { "List all Roles that match user :name",
\r
1551 "'user' must be expressed as full identity (ex: id@full.domain.com)",
\r
1552 "Note: You must have permission to see any given role"
\r
1557 public Result<ROLES> getRolesByUser(AuthzTrans trans, String user) {
\r
1558 final Validator v = new Validator();
\r
1559 if(v.nullOrBlank("User", user).err()) {
\r
1560 return Result.err(Status.ERR_BadData,v.errs());
\r
1563 ROLES roles = mapper.newInstance(API.ROLES);
\r
1564 // Get list of roles per user, then add to Roles as we go
\r
1565 Result<List<RoleDAO.Data>> rlrd;
\r
1566 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, user);
\r
1567 if(rlurd.isOKhasData()) {
\r
1568 for(UserRoleDAO.Data urd : rlurd.value ) {
\r
1569 rlrd = ques.roleDAO.read(trans, urd.ns,urd.rname);
\r
1570 // Note: Mapper will restrict what can be viewed
\r
1571 // if user is the same as that which is looked up, no filtering is required
\r
1572 if(rlrd.isOKhasData()) {
\r
1573 mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user()));
\r
1577 return Result.ok(roles);
\r
1582 * @see com.att.authz.service.AuthzService#getRolesByNS(com.att.authz.env.AuthzTrans, java.lang.String)
\r
1586 path = "/authz/roles/ns/:ns",
\r
1587 params = {"ns|string|true"},
\r
1588 expectedCode = 200,
\r
1589 errorCodes = {404,406},
\r
1590 text = { "List all Roles for the Namespace :ns",
\r
1591 "Note: You must have permission to see any given role"
\r
1596 public Result<ROLES> getRolesByNS(AuthzTrans trans, String ns) {
\r
1597 final Validator v = new Validator();
\r
1598 if(v.nullOrBlank("NS", ns).err()) {
\r
1599 return Result.err(Status.ERR_BadData,v.errs());
\r
1602 // check if user is allowed to view NS
\r
1603 Result<NsDAO.Data> rnsd = ques.deriveNs(trans, ns);
\r
1604 if(rnsd.notOK()) {
\r
1605 return Result.err(rnsd);
\r
1607 rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read);
\r
1608 if(rnsd.notOK()) {
\r
1609 return Result.err(rnsd);
\r
1612 TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB);
\r
1614 ROLES roles = mapper.newInstance(API.ROLES);
\r
1615 // Get list of roles per user, then add to Roles as we go
\r
1616 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.readNS(trans, ns);
\r
1618 if(!rlrd.isEmpty()) {
\r
1619 // Note: Mapper doesn't need to restrict what can be viewed, because we did it already.
\r
1620 mapper.roles(trans,rlrd.value,roles,false);
\r
1622 return Result.ok(roles);
\r
1624 return Result.err(rlrd);
\r
1633 * @see com.att.authz.service.AuthzService#getRolesByNS(com.att.authz.env.AuthzTrans, java.lang.String)
\r
1637 path = "/authz/roles/name/:name",
\r
1638 params = {"name|string|true"},
\r
1639 expectedCode = 200,
\r
1640 errorCodes = {404,406},
\r
1641 text = { "List all Roles for only the Name of Role (without Namespace)",
\r
1642 "Note: You must have permission to see any given role"
\r
1646 public Result<ROLES> getRolesByNameOnly(AuthzTrans trans, String name) {
\r
1647 final Validator v = new Validator();
\r
1648 if(v.nullOrBlank("Name", name).err()) {
\r
1649 return Result.err(Status.ERR_BadData,v.errs());
\r
1652 // User Mapper to make sure user is allowed to view NS
\r
1654 TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB);
\r
1656 ROLES roles = mapper.newInstance(API.ROLES);
\r
1657 // Get list of roles per user, then add to Roles as we go
\r
1658 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.readName(trans, name);
\r
1660 if(!rlrd.isEmpty()) {
\r
1661 // Note: Mapper will restrict what can be viewed
\r
1662 mapper.roles(trans,rlrd.value,roles,true);
\r
1664 return Result.ok(roles);
\r
1666 return Result.err(rlrd);
\r
1675 path = "/authz/roles/perm/:type/:instance/:action",
\r
1676 params = {"type|string|true",
\r
1677 "instance|string|true",
\r
1678 "action|string|true"},
\r
1679 expectedCode = 200,
\r
1680 errorCodes = {404,406},
\r
1681 text = { "Find all Roles containing the given Permission." +
\r
1682 "Permission consists of:",
\r
1683 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
\r
1684 + "is being protected</li>",
\r
1685 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
\r
1686 + " instance of the type</li>",
\r
1687 "<li>action - what kind of action is allowed</li></ul>",
\r
1688 "Notes: instance and action can be an *",
\r
1689 " You must have permission to see any given role"
\r
1694 public Result<ROLES> getRolesByPerm(AuthzTrans trans, String type, String instance, String action) {
\r
1695 final Validator v = new Validator(trans);
\r
1696 if(v.permType(type,null)
\r
1697 .permInstance(instance)
\r
1698 .permAction(action)
\r
1700 return Result.err(Status.ERR_BadData,v.errs());
\r
1703 TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB);
\r
1705 ROLES roles = mapper.newInstance(API.ROLES);
\r
1706 // Get list of roles per user, then add to Roles as we go
\r
1707 Result<NsSplit> nsSplit = ques.deriveNsSplit(trans, type);
\r
1708 if(nsSplit.isOK()) {
\r
1709 PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action);
\r
1711 if((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) {
\r
1712 return Result.err(res);
\r
1715 Result<List<PermDAO.Data>> pdlr = ques.permDAO.read(trans, pdd);
\r
1716 if(pdlr.isOK())for(PermDAO.Data pd : pdlr.value) {
\r
1717 Result<List<RoleDAO.Data>> rlrd;
\r
1718 for(String r : pd.roles) {
\r
1719 Result<String[]> rs = RoleDAO.Data.decodeToArray(trans, ques, r);
\r
1721 rlrd = ques.roleDAO.read(trans, rs.value[0],rs.value[1]);
\r
1722 // Note: Mapper will restrict what can be viewed
\r
1723 if(rlrd.isOKhasData()) {
\r
1724 mapper.roles(trans,rlrd.value,roles,true);
\r
1730 return Result.ok(roles);
\r
1738 path = "/authz/role",
\r
1740 expectedCode = 200,
\r
1741 errorCodes = {404,406},
\r
1742 text = { "Add Description Data to a Role" }
\r
1746 public Result<Void> updateRoleDescription(AuthzTrans trans, REQUEST from) {
\r
1747 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
\r
1748 final Validator v = new Validator(trans);
\r
1749 if(v.role(rd).err()) {
\r
1750 return Result.err(Status.ERR_BadData,v.errs());
\r
1752 if(v.nullOrBlank("description", rd.value.description).err()) {
\r
1753 return Result.err(Status.ERR_BadData,v.errs());
\r
1756 final RoleDAO.Data role = rd.value;
\r
1757 if(ques.roleDAO.read(trans, role.ns, role.name).notOKorIsEmpty()) {
\r
1758 return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist");
\r
1761 if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) {
\r
1762 return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName());
\r
1765 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
\r
1766 if(nsr.notOKorIsEmpty()) {
\r
1767 return Result.err(nsr);
\r
1770 Result<Void> rdr = ques.roleDAO.addDescription(trans, role.ns, role.name, role.description);
\r
1772 return Result.ok();
\r
1774 return Result.err(rdr);
\r
1781 path = "/authz/role/perm",
\r
1783 expectedCode = 201,
\r
1784 errorCodes = {403,404,406,409},
\r
1785 text = { "Grant a Permission to a Role",
\r
1786 "Permission consists of:",
\r
1787 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
\r
1788 + "is being protected</li>",
\r
1789 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
\r
1790 + " instance of the type</li>",
\r
1791 "<li>action - what kind of action is allowed</li></ul>",
\r
1792 "Note: instance and action can be an *",
\r
1793 "Note: Using the \"force\" property will create the Permission, if it doesn't exist AND the requesting " +
\r
1794 " ID is allowed to create. It will then grant",
\r
1795 " the permission to the role in one step. To do this: add 'force=true' as a query parameter."
\r
1800 public Result<Void> addPermToRole(final AuthzTrans trans, REQUEST rreq) {
\r
1801 // Translate Request into Perm and Role Objects
\r
1802 final Result<PermDAO.Data> rpd = mapper.permFromRPRequest(trans, rreq);
\r
1803 if(rpd.notOKorIsEmpty()) {
\r
1804 return Result.err(rpd);
\r
1806 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
\r
1807 if(rrd.notOKorIsEmpty()) {
\r
1808 return Result.err(rrd);
\r
1811 // Validate Role and Perm values
\r
1812 final Validator v = new Validator(trans);
\r
1813 if(v.perm(rpd.value)
\r
1816 return Result.err(Status.ERR_BadData,v.errs());
\r
1819 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.read(trans, rrd.value.ns, rrd.value.name);
\r
1820 if(rlrd.notOKorIsEmpty()) {
\r
1821 return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName());
\r
1824 // Check Status of Data in DB (does it exist)
\r
1825 Result<List<PermDAO.Data>> rlpd = ques.permDAO.read(trans, rpd.value.ns,
\r
1826 rpd.value.type, rpd.value.instance, rpd.value.action);
\r
1827 PermDAO.Data createPerm = null; // if not null, create first
\r
1828 if(rlpd.notOKorIsEmpty()) { // Permission doesn't exist
\r
1829 if(trans.forceRequested()) {
\r
1830 // Remove roles from perm data object so we just create the perm here
\r
1831 createPerm = rpd.value;
\r
1832 createPerm.roles.clear();
\r
1834 return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist",
\r
1835 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action);
\r
1838 if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) {
\r
1839 return Result.err(Status.ERR_ConflictAlreadyExists,
\r
1840 "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]",
\r
1841 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action,
\r
1842 rrd.value.ns,rrd.value.name
\r
1848 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals
\r
1849 new Mapper.Memo() {
\r
1851 public String get() {
\r
1852 return "Grant Permission [" + rpd.value.fullPerm() + ']' +
\r
1853 " to Role [" + rrd.value.fullName() + "]";
\r
1857 private Result<NsDAO.Data> nsd;
\r
1859 public Result<?> mayChange() {
\r
1861 nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
\r
1866 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rpd.value.ns);
\r
1867 if(nsr.notOKorIsEmpty()) {
\r
1868 return Result.err(nsr);
\r
1870 switch(fd.status) {
\r
1872 Result<List<Identity>> rfc = func.createFuture(trans,fd.value,
\r
1873 rpd.value.fullPerm(),
\r
1878 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
\r
1881 rpd.value.instance,
\r
1882 rpd.value.action);
\r
1884 return Result.err(rfc);
\r
1886 case Status.ACC_Now:
\r
1887 Result<Void> rv = null;
\r
1888 if(createPerm!=null) {// has been validated for creating
\r
1889 rv = func.createPerm(trans, createPerm, false);
\r
1891 if(rv==null || rv.isOK()) {
\r
1892 rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
\r
1896 return Result.err(fd);
\r
1902 * Create a RoleDAO.Data
\r
1904 * @param roleFullName
\r
1909 path = "/authz/role/:role/perm",
\r
1910 params = {"role|string|true"},
\r
1911 expectedCode = 200,
\r
1912 errorCodes = {404,406},
\r
1913 text = { "Ungrant a permission from Role :role" }
\r
1917 public Result<Void> delPermFromRole(final AuthzTrans trans, REQUEST rreq) {
\r
1918 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
\r
1919 if(updt.notOKorIsEmpty()) {
\r
1920 return Result.err(updt);
\r
1922 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
\r
1923 if(rrd.notOKorIsEmpty()) {
\r
1924 return Result.err(rrd);
\r
1927 final Validator v = new Validator(trans);
\r
1928 if(v.nullOrBlank(updt.value)
\r
1929 .nullOrBlank(rrd.value)
\r
1931 return Result.err(Status.ERR_BadData,v.errs());
\r
1934 Result<List<PermDAO.Data>> rlpd = ques.permDAO.read(trans, updt.value.ns, updt.value.type,
\r
1935 updt.value.instance, updt.value.action);
\r
1937 if(rlpd.notOKorIsEmpty()) {
\r
1938 return Result.err(Status.ERR_PermissionNotFound,
\r
1939 "Permission [%s.%s|%s|%s] does not exist",
\r
1940 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
\r
1943 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, updt.value,true, // allow ungrants requests
\r
1944 new Mapper.Memo() {
\r
1946 public String get() {
\r
1947 return "Ungrant Permission [" + updt.value.fullPerm() + ']' +
\r
1948 " from Role [" + rrd.value.fullName() + "]";
\r
1952 private Result<NsDAO.Data> nsd;
\r
1954 public Result<?> mayChange() {
\r
1956 nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
\r
1961 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, updt.value.ns);
\r
1962 if(nsr.notOKorIsEmpty()) {
\r
1963 return Result.err(nsr);
\r
1965 switch(fd.status) {
\r
1967 Result<List<Identity>> rfc = func.createFuture(trans,fd.value,
\r
1968 updt.value.fullPerm(),
\r
1974 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
\r
1977 updt.value.instance,
\r
1978 updt.value.action);
\r
1980 return Result.err(rfc);
\r
1982 case Status.ACC_Now:
\r
1983 return func.delPermFromRole(trans, rrd.value, updt.value, false);
\r
1985 return Result.err(fd);
\r
1991 path = "/authz/role/:role",
\r
1992 params = {"role|string|true"},
\r
1993 expectedCode = 200,
\r
1994 errorCodes = {404,406},
\r
1995 text = { "Delete the Role named :role"}
\r
1999 public Result<Void> deleteRole(AuthzTrans trans, String role) {
\r
2000 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
\r
2001 if(rrdd.isOKhasData()) {
\r
2002 final Validator v = new Validator(trans);
\r
2003 if(v.nullOrBlank(rrdd.value).err()) {
\r
2004 return Result.err(Status.ERR_BadData,v.errs());
\r
2006 return func.deleteRole(trans, rrdd.value, false, false);
\r
2008 return Result.err(rrdd);
\r
2014 path = "/authz/role",
\r
2016 expectedCode = 200,
\r
2017 errorCodes = { 404,406 },
\r
2018 text = { "Delete the Role referenced by RoleKey",
\r
2019 "You cannot normally delete a role which still has permissions granted or users assigned to it,",
\r
2020 "however the \"force\" property allows you to do just that. To do this: Add 'force=true'",
\r
2021 "as a query parameter.",
\r
2022 "<p>WARNING: Using force will remove all users and permission from this role. Use with care.</p>"}
\r
2026 public Result<Void> deleteRole(final AuthzTrans trans, REQUEST from) {
\r
2027 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
\r
2028 final Validator v = new Validator(trans);
\r
2030 return Result.err(Status.ERR_BadData,"Request does not contain Role");
\r
2032 if(v.nullOrBlank(rd.value).err()) {
\r
2033 return Result.err(Status.ERR_BadData,v.errs());
\r
2035 final RoleDAO.Data role = rd.value;
\r
2036 if(ques.roleDAO.read(trans, role).notOKorIsEmpty() && !trans.forceRequested()) {
\r
2037 return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist");
\r
2040 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
\r
2041 new Mapper.Memo() {
\r
2043 public String get() {
\r
2044 return "Delete Role [" + role.fullName() + ']'
\r
2045 + " and all attached user roles";
\r
2049 private Result<NsDAO.Data> nsd;
\r
2051 public Result<?> mayChange() {
\r
2053 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
\r
2059 switch(fd.status) {
\r
2061 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
\r
2062 if(nsr.notOKorIsEmpty()) {
\r
2063 return Result.err(nsr);
\r
2066 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
2067 role.encode(), trans.user(),nsr.value.get(0),"D");
\r
2069 return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing",
\r
2073 return Result.err(rfc);
\r
2075 case Status.ACC_Now:
\r
2076 return func.deleteRole(trans,role,trans.forceRequested(), true /*preapproved*/);
\r
2078 return Result.err(fd);
\r
2083 /***********************************
\r
2085 ***********************************/
\r
2086 private class MayCreateCred implements MayChange {
\r
2087 private Result<NsDAO.Data> nsd;
\r
2088 private AuthzTrans trans;
\r
2089 private CredDAO.Data cred;
\r
2090 private Executor exec;
\r
2092 public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) {
\r
2093 this.trans = trans;
\r
2099 public Result<?> mayChange() {
\r
2101 nsd = ques.validNSOfDomain(trans, cred.id);
\r
2103 // is Ns of CredID valid?
\r
2106 // Check Org Policy
\r
2107 if(trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) {
\r
2108 return Result.ok();
\r
2110 Result<?> rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write);
\r
2111 if(rmc.isOKhasData()) {
\r
2115 } catch (Exception e) {
\r
2116 trans.warn().log(e);
\r
2119 trans.warn().log(nsd.errorString());
\r
2121 return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns);
\r
2125 private class MayChangeCred implements MayChange {
\r
2127 private Result<NsDAO.Data> nsd;
\r
2128 private AuthzTrans trans;
\r
2129 private CredDAO.Data cred;
\r
2130 public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) {
\r
2131 this.trans = trans;
\r
2136 public Result<?> mayChange() {
\r
2137 // User can change himself (but not create)
\r
2138 if(trans.user().equals(cred.id)) {
\r
2139 return Result.ok();
\r
2142 nsd = ques.validNSOfDomain(trans, cred.id);
\r
2144 // Get the Namespace
\r
2146 if(ques.mayUser(trans, trans.user(), nsd.value,Access.write).isOK()) {
\r
2147 return Result.ok();
\r
2149 String user[] = Split.split('.',trans.user());
\r
2150 if(user.length>2) {
\r
2151 String company = user[user.length-1] + '.' + user[user.length-2];
\r
2152 if(ques.isGranted(trans, trans.user(), Define.ROOT_NS,"password",company,"reset")) {
\r
2153 return Result.ok();
\r
2157 return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns);
\r
2162 private final long DAY_IN_MILLIS = 24*3600*1000;
\r
2166 path = "/authn/cred",
\r
2168 expectedCode = 201,
\r
2169 errorCodes = {403,404,406,409},
\r
2170 text = { "A credential consists of:",
\r
2171 "<ul><li>id - the ID to create within AAF. The domain is in reverse",
\r
2172 "order of Namespace (i.e. Users of Namespace com.att.myapp would be",
\r
2173 "AB1234@myapp.att.com</li>",
\r
2174 "<li>password - Company Policy Compliant Password</li></ul>",
\r
2175 "Note: AAF does support multiple credentials with the same ID.",
\r
2176 "Check with your organization if you have this implemented."
\r
2180 public Result<Void> createUserCred(final AuthzTrans trans, REQUEST from) {
\r
2181 final String cmdDescription = ("Create User Credential");
\r
2182 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
\r
2185 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
\r
2186 if(rcred.isOKhasData()) {
\r
2187 rcred = ques.userCredSetup(trans, rcred.value);
\r
2189 final Validator v = new Validator();
\r
2191 if(v.cred(trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations
\r
2192 return Result.err(Status.ERR_BadData,v.errs());
\r
2196 // 2016-4 JG, New Behavior - If MechID is not registered with Org, deny creation
\r
2197 Identity mechID = null;
\r
2198 Organization org = trans.org();
\r
2200 mechID = org.getIdentity(trans, rcred.value.id);
\r
2201 } catch (Exception e1) {
\r
2202 trans.error().log(e1,rcred.value.id,"cannot be validated at this time");
\r
2204 if(mechID==null || !mechID.isFound()) {
\r
2205 return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName());
\r
2208 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rcred.value.ns);
\r
2209 if(nsr.notOKorIsEmpty()) {
\r
2210 return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns);
\r
2213 boolean firstID = false;
\r
2216 CassExecutor exec = new CassExecutor(trans, func);
\r
2217 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, rcred.value.id);
\r
2218 if (rlcd.isOKhasData()) {
\r
2219 if (!org.canHaveMultipleCreds(rcred.value.id)) {
\r
2220 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists");
\r
2222 for (CredDAO.Data curr : rlcd.value) {
\r
2223 if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) {
\r
2224 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'");
\r
2229 // 2016-04-12 JG If Caller is the Sponsor and is also an Owner of NS, allow without special Perm
\r
2230 String theMechID = rcred.value.id;
\r
2231 Boolean otherMechIDs = false;
\r
2232 // find out if this is the only mechID. other MechIDs mean special handling (not automated)
\r
2233 for(CredDAO.Data cd : ques.credDAO.readNS(trans,nsr.value.get(0).name).value) {
\r
2234 if(!cd.id.equals(theMechID)) {
\r
2235 otherMechIDs = true;
\r
2240 // We can say "ID does not exist" here
\r
2241 if((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) {
\r
2242 return Result.err(Status.ERR_Denied, reason);
\r
2245 } catch (Exception e) {
\r
2246 return Result.err(e);
\r
2250 mc = new MayCreateCred(trans, rcred.value, exec);
\r
2252 final CredDAO.Data cdd = rcred.value;
\r
2253 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future.
\r
2254 new Mapper.Memo() {
\r
2256 public String get() {
\r
2257 return cmdDescription + " [" +
\r
2260 + cdd.expires + ']';
\r
2265 switch(fd.status) {
\r
2267 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
2268 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
\r
2269 trans.user(), nsr.value.get(0), "C");
\r
2271 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing",
\r
2273 Integer.toString(rcred.value.type),
\r
2274 rcred.value.expires.toString());
\r
2276 return Result.err(rfc);
\r
2278 case Status.ACC_Now:
\r
2281 // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) {
\r
2282 Result<List<String>> admins = func.getAdmins(trans, nsr.value.get(0).name, false);
\r
2283 // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length
\r
2284 // Note, we only do this on First time, because of possibility of
\r
2285 // prematurely expiring a production id
\r
2286 if(admins.isOKhasData() && !admins.value.contains(trans.user())) {
\r
2287 rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime();
\r
2290 } catch (Exception e) {
\r
2291 trans.error().log(e, "While setting expiration to TempPassword");
\r
2293 Result<?>udr = ques.credDAO.create(trans, rcred.value);
\r
2295 return Result.ok();
\r
2297 return Result.err(udr);
\r
2299 return Result.err(fd);
\r
2303 return Result.err(rcred);
\r
2312 path = "/authn/creds/ns/:ns",
\r
2313 params = {"ns|string|true"},
\r
2314 expectedCode = 200,
\r
2315 errorCodes = {403,404,406},
\r
2316 text = { "Return all IDs in Namespace :ns"
\r
2320 public Result<USERS> getCredsByNS(AuthzTrans trans, String ns) {
\r
2321 final Validator v = new Validator();
\r
2322 if(v.ns(ns).err()) {
\r
2323 return Result.err(Status.ERR_BadData,v.errs());
\r
2326 // check if user is allowed to view NS
\r
2327 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
\r
2329 return Result.err(rnd);
\r
2331 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
2333 return Result.err(rnd);
\r
2336 TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB);
\r
2338 USERS users = mapper.newInstance(API.USERS);
\r
2339 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readNS(trans, ns);
\r
2342 if(!rlcd.isEmpty()) {
\r
2343 return mapper.cred(rlcd.value, users);
\r
2345 return Result.ok(users);
\r
2347 return Result.err(rlcd);
\r
2357 path = "/authn/creds/id/:ns",
\r
2358 params = {"id|string|true"},
\r
2359 expectedCode = 200,
\r
2360 errorCodes = {403,404,406},
\r
2361 text = { "Return all IDs in for ID"
\r
2362 ,"(because IDs are multiple, due to multiple Expiration Dates)"
\r
2366 public Result<USERS> getCredsByID(AuthzTrans trans, String id) {
\r
2367 final Validator v = new Validator();
\r
2368 if(v.nullOrBlank("ID",id).err()) {
\r
2369 return Result.err(Status.ERR_BadData,v.errs());
\r
2372 String ns = Question.domain2ns(id);
\r
2373 // check if user is allowed to view NS
\r
2374 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
\r
2376 return Result.err(rnd);
\r
2378 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
2380 return Result.err(rnd);
\r
2383 TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB);
\r
2385 USERS users = mapper.newInstance(API.USERS);
\r
2386 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, id);
\r
2389 if(!rlcd.isEmpty()) {
\r
2390 return mapper.cred(rlcd.value, users);
\r
2392 return Result.ok(users);
\r
2394 return Result.err(rlcd);
\r
2404 path = "/authn/certs/id/:id",
\r
2405 params = {"id|string|true"},
\r
2406 expectedCode = 200,
\r
2407 errorCodes = {403,404,406},
\r
2408 text = { "Return Cert Info for ID"
\r
2412 public Result<CERTS> getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) {
\r
2413 TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB);
\r
2415 CERTS certs = mapper.newInstance(API.CERTS);
\r
2416 Result<List<CertDAO.Data>> rlcd = ques.certDAO.readID(trans, id);
\r
2419 if(!rlcd.isEmpty()) {
\r
2420 return mapper.cert(rlcd.value, certs);
\r
2422 return Result.ok(certs);
\r
2424 return Result.err(rlcd);
\r
2434 path = "/authn/cred",
\r
2436 expectedCode = 200,
\r
2437 errorCodes = {300,403,404,406},
\r
2438 text = { "Reset a Credential Password. If multiple credentials exist for this",
\r
2439 "ID, you will need to specify which entry you are resetting in the",
\r
2440 "CredRequest object"
\r
2444 public Result<Void> changeUserCred(final AuthzTrans trans, REQUEST from) {
\r
2445 final String cmdDescription = "Update User Credential";
\r
2446 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
\r
2448 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
\r
2449 if(rcred.isOKhasData()) {
\r
2450 rcred = ques.userCredSetup(trans, rcred.value);
\r
2452 final Validator v = new Validator();
\r
2454 if(v.cred(trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations
\r
2455 return Result.err(Status.ERR_BadData,v.errs());
\r
2457 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, rcred.value.id);
\r
2458 if(rlcd.notOKorIsEmpty()) {
\r
2459 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
\r
2462 MayChange mc = new MayChangeCred(trans, rcred.value);
\r
2463 Result<?> rmc = mc.mayChange();
\r
2464 if (rmc.notOK()) {
\r
2465 return Result.err(rmc);
\r
2468 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
\r
2470 return Result.err(ri);
\r
2472 int entry = ri.value;
\r
2475 final CredDAO.Data cred = rcred.value;
\r
2477 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false,
\r
2478 new Mapper.Memo() {
\r
2480 public String get() {
\r
2481 return cmdDescription + " [" +
\r
2483 + cred.type + '|'
\r
2484 + cred.expires + ']';
\r
2489 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rcred.value.ns);
\r
2490 if(nsr.notOKorIsEmpty()) {
\r
2491 return Result.err(nsr);
\r
2494 switch(fd.status) {
\r
2496 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
2497 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
\r
2498 trans.user(), nsr.value.get(0), "U");
\r
2500 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]",
\r
2502 Integer.toString(rcred.value.type),
\r
2503 rcred.value.expires.toString());
\r
2505 return Result.err(rfc);
\r
2507 case Status.ACC_Now:
\r
2508 Result<?>udr = null;
\r
2509 // If we are Resetting Password on behalf of someone else (am not the Admin)
\r
2510 // use TempPassword Expiration time.
\r
2512 if(ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) {
\r
2513 exp = Expiration.Password;
\r
2515 exp = Expiration.TempPassword;
\r
2518 Organization org = trans.org();
\r
2519 // If user resets password in same day, we will have a primary key conflict, so subtract 1 day
\r
2520 if (rlcd.value.get(entry).expires.equals(rcred.value.expires)
\r
2521 && rlcd.value.get(entry).type==rcred.value.type) {
\r
2522 GregorianCalendar gc = org.expiration(null, exp,rcred.value.id);
\r
2523 gc = Chrono.firstMomentOfDay(gc);
\r
2524 gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay());
\r
2525 rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS);
\r
2527 rcred.value.expires = org.expiration(null,exp).getTime();
\r
2530 udr = ques.credDAO.create(trans, rcred.value);
\r
2532 udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false);
\r
2535 return Result.ok();
\r
2538 return Result.err(udr);
\r
2540 return Result.err(fd);
\r
2543 return Result.err(rcred);
\r
2551 * Codify the way to get Either Choice Needed or actual Integer from Credit Request
\r
2553 private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd) {
\r
2555 if (lcd.size() > 1) {
\r
2556 String inputOption = cr.getEntry();
\r
2557 if (inputOption == null) {
\r
2558 String message = selectCredFromList(lcd, false);
\r
2559 String[] variables = buildVariables(lcd);
\r
2560 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
\r
2562 entry = Integer.parseInt(inputOption) - 1;
\r
2564 if (entry < 0 || entry >= lcd.size()) {
\r
2565 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
\r
2568 return Result.ok(entry);
\r
2573 path = "/authn/cred/:days",
\r
2574 params = {"days|string|true"},
\r
2575 expectedCode = 200,
\r
2576 errorCodes = {300,403,404,406},
\r
2577 text = { "Extend a Credential Expiration Date. The intention of this API is",
\r
2578 "to avoid an outage in PROD due to a Credential expiring before it",
\r
2579 "can be configured correctly. Measures are being put in place ",
\r
2580 "so that this is not abused."
\r
2584 public Result<Void> extendUserCred(final AuthzTrans trans, REQUEST from, String days) {
\r
2585 TimeTaken tt = trans.start("Extend User Credential", Env.SUB);
\r
2587 Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
\r
2588 Organization org = trans.org();
\r
2589 final Validator v = new Validator();
\r
2590 if(v.notOK(cred).err() ||
\r
2591 v.nullOrBlank(cred.value.id, "Invalid ID").err() ||
\r
2592 v.user(org,cred.value.id).err()) {
\r
2593 return Result.err(Status.ERR_BadData,v.errs());
\r
2598 if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) {
\r
2599 return Result.err(Status.ERR_Policy,reason);
\r
2601 } catch (Exception e) {
\r
2603 trans.error().log(e, msg="Could not contact Organization for User Validation");
\r
2604 return Result.err(Status.ERR_Denied, msg);
\r
2607 // Get the list of Cred Entries
\r
2608 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, cred.value.id);
\r
2609 if(rlcd.notOKorIsEmpty()) {
\r
2610 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
\r
2613 //Need to do the "Pick Entry" mechanism
\r
2614 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
\r
2616 return Result.err(ri);
\r
2619 CredDAO.Data found = rlcd.value.get(ri.value);
\r
2620 CredDAO.Data cd = cred.value;
\r
2621 // Copy over the cred
\r
2622 cd.cred = found.cred;
\r
2623 cd.type = found.type;
\r
2624 cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime();
\r
2626 cred = ques.credDAO.create(trans, cd);
\r
2628 return Result.ok();
\r
2630 return Result.err(cred);
\r
2636 private String[] buildVariables(List<CredDAO.Data> value) {
\r
2637 // ensure credentials are sorted so we can fully automate Cred regression test
\r
2638 Collections.sort(value, new Comparator<CredDAO.Data>() {
\r
2640 public int compare(CredDAO.Data cred1, CredDAO.Data cred2) {
\r
2641 return cred1.expires.compareTo(cred2.expires);
\r
2644 String [] vars = new String[value.size()+1];
\r
2646 for (int i = 0; i < value.size(); i++) {
\r
2647 vars[i+1] = value.get(i).id + " " + value.get(i).type
\r
2648 + " |" + value.get(i).expires;
\r
2653 private String selectCredFromList(List<CredDAO.Data> value, boolean isDelete) {
\r
2654 StringBuilder errMessage = new StringBuilder();
\r
2655 String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:";
\r
2656 int numSpaces = value.get(0).id.length() - "Id".length();
\r
2658 errMessage.append(userPrompt + '\n');
\r
2659 errMessage.append(" Id");
\r
2660 for (int i = 0; i < numSpaces; i++) {
\r
2661 errMessage.append(' ');
\r
2663 errMessage.append(" Type Expires" + '\n');
\r
2664 for(int i=0;i<value.size();++i) {
\r
2665 errMessage.append(" %s\n");
\r
2667 errMessage.append("Run same command again with chosen entry as last parameter");
\r
2669 return errMessage.toString();
\r
2675 path = "/authn/cred",
\r
2677 expectedCode = 200,
\r
2678 errorCodes = {300,403,404,406},
\r
2679 text = { "Delete a Credential. If multiple credentials exist for this",
\r
2680 "ID, you will need to specify which entry you are deleting in the",
\r
2681 "CredRequest object."
\r
2685 public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from) {
\r
2686 final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
\r
2687 final Validator v = new Validator();
\r
2688 if(v.nullOrBlank("cred", cred.value.id).err()) {
\r
2689 return Result.err(Status.ERR_BadData,v.errs());
\r
2692 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, cred.value.id);
\r
2693 if(rlcd.notOKorIsEmpty()) {
\r
2694 // Empty Creds should have no user_roles.
\r
2695 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id);
\r
2696 if(rlurd.isOK()) {
\r
2697 for(UserRoleDAO.Data data : rlurd.value) {
\r
2698 ques.userRoleDAO.delete(trans, data, false);
\r
2701 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
\r
2703 boolean isLastCred = rlcd.value.size()==1;
\r
2705 MayChange mc = new MayChangeCred(trans,cred.value);
\r
2706 Result<?> rmc = mc.mayChange();
\r
2707 if (rmc.notOK()) {
\r
2708 return Result.err(rmc);
\r
2712 if(!trans.forceRequested()) {
\r
2713 if (rlcd.value.size() > 1) {
\r
2714 CredRequest cr = (CredRequest)from;
\r
2715 String inputOption = cr.getEntry();
\r
2716 if (inputOption == null) {
\r
2717 String message = selectCredFromList(rlcd.value, true);
\r
2718 String[] variables = buildVariables(rlcd.value);
\r
2719 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
\r
2722 entry = Integer.parseInt(inputOption) - 1;
\r
2723 } catch(NumberFormatException e) {
\r
2724 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
\r
2727 isLastCred = (entry==-1)?true:false;
\r
2729 isLastCred = true;
\r
2731 if (entry < -1 || entry >= rlcd.value.size()) {
\r
2732 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
\r
2736 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
\r
2737 new Mapper.Memo() {
\r
2739 public String get() {
\r
2740 return "Delete Credential [" +
\r
2747 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, cred.value.ns);
\r
2748 if(nsr.notOKorIsEmpty()) {
\r
2749 return Result.err(nsr);
\r
2752 switch(fd.status) {
\r
2754 Result<List<Identity>> rfc = func.createFuture(trans, fd.value, cred.value.id,
\r
2755 trans.user(), nsr.value.get(0),"D");
\r
2758 return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
\r
2760 return Result.err(rfc);
\r
2762 case Status.ACC_Now:
\r
2763 Result<?>udr = null;
\r
2764 if (!trans.forceRequested()) {
\r
2765 if(entry<0 || entry >= rlcd.value.size()) {
\r
2766 return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
\r
2768 udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false);
\r
2770 for (CredDAO.Data curr : rlcd.value) {
\r
2771 udr = ques.credDAO.delete(trans, curr, false);
\r
2772 if (udr.notOK()) {
\r
2773 return Result.err(udr);
\r
2778 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id);
\r
2779 if(rlurd.isOK()) {
\r
2780 for(UserRoleDAO.Data data : rlurd.value) {
\r
2781 ques.userRoleDAO.delete(trans, data, false);
\r
2786 return Result.ok();
\r
2788 return Result.err(udr);
\r
2790 return Result.err(fd);
\r
2797 public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
\r
2798 TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
\r
2800 // Note: Mapper assigns RAW type
\r
2801 Result<CredDAO.Data> data = mapper.cred(trans, credReq,false);
\r
2802 if(data.notOKorIsEmpty()) {
\r
2803 return Result.err(data);
\r
2805 CredDAO.Data cred = data.value; // of the Mapped Cred
\r
2806 return ques.doesUserCredMatch(trans, cred.id, cred.cred.array());
\r
2808 } catch (DAOException e) {
\r
2809 trans.error().log(e,"Error looking up cred");
\r
2810 return Result.err(Status.ERR_Denied,"Credential does not match");
\r
2818 path = "/authn/basicAuth",
\r
2820 expectedCode = 200,
\r
2821 errorCodes = { 403 },
\r
2822 text = { "Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
\r
2823 + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
\r
2824 + "security, and 403 if it does not." }
\r
2826 private void basicAuth() {
\r
2827 // This is a place holder for Documentation. The real BasicAuth API does not call Service.
\r
2832 path = "/authn/validate",
\r
2834 expectedCode = 200,
\r
2835 errorCodes = { 403 },
\r
2836 text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can "
\r
2837 + "do more than BasicAuth as Credential types exp" }
\r
2840 public Result<Date> validateBasicAuth(AuthzTrans trans, String basicAuth) {
\r
2841 //TODO how to make sure people don't use this in browsers? Do we care?
\r
2842 TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB);
\r
2844 BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm());
\r
2845 Result<Date> rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred());
\r
2846 // Note: Only want to log problem, don't want to send back to end user
\r
2850 trans.audit().log(rq.errorString());
\r
2852 } catch (Exception e) {
\r
2853 trans.warn().log(e);
\r
2857 return Result.err(Status.ERR_Denied,"Bad Basic Auth");
\r
2860 /***********************************
\r
2862 ***********************************/
\r
2865 path = "/authz/userRole",
\r
2867 expectedCode = 201,
\r
2868 errorCodes = {403,404,406,409},
\r
2869 text = { "Create a UserRole relationship (add User to Role)",
\r
2870 "A UserRole is an object Representation of membership of a Role for limited time.",
\r
2871 "If a shorter amount of time for Role ownership is required, use the 'End' field.",
\r
2872 "** Note: Owners of Namespaces will be required to revalidate users in these roles ",
\r
2873 "before Expirations expire. Namespace owners will be notified by email."
\r
2877 public Result<Void> createUserRole(final AuthzTrans trans, REQUEST from) {
\r
2878 TimeTaken tt = trans.start("Create UserRole", Env.SUB);
\r
2880 Result<UserRoleDAO.Data> urr = mapper.userRole(trans, from);
\r
2881 if(urr.notOKorIsEmpty()) {
\r
2882 return Result.err(urr);
\r
2884 final UserRoleDAO.Data userRole = urr.value;
\r
2886 final Validator v = new Validator();
\r
2887 if(v.user_role(userRole).err() ||
\r
2888 v.user(trans.org(), userRole.user).err()) {
\r
2889 return Result.err(Status.ERR_BadData,v.errs());
\r
2894 // Check if user can change first
\r
2895 Result<FutureDAO.Data> fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals
\r
2896 new Mapper.Memo() {
\r
2898 public String get() {
\r
2899 return "Add User [" + userRole.user + "] to Role [" +
\r
2905 private Result<NsDAO.Data> nsd;
\r
2907 public Result<?> mayChange() {
\r
2909 RoleDAO.Data r = RoleDAO.Data.decode(userRole);
\r
2910 nsd = ques.mayUser(trans, trans.user(), r, Access.write);
\r
2915 Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
\r
2916 if(nsr.notOKorIsEmpty()) {
\r
2917 return Result.err(nsr);
\r
2920 switch(fd.status) {
\r
2922 Result<List<Identity>> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname,
\r
2923 userRole.user, nsr.value, "C");
\r
2925 return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
\r
2930 return Result.err(rfc);
\r
2932 case Status.ACC_Now:
\r
2933 return func.addUserRole(trans, userRole);
\r
2935 return Result.err(fd);
\r
2943 * getUserRolesByRole
\r
2947 path = "/authz/userRoles/role/:role",
\r
2948 params = {"role|string|true"},
\r
2949 expectedCode = 200,
\r
2950 errorCodes = {404,406},
\r
2951 text = { "List all Users that are attached to Role specified in :role",
\r
2955 public Result<USERROLES> getUserRolesByRole(AuthzTrans trans, String role) {
\r
2956 final Validator v = new Validator(trans);
\r
2957 if(v.nullOrBlank("Role",role).err()) {
\r
2958 return Result.err(Status.ERR_BadData,v.errs());
\r
2961 Result<RoleDAO.Data> rrdd;
\r
2962 rrdd = RoleDAO.Data.decode(trans,ques,role);
\r
2963 if(rrdd.notOK()) {
\r
2964 return Result.err(rrdd);
\r
2966 // May Requester see result?
\r
2967 Result<NsDAO.Data> ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read);
\r
2969 return Result.err(ns);
\r
2972 // boolean filter = true;
\r
2973 // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user()))
\r
2974 // filter = false;
\r
2976 // Get list of roles per user, then add to Roles as we go
\r
2977 HashSet<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
\r
2978 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role);
\r
2979 if(rlurd.isOK()) {
\r
2980 for(UserRoleDAO.Data data : rlurd.value) {
\r
2981 userSet.add(data);
\r
2985 @SuppressWarnings("unchecked")
\r
2986 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
\r
2987 // Checked for permission
\r
2988 mapper.userRoles(trans, userSet, users);
\r
2989 return Result.ok(users);
\r
2992 * getUserRolesByRole
\r
2996 path = "/authz/userRoles/user/:user",
\r
2997 params = {"role|string|true"},
\r
2998 expectedCode = 200,
\r
2999 errorCodes = {404,406},
\r
3000 text = { "List all UserRoles for :user",
\r
3004 public Result<USERROLES> getUserRolesByUser(AuthzTrans trans, String user) {
\r
3005 final Validator v = new Validator(trans);
\r
3006 if(v.nullOrBlank("User",user).err()) {
\r
3007 return Result.err(Status.ERR_BadData,v.errs());
\r
3010 // Get list of roles per user, then add to Roles as we go
\r
3011 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, user);
\r
3012 if(rlurd.notOK()) {
\r
3013 return Result.err(rlurd);
\r
3015 @SuppressWarnings("unchecked")
\r
3016 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
\r
3017 // Checked for permission
\r
3018 mapper.userRoles(trans, rlurd.value, users);
\r
3019 return Result.ok(users);
\r
3025 path = "/authz/userRole/user",
\r
3027 expectedCode = 200,
\r
3028 errorCodes = {403,404,406},
\r
3029 text = { "Set a User's roles to the roles specified in the UserRoleRequest object.",
\r
3030 "WARNING: Roles supplied will be the ONLY roles attached to this user",
\r
3031 "If no roles are supplied, user's roles are reset."
\r
3035 public Result<Void> resetRolesForUser(AuthzTrans trans, REQUEST rreq) {
\r
3036 Result<UserRoleDAO.Data> rurdd = mapper.userRole(trans, rreq);
\r
3037 final Validator v = new Validator();
\r
3038 if(rurdd.notOKorIsEmpty()) {
\r
3039 return Result.err(rurdd);
\r
3041 if (v.user(trans.org(), rurdd.value.user).err()) {
\r
3042 return Result.err(Status.ERR_BadData,v.errs());
\r
3045 Set<String> currRoles = new HashSet<String>();
\r
3046 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, rurdd.value.user);
\r
3047 if(rlurd.isOK()) {
\r
3048 for(UserRoleDAO.Data data : rlurd.value) {
\r
3049 currRoles.add(data.role);
\r
3053 Result<Void> rv = null;
\r
3055 if(rurdd.value.role==null) {
\r
3056 roles = new String[0];
\r
3058 roles = rurdd.value.role.split(",");
\r
3061 for (String role : roles) {
\r
3062 if (v.role(role).err()) {
\r
3063 return Result.err(Status.ERR_BadData,v.errs());
\r
3065 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
3066 if(rrdd.notOK()) {
\r
3067 return Result.err(rrdd);
\r
3070 rurdd.value.role(rrdd.value);
\r
3072 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), rrdd.value,Access.write);
\r
3073 if (nsd.notOK()) {
\r
3074 return Result.err(nsd);
\r
3076 Result<NsDAO.Data> nsr = ques.deriveNs(trans, role);
\r
3077 if(nsr.notOKorIsEmpty()) {
\r
3078 return Result.err(nsr);
\r
3081 if(currRoles.contains(role)) {
\r
3082 currRoles.remove(role);
\r
3084 rv = func.addUserRole(trans, rurdd.value);
\r
3091 for (String role : currRoles) {
\r
3092 rurdd.value.role(trans,ques,role);
\r
3093 rv = ques.userRoleDAO.delete(trans, rurdd.value, true);
\r
3095 trans.info().log(rurdd.value.user,"/",rurdd.value.role, "expected to be deleted, but does not exist");
\r
3096 // return rv; // if it doesn't exist, don't error out
\r
3101 return Result.ok();
\r
3107 path = "/authz/userRole/role",
\r
3109 expectedCode = 200,
\r
3110 errorCodes = {403,404,406},
\r
3111 text = { "Set a Role's users to the users specified in the UserRoleRequest object.",
\r
3112 "WARNING: Users supplied will be the ONLY users attached to this role",
\r
3113 "If no users are supplied, role's users are reset."
\r
3117 public Result<Void> resetUsersForRole(AuthzTrans trans, REQUEST rreq) {
\r
3118 Result<UserRoleDAO.Data> rurdd = mapper.userRole(trans, rreq);
\r
3119 if(rurdd.notOKorIsEmpty()) {
\r
3120 return Result.err(rurdd);
\r
3122 final Validator v = new Validator();
\r
3123 if (v.user_role(rurdd.value).err()) {
\r
3124 return Result.err(Status.ERR_BadData,v.errs());
\r
3127 RoleDAO.Data rd = RoleDAO.Data.decode(rurdd.value);
\r
3129 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), rd, Access.write);
\r
3130 if (nsd.notOK()) {
\r
3131 return Result.err(nsd);
\r
3134 Result<NsDAO.Data> nsr = ques.deriveNs(trans, rurdd.value.role);
\r
3135 if(nsr.notOKorIsEmpty()) {
\r
3136 return Result.err(nsr);
\r
3139 Set<String> currUsers = new HashSet<String>();
\r
3140 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, rurdd.value.role);
\r
3141 if(rlurd.isOK()) {
\r
3142 for(UserRoleDAO.Data data : rlurd.value) {
\r
3143 currUsers.add(data.user);
\r
3147 // found when connected remotely to DEVL, can't replicate locally
\r
3148 // inconsistent errors with cmd: role user setTo [nothing]
\r
3149 // deleteUserRole --> read --> get --> cacheIdx(?)
\r
3150 // sometimes returns idx for last added user instead of user passed in
\r
3154 Result<Void> rv = null;
\r
3155 String[] users = {};
\r
3156 if (rurdd.value.user != null) {
\r
3157 users = rurdd.value.user.split(",");
\r
3160 for (String user : users) {
\r
3161 if (v.user(trans.org(), user).err()) {
\r
3162 return Result.err(Status.ERR_BadData,v.errs());
\r
3164 rurdd.value.user = user;
\r
3166 if(currUsers.contains(user)) {
\r
3167 currUsers.remove(user);
\r
3169 rv = func.addUserRole(trans, rurdd.value);
\r
3170 if (rv.notOK()) {
\r
3176 for (String user : currUsers) {
\r
3177 rurdd.value.user = user;
\r
3178 rv = ques.userRoleDAO.delete(trans, rurdd.value, true);
\r
3180 trans.info().log(rurdd.value, "expected to be deleted, but not exists");
\r
3185 return Result.ok();
\r
3190 path = "/authz/userRole/extend/:user/:role",
\r
3191 params = { "user|string|true",
\r
3192 "role|string|true"
\r
3194 expectedCode = 200,
\r
3195 errorCodes = {403,404,406},
\r
3196 text = { "Extend the Expiration of this User Role by the amount set by Organization",
\r
3197 "Requestor must be allowed to modify the role"
\r
3201 public Result<Void> extendUserRole(AuthzTrans trans, String user, String role) {
\r
3202 Organization org = trans.org();
\r
3203 final Validator v = new Validator();
\r
3204 if(v.user(org, user)
\r
3207 return Result.err(Status.ERR_BadData,v.errs());
\r
3210 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
\r
3211 if(rrdd.notOK()) {
\r
3212 return Result.err(rrdd);
\r
3215 Result<NsDAO.Data> rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write);
\r
3216 boolean mayNotChange;
\r
3217 if((mayNotChange = rcr.notOK()) && !trans.futureRequested()) {
\r
3218 return Result.err(rcr);
\r
3221 Result<List<UserRoleDAO.Data>> rr = ques.userRoleDAO.read(trans, user,role);
\r
3223 return Result.err(rr);
\r
3225 for(UserRoleDAO.Data userRole : rr.value) {
\r
3226 if(mayNotChange) { // Function exited earlier if !trans.futureRequested
\r
3227 FutureDAO.Data fto = new FutureDAO.Data();
\r
3228 fto.target=UserRoleDAO.TABLE;
\r
3229 fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]";
\r
3230 GregorianCalendar now = new GregorianCalendar();
\r
3231 fto.start = now.getTime();
\r
3232 fto.expires = org.expiration(now, Expiration.Future).getTime();
\r
3234 fto.construct = userRole.bytify();
\r
3235 } catch (IOException e) {
\r
3236 trans.error().log(e, "Error while bytifying UserRole for Future");
\r
3237 return Result.err(e);
\r
3240 Result<List<Identity>> rfc = func.createFuture(trans, fto,
\r
3241 userRole.user+'|'+userRole.role, userRole.user, rcr.value, "U");
\r
3243 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
\r
3247 return Result.err(rfc);
\r
3250 return func.extendUserRole(trans, userRole, false);
\r
3253 return Result.err(Result.ERR_NotFound,"This user and role doesn't exist");
\r
3258 path = "/authz/userRole/:user/:role",
\r
3259 params = { "user|string|true",
\r
3260 "role|string|true"
\r
3262 expectedCode = 200,
\r
3263 errorCodes = {403,404,406},
\r
3264 text = { "Remove Role :role from User :user."
\r
3268 public Result<Void> deleteUserRole(AuthzTrans trans, String usr, String role) {
\r
3269 Validator val = new Validator();
\r
3270 if(val.nullOrBlank("User", usr)
\r
3271 .nullOrBlank("Role", role).err()) {
\r
3272 return Result.err(Status.ERR_BadData, val.errs());
\r
3275 boolean mayNotChange;
\r
3276 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
\r
3277 if(rrdd.notOK()) {
\r
3278 return Result.err(rrdd);
\r
3281 RoleDAO.Data rdd = rrdd.value;
\r
3282 // Make sure we don't delete the last owner
\r
3283 if(Question.OWNER.equals(rdd.name) && ques.countOwner(trans, usr, rdd.ns)<=1) {
\r
3284 return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns );
\r
3287 Result<NsDAO.Data> rns = ques.mayUser(trans, trans.user(), rdd, Access.write);
\r
3288 if(mayNotChange=rns.notOK()) {
\r
3289 if(!trans.futureRequested()) {
\r
3290 return Result.err(rns);
\r
3294 Result<List<UserRoleDAO.Data>> rulr;
\r
3295 if((rulr=ques.userRoleDAO.read(trans, usr, role)).notOKorIsEmpty()) {
\r
3296 return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not "
\r
3297 + "Assigned to the Role [ " + role + " ]");
\r
3300 UserRoleDAO.Data userRole = rulr.value.get(0);
\r
3301 if(mayNotChange) { // Function exited earlier if !trans.futureRequested
\r
3302 FutureDAO.Data fto = new FutureDAO.Data();
\r
3303 fto.target=UserRoleDAO.TABLE;
\r
3304 fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]";
\r
3305 GregorianCalendar now = new GregorianCalendar();
\r
3306 fto.start = now.getTime();
\r
3307 fto.expires = trans.org().expiration(now, Expiration.Future).getTime();
\r
3309 Result<List<Identity>> rfc = func.createFuture(trans, fto,
\r
3310 userRole.user+'|'+userRole.role, userRole.user, rns.value, "D");
\r
3312 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
\r
3316 return Result.err(rfc);
\r
3319 return ques.userRoleDAO.delete(trans, rulr.value.get(0), false);
\r
3325 path = "/authz/userRole/:user/:role",
\r
3326 params = {"user|string|true",
\r
3327 "role|string|true"},
\r
3328 expectedCode = 200,
\r
3329 errorCodes = {403,404,406},
\r
3330 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
\r
3334 public Result<USERS> getUserInRole(AuthzTrans trans, String user, String role) {
\r
3335 final Validator v = new Validator();
\r
3336 if(v.role(role).nullOrBlank("User", user).err()) {
\r
3337 return Result.err(Status.ERR_BadData,v.errs());
\r
3340 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
\r
3341 // if (ns.notOK()) return Result.err(ns);
\r
3343 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
\r
3344 // May calling user see by virtue of the Role
\r
3345 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
3346 if(rrdd.notOK()) {
\r
3347 return Result.err(rrdd);
\r
3349 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
\r
3351 return Result.err(rnd);
\r
3354 HashSet<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
\r
3355 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readUserInRole(trans, user, role);
\r
3356 if(rlurd.isOK()) {
\r
3357 for(UserRoleDAO.Data data : rlurd.value) {
\r
3358 userSet.add(data);
\r
3362 @SuppressWarnings("unchecked")
\r
3363 USERS users = (USERS) mapper.newInstance(API.USERS);
\r
3364 mapper.users(trans, userSet, users);
\r
3365 return Result.ok(users);
\r
3370 path = "/authz/users/role/:role",
\r
3371 params = {"user|string|true",
\r
3372 "role|string|true"},
\r
3373 expectedCode = 200,
\r
3374 errorCodes = {403,404,406},
\r
3375 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
\r
3379 public Result<USERS> getUsersByRole(AuthzTrans trans, String role) {
\r
3380 final Validator v = new Validator();
\r
3381 if(v.nullOrBlank("Role",role).err()) {
\r
3382 return Result.err(Status.ERR_BadData,v.errs());
\r
3385 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
\r
3386 // if (ns.notOK()) return Result.err(ns);
\r
3388 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
\r
3389 // May calling user see by virtue of the Role
\r
3390 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
3391 if(rrdd.notOK()) {
\r
3392 return Result.err(rrdd);
\r
3394 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
\r
3396 return Result.err(rnd);
\r
3399 HashSet<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
\r
3400 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role);
\r
3401 if(rlurd.isOK()) {
\r
3402 for(UserRoleDAO.Data data : rlurd.value) {
\r
3403 userSet.add(data);
\r
3407 @SuppressWarnings("unchecked")
\r
3408 USERS users = (USERS) mapper.newInstance(API.USERS);
\r
3409 mapper.users(trans, userSet, users);
\r
3410 return Result.ok(users);
\r
3414 * getUsersByPermission
\r
3418 path = "/authz/users/perm/:type/:instance/:action",
\r
3419 params = { "type|string|true",
\r
3420 "instance|string|true",
\r
3421 "action|string|true"
\r
3423 expectedCode = 200,
\r
3424 errorCodes = {404,406},
\r
3425 text = { "List all Users that have Permission specified by :type :instance :action",
\r
3429 public Result<USERS> getUsersByPermission(AuthzTrans trans, String type, String instance, String action) {
\r
3430 final Validator v = new Validator(trans);
\r
3431 if(v.nullOrBlank("Type",type)
\r
3432 .nullOrBlank("Instance",instance)
\r
3433 .nullOrBlank("Action",action)
\r
3435 return Result.err(Status.ERR_BadData,v.errs());
\r
3438 Result<NsSplit> nss = ques.deriveNsSplit(trans, type);
\r
3440 return Result.err(nss);
\r
3443 Result<List<NsDAO.Data>> nsd = ques.nsDAO.read(trans, nss.value.ns);
\r
3444 if (nsd.notOK()) {
\r
3445 return Result.err(nsd);
\r
3448 boolean allInstance = ASTERIX.equals(instance);
\r
3449 boolean allAction = ASTERIX.equals(action);
\r
3450 // Get list of roles per Permission,
\r
3451 // Then loop through Roles to get Users
\r
3452 // Note: Use Sets to avoid processing or responding with Duplicates
\r
3453 Set<String> roleUsed = new HashSet<String>();
\r
3454 Set<UserRoleDAO.Data> userSet = new HashSet<UserRoleDAO.Data>();
\r
3456 if(!nss.isEmpty()) {
\r
3457 Result<List<PermDAO.Data>> rlp = ques.permDAO.readByType(trans, nss.value.ns, nss.value.name);
\r
3458 if(rlp.isOKhasData()) {
\r
3459 for(PermDAO.Data pd : rlp.value) {
\r
3460 if((allInstance || pd.instance.equals(instance)) &&
\r
3461 (allAction || pd.action.equals(action))) {
\r
3462 if(ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) {
\r
3463 for(String role : pd.roles) {
\r
3464 if(!roleUsed.contains(role)) { // avoid evaluating Role many times
\r
3465 roleUsed.add(role);
\r
3466 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role.replace('|', '.'));
\r
3467 if(rlurd.isOKhasData()) {
\r
3468 for(UserRoleDAO.Data urd : rlurd.value) {
\r
3479 @SuppressWarnings("unchecked")
\r
3480 USERS users = (USERS) mapper.newInstance(API.USERS);
\r
3481 mapper.users(trans, userSet, users);
\r
3482 return Result.ok(users);
\r
3485 /***********************************
\r
3487 ***********************************/
\r
3489 public Result<HISTORY> getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) {
\r
3490 final Validator v = new Validator(trans);
\r
3491 if(v.nullOrBlank("User",user).err()) {
\r
3492 return Result.err(Status.ERR_BadData,v.errs());
\r
3495 Result<NsDAO.Data> rnd;
\r
3496 // Users may look at their own data
\r
3497 if(trans.user().equals(user)) {
\r
3498 // Users may look at their own data
\r
3500 int at = user.indexOf('@');
\r
3501 if(at>=0 && trans.org().getRealm().equals(user.substring(at+1))) {
\r
3502 NsDAO.Data nsd = new NsDAO.Data();
\r
3503 nsd.name = Question.domain2ns(user);
\r
3504 rnd = ques.mayUser(trans, trans.user(), nsd, Access.read);
\r
3506 return Result.err(rnd);
\r
3509 rnd = ques.validNSOfDomain(trans, user);
\r
3511 return Result.err(rnd);
\r
3514 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
3516 return Result.err(rnd);
\r
3520 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readByUser(trans, user, yyyymm);
\r
3521 if(resp.notOK()) {
\r
3522 return Result.err(resp);
\r
3524 return mapper.history(trans, resp.value,sort);
\r
3528 public Result<HISTORY> getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) {
\r
3529 final Validator v = new Validator(trans);
\r
3530 if(v.nullOrBlank("Role",role).err()) {
\r
3531 return Result.err(Status.ERR_BadData,v.errs());
\r
3534 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
\r
3535 if(rrdd.notOK()) {
\r
3536 return Result.err(rrdd);
\r
3539 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
\r
3541 return Result.err(rnd);
\r
3543 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, role, "role", yyyymm);
\r
3544 if(resp.notOK()) {
\r
3545 return Result.err(resp);
\r
3547 return mapper.history(trans, resp.value,sort);
\r
3551 public Result<HISTORY> getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) {
\r
3552 final Validator v = new Validator(trans);
\r
3553 if(v.nullOrBlank("Type",type)
\r
3555 return Result.err(Status.ERR_BadData,v.errs());
\r
3558 // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
\r
3559 Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
\r
3561 return Result.err(rnd);
\r
3564 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
3566 return Result.err(rnd);
\r
3568 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, type, "perm", yyyymm);
\r
3569 if(resp.notOK()) {
\r
3570 return Result.err(resp);
\r
3572 return mapper.history(trans, resp.value,sort);
\r
3576 public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
\r
3577 final Validator v = new Validator(trans);
\r
3578 if(v.nullOrBlank("NS",ns)
\r
3580 return Result.err(Status.ERR_BadData,v.errs());
\r
3583 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
\r
3585 return Result.err(rnd);
\r
3587 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
\r
3589 return Result.err(rnd);
\r
3592 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, ns, "ns", yyyymm);
\r
3593 if(resp.notOK()) {
\r
3594 return Result.err(resp);
\r
3596 return mapper.history(trans, resp.value,sort);
\r
3599 /***********************************
\r
3601 ***********************************/
\r
3603 public Result<Void> createDelegate(final AuthzTrans trans, REQUEST base) {
\r
3604 return createOrUpdateDelegate(trans, base, Question.Access.create);
\r
3608 public Result<Void> updateDelegate(AuthzTrans trans, REQUEST base) {
\r
3609 return createOrUpdateDelegate(trans, base, Question.Access.write);
\r
3613 private Result<Void> createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) {
\r
3614 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
\r
3615 final Validator v = new Validator();
\r
3616 if(v.delegate(trans.org(),rd).err()) {
\r
3617 return Result.err(Status.ERR_BadData,v.errs());
\r
3620 final DelegateDAO.Data dd = rd.value;
\r
3622 Result<List<DelegateDAO.Data>> ddr = ques.delegateDAO.read(trans, dd);
\r
3623 if(access==Access.create && ddr.isOKhasData()) {
\r
3624 return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate);
\r
3625 } else if(access!=Access.create && ddr.notOKorIsEmpty()) {
\r
3626 return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name());
\r
3628 Result<Void> rv = ques.mayUser(trans, dd, access);
\r
3633 Result<FutureDAO.Data> fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false,
\r
3634 new Mapper.Memo() {
\r
3636 public String get() {
\r
3637 StringBuilder sb = new StringBuilder();
\r
3638 sb.append(access.name());
\r
3639 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
\r
3640 sb.append("Delegate ");
\r
3641 sb.append(access==Access.create?"[":"to [");
\r
3642 sb.append(rd.value.delegate);
\r
3643 sb.append("] for [");
\r
3644 sb.append(rd.value.user);
\r
3646 return sb.toString();
\r
3651 public Result<?> mayChange() {
\r
3652 return Result.ok(); // Validate in code above
\r
3656 switch(fd.status) {
\r
3658 Result<List<Identity>> rfc = func.createFuture(trans, fd.value,
\r
3659 dd.user, trans.user(),null, access==Access.create?"C":"U");
\r
3661 return Result.err(Status.ACC_Future, "Delegate for [%s]",
\r
3664 return Result.err(rfc);
\r
3666 case Status.ACC_Now:
\r
3667 if(access==Access.create) {
\r
3668 Result<DelegateDAO.Data> rdr = ques.delegateDAO.create(trans, dd);
\r
3670 return Result.ok();
\r
3672 return Result.err(rdr);
\r
3675 return ques.delegateDAO.update(trans, dd);
\r
3678 return Result.err(fd);
\r
3683 public Result<Void> deleteDelegate(AuthzTrans trans, REQUEST base) {
\r
3684 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
\r
3685 final Validator v = new Validator();
\r
3686 if(v.notOK(rd).nullOrBlank("User", rd.value.user).err()) {
\r
3687 return Result.err(Status.ERR_BadData,v.errs());
\r
3690 Result<List<DelegateDAO.Data>> ddl;
\r
3691 if((ddl=ques.delegateDAO.read(trans, rd.value)).notOKorIsEmpty()) {
\r
3692 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
\r
3694 final DelegateDAO.Data dd = ddl.value.get(0);
\r
3695 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
\r
3700 return ques.delegateDAO.delete(trans, dd, false);
\r
3704 public Result<Void> deleteDelegate(AuthzTrans trans, String userName) {
\r
3705 DelegateDAO.Data dd = new DelegateDAO.Data();
\r
3706 final Validator v = new Validator();
\r
3707 if(v.nullOrBlank("User", userName).err()) {
\r
3708 return Result.err(Status.ERR_BadData,v.errs());
\r
3710 dd.user = userName;
\r
3711 Result<List<DelegateDAO.Data>> ddl;
\r
3712 if((ddl=ques.delegateDAO.read(trans, dd)).notOKorIsEmpty()) {
\r
3713 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
\r
3715 dd = ddl.value.get(0);
\r
3716 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
\r
3721 return ques.delegateDAO.delete(trans, dd, false);
\r
3725 public Result<DELGS> getDelegatesByUser(AuthzTrans trans, String user) {
\r
3726 final Validator v = new Validator();
\r
3727 if(v.nullOrBlank("User", user).err()) {
\r
3728 return Result.err(Status.ERR_BadData,v.errs());
\r
3731 DelegateDAO.Data ddd = new DelegateDAO.Data();
\r
3733 ddd.delegate = null;
\r
3734 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
\r
3736 return Result.err(rv);
\r
3739 TimeTaken tt = trans.start("Get delegates for a user", Env.SUB);
\r
3741 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO.read(trans, user);
\r
3743 if (dbDelgs.isOKhasData()) {
\r
3744 return mapper.delegate(dbDelgs.value);
\r
3746 return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user);
\r
3754 public Result<DELGS> getDelegatesByDelegate(AuthzTrans trans, String delegate) {
\r
3755 final Validator v = new Validator();
\r
3756 if(v.nullOrBlank("Delegate", delegate).err()) {
\r
3757 return Result.err(Status.ERR_BadData,v.errs());
\r
3760 DelegateDAO.Data ddd = new DelegateDAO.Data();
\r
3761 ddd.user = delegate;
\r
3762 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
\r
3764 return Result.err(rv);
\r
3767 TimeTaken tt = trans.start("Get users for a delegate", Env.SUB);
\r
3769 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO.readByDelegate(trans, delegate);
\r
3771 if (dbDelgs.isOKhasData()) {
\r
3772 return mapper.delegate(dbDelgs.value);
\r
3774 return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate);
\r
3781 /***********************************
\r
3783 ***********************************/
\r
3785 public Result<Void> updateApproval(AuthzTrans trans, APPROVALS approvals) {
\r
3786 Result<List<ApprovalDAO.Data>> rlad = mapper.approvals(approvals);
\r
3787 if(rlad.notOK()) {
\r
3788 return Result.err(rlad);
\r
3790 int numApprs = rlad.value.size();
\r
3792 return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating");
\r
3794 int numProcessed = 0;
\r
3795 String user = trans.user();
\r
3797 Result<List<ApprovalDAO.Data>> curr;
\r
3798 for(ApprovalDAO.Data updt : rlad.value) {
\r
3799 if(updt.ticket!=null) {
\r
3800 curr = ques.approvalDAO.readByTicket(trans, updt.ticket);
\r
3801 } else if(updt.id!=null) {
\r
3802 curr = ques.approvalDAO.read(trans, updt);
\r
3803 } else if(updt.approver!=null) {
\r
3804 curr = ques.approvalDAO.readByApprover(trans, updt.approver);
\r
3806 return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update");
\r
3808 if(curr.isOKhasData()) {
\r
3809 for(ApprovalDAO.Data cd : curr.value){
\r
3810 // Check for right record. Need ID, or (Ticket&Trans.User==Appr)
\r
3812 boolean delegatedAction = ques.isDelegated(trans, user, cd.approver);
\r
3813 String delegator = cd.approver;
\r
3814 if(updt.id!=null ||
\r
3815 (updt.ticket!=null && user.equals(cd.approver)) ||
\r
3816 (updt.ticket!=null && delegatedAction)) {
\r
3817 if(updt.ticket.equals(cd.ticket)) {
\r
3818 cd.id = changed(updt.id,cd.id);
\r
3819 cd.ticket = changed(updt.ticket,cd.ticket);
\r
3820 cd.user = changed(updt.user,cd.user);
\r
3821 cd.approver = changed(updt.approver,cd.approver);
\r
3822 cd.type = changed(updt.type,cd.type);
\r
3823 cd.status = changed(updt.status,cd.status);
\r
3824 cd.memo = changed(updt.memo,cd.memo);
\r
3825 cd.operation = changed(updt.operation,cd.operation);
\r
3826 cd.updated = changed(updt.updated,cd.updated);
\r
3827 ques.approvalDAO.update(trans, cd);
\r
3828 Result<Void> rv = func.performFutureOp(trans, cd);
\r
3830 if (delegatedAction) {
\r
3831 trans.audit().log("actor=",user,",action=",updt.status,",operation=\"",cd.memo,
\r
3832 '"',",requestor=",cd.user,",delegator=",delegator);
\r
3834 if (!delegatedAction && cd.status.equalsIgnoreCase("denied")) {
\r
3835 trans.audit().log("actor=",trans.user(),",action=denied,operation=\"",cd.memo,'"',",requestor=",cd.user);
\r
3837 rv = ques.approvalDAO.delete(trans, cd, false);
\r
3847 if(numApprs==numProcessed) {
\r
3848 return Result.ok();
\r
3850 return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed");
\r
3854 private<T> T changed(T src, T dflt) {
\r
3862 public Result<APPROVALS> getApprovalsByUser(AuthzTrans trans, String user) {
\r
3863 final Validator v = new Validator();
\r
3864 if(v.nullOrBlank("User", user).err()) {
\r
3865 return Result.err(Status.ERR_BadData,v.errs());
\r
3868 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByUser(trans, user);
\r
3870 return mapper.approvals(rapd.value);
\r
3872 return Result.err(rapd);
\r
3877 public Result<APPROVALS> getApprovalsByTicket(AuthzTrans trans, String ticket) {
\r
3878 final Validator v = new Validator();
\r
3879 if(v.nullOrBlank("Ticket", ticket).err()) {
\r
3880 return Result.err(Status.ERR_BadData,v.errs());
\r
3884 uuid = UUID.fromString(ticket);
\r
3885 } catch (IllegalArgumentException e) {
\r
3886 return Result.err(Status.ERR_BadData,e.getMessage());
\r
3889 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByTicket(trans, uuid);
\r
3891 return mapper.approvals(rapd.value);
\r
3893 return Result.err(rapd);
\r
3898 public Result<APPROVALS> getApprovalsByApprover(AuthzTrans trans, String approver) {
\r
3899 final Validator v = new Validator();
\r
3900 if(v.nullOrBlank("Approver", approver).err()) {
\r
3901 return Result.err(Status.ERR_BadData,v.errs());
\r
3904 List<ApprovalDAO.Data> listRapds = new ArrayList<ApprovalDAO.Data>();
\r
3906 Result<List<ApprovalDAO.Data>> myRapd = ques.approvalDAO.readByApprover(trans, approver);
\r
3907 if(myRapd.notOK()) {
\r
3908 return Result.err(myRapd);
\r
3911 listRapds.addAll(myRapd.value);
\r
3913 Result<List<DelegateDAO.Data>> delegatedFor = ques.delegateDAO.readByDelegate(trans, approver);
\r
3914 if (delegatedFor.isOK()) {
\r
3915 for (DelegateDAO.Data dd : delegatedFor.value) {
\r
3916 if (dd.expires.after(new Date())) {
\r
3917 String delegator = dd.user;
\r
3918 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByApprover(trans, delegator);
\r
3919 if (rapd.isOK()) {
\r
3920 for (ApprovalDAO.Data d : rapd.value) {
\r
3921 if (!d.user.equals(trans.user())) {
\r
3930 return mapper.approvals(listRapds);
\r
3934 * @see com.att.authz.service.AuthzService#clearCache(com.att.authz.env.AuthzTrans, java.lang.String)
\r
3937 public Result<Void> cacheClear(AuthzTrans trans, String cname) {
\r
3938 if(ques.isGranted(trans,trans.user(),Define.ROOT_NS,CACHE,cname,"clear")) {
\r
3939 return ques.clearCache(trans,cname);
\r
3941 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.cache|%s|clear",
\r
3942 trans.user(),Define.ROOT_NS,cname);
\r
3946 * @see com.att.authz.service.AuthzService#cacheClear(com.att.authz.env.AuthzTrans, java.lang.String, java.lang.Integer)
\r
3949 public Result<Void> cacheClear(AuthzTrans trans, String cname, int[] segment) {
\r
3950 if(ques.isGranted(trans,trans.user(),Define.ROOT_NS,CACHE,cname,"clear")) {
\r
3951 Result<Void> v=null;
\r
3952 for(int i: segment) {
\r
3953 v=ques.cacheClear(trans,cname,i);
\r
3959 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.cache|%s|clear",
\r
3960 trans.user(),Define.ROOT_NS,cname);
\r
3964 * @see com.att.authz.service.AuthzService#dbReset(com.att.authz.env.AuthzTrans)
\r
3967 public void dbReset(AuthzTrans trans) {
\r
3968 ques.historyDAO.reportPerhapsReset(trans, null);
\r