1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
23 package org.onap.aaf.dao.aaf.hl;
\r
25 import java.io.IOException;
\r
26 import java.nio.ByteBuffer;
\r
27 import java.security.NoSuchAlgorithmException;
\r
28 import java.security.SecureRandom;
\r
29 import java.util.ArrayList;
\r
30 import java.util.Collections;
\r
31 import java.util.Comparator;
\r
32 import java.util.Date;
\r
33 import java.util.HashSet;
\r
34 import java.util.List;
\r
35 import java.util.Set;
\r
36 import java.util.TreeSet;
\r
38 import org.onap.aaf.authz.common.Define;
\r
39 import org.onap.aaf.authz.env.AuthzTrans;
\r
40 import org.onap.aaf.authz.env.AuthzTransFilter;
\r
41 import org.onap.aaf.authz.layer.Result;
\r
42 import org.onap.aaf.authz.org.Organization;
\r
43 import org.onap.aaf.authz.org.Organization.Identity;
\r
44 import org.onap.aaf.dao.AbsCassDAO;
\r
45 import org.onap.aaf.dao.CachedDAO;
\r
46 import org.onap.aaf.dao.DAOException;
\r
47 import org.onap.aaf.dao.aaf.cached.CachedCertDAO;
\r
48 import org.onap.aaf.dao.aaf.cached.CachedCredDAO;
\r
49 import org.onap.aaf.dao.aaf.cached.CachedNSDAO;
\r
50 import org.onap.aaf.dao.aaf.cached.CachedPermDAO;
\r
51 import org.onap.aaf.dao.aaf.cached.CachedRoleDAO;
\r
52 import org.onap.aaf.dao.aaf.cached.CachedUserRoleDAO;
\r
53 import org.onap.aaf.dao.aaf.cass.ApprovalDAO;
\r
54 import org.onap.aaf.dao.aaf.cass.CacheInfoDAO;
\r
55 import org.onap.aaf.dao.aaf.cass.CertDAO;
\r
56 import org.onap.aaf.dao.aaf.cass.CredDAO;
\r
57 import org.onap.aaf.dao.aaf.cass.DelegateDAO;
\r
58 import org.onap.aaf.dao.aaf.cass.FutureDAO;
\r
59 import org.onap.aaf.dao.aaf.cass.HistoryDAO;
\r
60 import org.onap.aaf.dao.aaf.cass.NsDAO;
\r
61 import org.onap.aaf.dao.aaf.cass.NsSplit;
\r
62 import org.onap.aaf.dao.aaf.cass.NsType;
\r
63 import org.onap.aaf.dao.aaf.cass.PermDAO;
\r
64 import org.onap.aaf.dao.aaf.cass.RoleDAO;
\r
65 import org.onap.aaf.dao.aaf.cass.Status;
\r
66 import org.onap.aaf.dao.aaf.cass.UserRoleDAO;
\r
67 import org.onap.aaf.dao.aaf.cass.NsDAO.Data;
\r
69 import org.onap.aaf.cadi.Hash;
\r
70 import org.onap.aaf.cadi.aaf.PermEval;
\r
71 import org.onap.aaf.inno.env.APIException;
\r
72 import org.onap.aaf.inno.env.Env;
\r
73 import org.onap.aaf.inno.env.Slot;
\r
74 import org.onap.aaf.inno.env.TimeTaken;
\r
75 import org.onap.aaf.inno.env.util.Chrono;
\r
76 import com.datastax.driver.core.Cluster;
\r
81 * A Data Access Combination Object which asks Security and other Questions
\r
85 public class Question {
\r
86 // DON'T CHANGE FROM lower Case!!!
\r
87 public static enum Type {
\r
88 ns, role, perm, cred
\r
91 public static final String OWNER="owner";
\r
92 public static final String ADMIN="admin";
\r
93 public static final String DOT_OWNER=".owner";
\r
94 public static final String DOT_ADMIN=".admin";
\r
95 static final String ASTERIX = "*";
\r
97 public static enum Access {
\r
101 public static final String READ = Access.read.name();
\r
102 public static final String WRITE = Access.write.name();
\r
103 public static final String CREATE = Access.create.name();
\r
105 public static final String ROLE = Type.role.name();
\r
106 public static final String PERM = Type.perm.name();
\r
107 public static final String NS = Type.ns.name();
\r
108 public static final String CRED = Type.cred.name();
\r
109 private static final String DELG = "delg";
\r
110 public static final String ATTRIB = "attrib";
\r
113 public static final int MAX_SCOPE = 10;
\r
114 public static final int APP_SCOPE = 3;
\r
115 public static final int COMPANY_SCOPE = 2;
\r
118 private static Set<String> specialLog = null;
\r
119 public static final SecureRandom random = new SecureRandom();
\r
120 private static long traceID = random.nextLong();
\r
121 private static final String SPECIAL_LOG_SLOT = "SPECIAL_LOG_SLOT";
\r
122 private static Slot specialLogSlot = null;
\r
123 private static Slot transIDSlot = null;
\r
126 public final HistoryDAO historyDAO;
\r
127 public final CachedNSDAO nsDAO;
\r
128 public final CachedRoleDAO roleDAO;
\r
129 public final CachedPermDAO permDAO;
\r
130 public final CachedUserRoleDAO userRoleDAO;
\r
131 public final CachedCredDAO credDAO;
\r
132 public final CachedCertDAO certDAO;
\r
133 public final DelegateDAO delegateDAO;
\r
134 public final FutureDAO futureDAO;
\r
135 public final ApprovalDAO approvalDAO;
\r
136 private final CacheInfoDAO cacheInfoDAO;
\r
138 // final ContactDAO contDAO;
\r
139 // private static final String DOMAIN = "@aaf.att.com";
\r
140 // private static final int DOMAIN_LENGTH = 0;
\r
142 public Question(AuthzTrans trans, Cluster cluster, String keyspace, boolean startClean) throws APIException, IOException {
\r
143 PERMS = trans.slot("USER_PERMS");
\r
144 trans.init().log("Instantiating DAOs");
\r
145 historyDAO = new HistoryDAO(trans, cluster, keyspace);
\r
147 // Deal with Cached Entries
\r
148 cacheInfoDAO = new CacheInfoDAO(trans, historyDAO);
\r
150 nsDAO = new CachedNSDAO(new NsDAO(trans, historyDAO, cacheInfoDAO),
\r
152 permDAO = new CachedPermDAO(
\r
153 new PermDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO);
\r
154 roleDAO = new CachedRoleDAO(
\r
155 new RoleDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO);
\r
156 userRoleDAO = new CachedUserRoleDAO(new UserRoleDAO(trans, historyDAO,
\r
157 cacheInfoDAO), cacheInfoDAO);
\r
158 credDAO = new CachedCredDAO(
\r
159 new CredDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO);
\r
160 certDAO = new CachedCertDAO(
\r
161 new CertDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO);
\r
163 futureDAO = new FutureDAO(trans, historyDAO);
\r
164 delegateDAO = new DelegateDAO(trans, historyDAO);
\r
165 approvalDAO = new ApprovalDAO(trans, historyDAO);
\r
167 // Only want to aggressively cleanse User related Caches... The others,
\r
168 // just normal refresh
\r
170 CachedDAO.startCleansing(trans.env(), credDAO, userRoleDAO);
\r
171 CachedDAO.startRefresh(trans.env(), cacheInfoDAO);
\r
173 // Set a Timer to Check Caches to send messages for Caching changes
\r
175 if(specialLogSlot==null) {
\r
176 specialLogSlot = trans.slot(SPECIAL_LOG_SLOT);
\r
177 transIDSlot = trans.slot(AuthzTransFilter.TRANS_ID_SLOT);
\r
180 AbsCassDAO.primePSIs(trans);
\r
184 public void close(AuthzTrans trans) {
\r
185 historyDAO.close(trans);
\r
186 cacheInfoDAO.close(trans);
\r
187 nsDAO.close(trans);
\r
188 permDAO.close(trans);
\r
189 roleDAO.close(trans);
\r
190 userRoleDAO.close(trans);
\r
191 credDAO.close(trans);
\r
192 certDAO.close(trans);
\r
193 delegateDAO.close(trans);
\r
194 futureDAO.close(trans);
\r
195 approvalDAO.close(trans);
\r
198 public Result<PermDAO.Data> permFrom(AuthzTrans trans, String type,
\r
199 String instance, String action) {
\r
200 Result<NsDAO.Data> rnd = deriveNs(trans, type);
\r
202 return Result.ok(new PermDAO.Data(new NsSplit(rnd.value, type),
\r
203 instance, action));
\r
205 return Result.err(rnd);
\r
212 * Because this call is frequently called internally, AND because we already
\r
213 * look for it in the initial Call, we cache within the Transaction
\r
219 public Result<List<PermDAO.Data>> getPermsByUser(AuthzTrans trans, String user, boolean lookup) {
\r
220 return PermLookup.get(trans, this, user).getPerms(lookup);
\r
223 public Result<List<PermDAO.Data>> getPermsByUserFromRolesFilter(AuthzTrans trans, String user, String forUser) {
\r
224 PermLookup plUser = PermLookup.get(trans, this, user);
\r
225 Result<Set<String>> plPermNames = plUser.getPermNames();
\r
226 if(plPermNames.notOK()) {
\r
227 return Result.err(plPermNames);
\r
231 if(forUser.equals(user)) {
\r
234 // Setup a TreeSet to check on Namespaces to
\r
235 nss = new TreeSet<String>();
\r
236 PermLookup fUser = PermLookup.get(trans, this, forUser);
\r
237 Result<Set<String>> forUpn = fUser.getPermNames();
\r
238 if(forUpn.notOK()) {
\r
239 return Result.err(forUpn);
\r
242 for(String pn : forUpn.value) {
\r
243 Result<String[]> decoded = PermDAO.Data.decodeToArray(trans, this, pn);
\r
244 if(decoded.isOKhasData()) {
\r
245 nss.add(decoded.value[0]);
\r
247 trans.error().log(pn,", derived from a Role, is invalid:",decoded.errorString());
\r
252 List<PermDAO.Data> rlpUser = new ArrayList<PermDAO.Data>();
\r
253 Result<PermDAO.Data> rpdd;
\r
255 for(String pn : plPermNames.value) {
\r
256 rpdd = PermDAO.Data.decode(trans, this, pn);
\r
257 if(rpdd.isOKhasData()) {
\r
259 if(nss==null || nss.contains(pdd.ns)) {
\r
263 trans.error().log(pn,", derived from a Role, is invalid. Run Data Cleanup:",rpdd.errorString());
\r
266 return Result.ok(rlpUser);
\r
269 public Result<List<PermDAO.Data>> getPermsByType(AuthzTrans trans, String perm) {
\r
270 Result<NsSplit> nss = deriveNsSplit(trans, perm);
\r
272 return Result.err(nss);
\r
274 return permDAO.readByType(trans, nss.value.ns, nss.value.name);
\r
277 public Result<List<PermDAO.Data>> getPermsByName(AuthzTrans trans,
\r
278 String type, String instance, String action) {
\r
279 Result<NsSplit> nss = deriveNsSplit(trans, type);
\r
281 return Result.err(nss);
\r
283 return permDAO.read(trans, nss.value.ns, nss.value.name, instance,action);
\r
286 public Result<List<PermDAO.Data>> getPermsByRole(AuthzTrans trans, String role, boolean lookup) {
\r
287 Result<NsSplit> nss = deriveNsSplit(trans, role);
\r
289 return Result.err(nss);
\r
292 Result<List<RoleDAO.Data>> rlrd = roleDAO.read(trans, nss.value.ns,
\r
294 if (rlrd.notOKorIsEmpty()) {
\r
295 return Result.err(rlrd);
\r
297 // Using Set to avoid duplicates
\r
298 Set<String> permNames = new HashSet<String>();
\r
299 if (rlrd.isOKhasData()) {
\r
300 for (RoleDAO.Data drr : rlrd.value) {
\r
301 permNames.addAll(drr.perms(false));
\r
305 // Note: It should be ok for a Valid user to have no permissions -
\r
307 List<PermDAO.Data> perms = new ArrayList<PermDAO.Data>();
\r
308 for (String perm : permNames) {
\r
309 Result<PermDAO.Data> pr = PermDAO.Data.decode(trans, this, perm);
\r
311 return Result.err(pr);
\r
315 Result<List<PermDAO.Data>> rlpd = permDAO.read(trans, pr.value);
\r
316 if (rlpd.isOKhasData()) {
\r
317 for (PermDAO.Data pData : rlpd.value) {
\r
322 perms.add(pr.value);
\r
326 return Result.ok(perms);
\r
329 public Result<List<RoleDAO.Data>> getRolesByName(AuthzTrans trans,
\r
331 Result<NsSplit> nss = deriveNsSplit(trans, role);
\r
333 return Result.err(nss);
\r
335 String r = nss.value.name;
\r
336 if (r.endsWith(".*")) { // do children Search
\r
337 return roleDAO.readChildren(trans, nss.value.ns,
\r
338 r.substring(0, r.length() - 2));
\r
339 } else if (ASTERIX.equals(r)) {
\r
340 return roleDAO.readChildren(trans, nss.value.ns, ASTERIX);
\r
342 return roleDAO.read(trans, nss.value.ns, r);
\r
349 * Given a Child Namespace, figure out what the best Namespace parent is.
\r
351 * For instance, if in the NS table, the parent "com.att" exists, but not
\r
352 * "com.att.child" or "com.att.a.b.c", then passing in either
\r
353 * "com.att.child" or "com.att.a.b.c" will return "com.att"
\r
355 * Uses recursive search on Cached DAO data
\r
361 public Result<NsDAO.Data> deriveNs(AuthzTrans trans, String child) {
\r
362 Result<List<NsDAO.Data>> r = nsDAO.read(trans, child);
\r
364 if (r.isOKhasData()) {
\r
365 return Result.ok(r.value.get(0));
\r
367 int dot = child == null ? -1 : child.lastIndexOf('.');
\r
369 return Result.err(Status.ERR_NsNotFound,
\r
370 "No Namespace for [%s]", child);
\r
372 return deriveNs(trans, child.substring(0, dot));
\r
377 public Result<NsDAO.Data> deriveFirstNsForType(AuthzTrans trans, String str, NsType type) {
\r
380 System.out.println("value of str before for loop ---------0---++++++++++++++++++" +str);
\r
381 for(int idx = str.indexOf('.');idx>=0;idx=str.indexOf('.',idx+1)) {
\r
382 // System.out.println("printing value of str-----------------1------------++++++++++++++++++++++" +str);
\r
383 Result<List<Data>> rld = nsDAO.read(trans, str.substring(0,idx));
\r
384 System.out.println("value of idx is -----------------++++++++++++++++++++++++++" +idx);
\r
385 System.out.println("printing value of str.substring-----------------1------------++++++++++++++++++++++" + (str.substring(0,idx)));
\r
386 System.out.println("value of ResultListData ------------------2------------+++++++++++++++++++++++++++" +rld);
\r
387 if(rld.isOKhasData()) {
\r
388 System.out.println("In if loop -----------------3-------------- ++++++++++++++++");
\r
389 System.out.println("value of nsd=rld.value.get(0).type -----------4------++++++++++++++++++++++++++++++++++++" +(nsd=rld.value.get(0)).type);
\r
390 System.out.println("value of rld.value.get(0).name.toString()+++++++++++++++++++++++++++++++ " +rld.value.get(0).name);
\r
391 if(type.type == (nsd=rld.value.get(0)).type) {
\r
392 return Result.ok(nsd);
\r
395 System.out.println("In else loop ----------------4------------+++++++++++++++++++++++");
\r
396 return Result.err(Status.ERR_NsNotFound,"There is no valid Company Namespace for %s",str.substring(0,idx));
\r
399 return Result.err(Status.ERR_NotFound, str + " does not contain type " + type.name());
\r
402 public Result<NsSplit> deriveNsSplit(AuthzTrans trans, String child) {
\r
403 Result<NsDAO.Data> ndd = deriveNs(trans, child);
\r
405 NsSplit nss = new NsSplit(ndd.value, child);
\r
407 return Result.ok(nss);
\r
409 return Result.err(Status.ERR_NsNotFound,
\r
410 "Cannot split [%s] into valid namespace elements",
\r
414 return Result.err(ndd);
\r
418 * Translate an ID into it's domain
\r
420 * i.e. myid1234@myapp.att.com results in domain of com.att.myapp
\r
425 public static String domain2ns(String id) {
\r
426 int at = id.indexOf('@');
\r
428 String[] domain = id.substring(at + 1).split("\\.");
\r
429 StringBuilder ns = new StringBuilder(id.length());
\r
430 boolean first = true;
\r
431 for (int i = domain.length - 1; i >= 0; --i) {
\r
437 ns.append(domain[i]);
\r
439 return ns.toString();
\r
447 * Validate Namespace of ID@Domain
\r
449 * Namespace is reverse order of Domain.
\r
451 * i.e. myid1234@myapp.att.com results in domain of com.att.myapp
\r
457 public Result<NsDAO.Data> validNSOfDomain(AuthzTrans trans, String id) {
\r
458 // Take domain, reverse order, and check on NS
\r
460 if(id.indexOf('@')<0) { // it's already an ns, not an ID
\r
463 ns = domain2ns(id);
\r
465 if (ns.length() > 0) {
\r
466 if(!trans.org().getDomain().equals(ns)) {
\r
467 Result<List<NsDAO.Data>> rlnsd = nsDAO.read(trans, ns);
\r
468 if (rlnsd.isOKhasData()) {
\r
469 return Result.ok(rlnsd.value.get(0));
\r
473 return Result.err(Status.ERR_NsNotFound,
\r
474 "A Namespace is not available for %s", id);
\r
477 public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,NsDAO.Data ndd, Access access) {
\r
478 // <ns>.access|:role:<role name>|<read|write>
\r
479 String ns = ndd.name;
\r
482 if (isGranted(trans, user, ns, "access", ":ns", access.name())) {
\r
483 return Result.ok(ndd);
\r
485 if ((last = ns.lastIndexOf('.')) >= 0) {
\r
486 ns = ns.substring(0, last);
\r
488 } while (last >= 0);
\r
489 // <root ns>.ns|:<client ns>:ns|<access>
\r
490 // AAF-724 - Make consistent response for May User", and not take the
\r
491 // last check... too confusing.
\r
492 Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":" + ndd.name + ":ns", access.name());
\r
495 } else if(rv.status==Result.ERR_Backend) {
\r
496 return Result.err(rv);
\r
498 return Result.err(Status.ERR_Denied, "[%s] may not %s in NS [%s]",
\r
499 user, access.name(), ndd.name);
\r
503 public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user, RoleDAO.Data rdd, Access access) {
\r
504 Result<NsDAO.Data> rnsd = deriveNs(trans, rdd.ns);
\r
506 return mayUser(trans, user, rnsd.value, rdd, access);
\r
511 public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user, NsDAO.Data ndd, RoleDAO.Data rdd, Access access) {
\r
512 // 1) Is User in the Role?
\r
513 Result<List<UserRoleDAO.Data>> rurd = userRoleDAO.readUserInRole(trans, user, rdd.fullName());
\r
514 if (rurd.isOKhasData()) {
\r
515 return Result.ok(ndd);
\r
518 String roleInst = ":role:" + rdd.name;
\r
519 // <ns>.access|:role:<role name>|<read|write>
\r
520 String ns = rdd.ns;
\r
523 if (isGranted(trans, user, ns,"access", roleInst, access.name())) {
\r
524 return Result.ok(ndd);
\r
526 if ((last = ns.lastIndexOf('.')) >= 0) {
\r
527 ns = ns.substring(0, last);
\r
529 } while (last >= 0);
\r
531 // Check if Access by Global Role perm
\r
532 // <root ns>.ns|:<client ns>:role:name|<access>
\r
533 Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":"
\r
534 + rdd.ns + roleInst, access.name());
\r
537 } else if(rnsd.status==Result.ERR_Backend) {
\r
538 return Result.err(rnsd);
\r
541 // Check if Access to Whole NS
\r
542 // AAF-724 - Make consistent response for May User", and not take the
\r
543 // last check... too confusing.
\r
544 Result<org.onap.aaf.dao.aaf.cass.NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd,
\r
545 ":" + rdd.ns + ":ns", access.name());
\r
548 } else if(rnsd.status==Result.ERR_Backend) {
\r
549 return Result.err(rnsd);
\r
551 return Result.err(Status.ERR_Denied, "[%s] may not %s Role [%s]",
\r
552 user, access.name(), rdd.fullName());
\r
557 public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,PermDAO.Data pdd, Access access) {
\r
558 Result<NsDAO.Data> rnsd = deriveNs(trans, pdd.ns);
\r
560 return mayUser(trans, user, rnsd.value, pdd, access);
\r
565 public Result<NsDAO.Data> mayUser(AuthzTrans trans, String user,NsDAO.Data ndd, PermDAO.Data pdd, Access access) {
\r
566 if (isGranted(trans, user, pdd.ns, pdd.type, pdd.instance, pdd.action)) {
\r
567 return Result.ok(ndd);
\r
569 String permInst = ":perm:" + pdd.type + ':' + pdd.instance + ':' + pdd.action;
\r
570 // <ns>.access|:role:<role name>|<read|write>
\r
571 String ns = ndd.name;
\r
574 if (isGranted(trans, user, ns, "access", permInst, access.name())) {
\r
575 return Result.ok(ndd);
\r
577 if ((last = ns.lastIndexOf('.')) >= 0) {
\r
578 ns = ns.substring(0, last);
\r
580 } while (last >= 0);
\r
582 // Check if Access by NS perm
\r
583 // <root ns>.ns|:<client ns>:role:name|<access>
\r
584 Result<NsDAO.Data> rnsd = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + permInst, access.name());
\r
587 } else if(rnsd.status==Result.ERR_Backend) {
\r
588 return Result.err(rnsd);
\r
591 // Check if Access to Whole NS
\r
592 // AAF-724 - Make consistent response for May User", and not take the
\r
593 // last check... too confusing.
\r
594 Result<NsDAO.Data> rv = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + ":ns", access.name());
\r
598 return Result.err(Status.ERR_Denied,
\r
599 "[%s] may not %s Perm [%s|%s|%s]", user, access.name(),
\r
600 pdd.fullType(), pdd.instance, pdd.action);
\r
605 public Result<Void> mayUser(AuthzTrans trans, DelegateDAO.Data dd, Access access) {
\r
607 boolean isUser = trans.user().equals(dd.user);
\r
608 boolean isDelegate = dd.delegate != null
\r
609 && (dd.user.equals(dd.delegate) || trans.user().equals(
\r
611 Organization org = trans.org();
\r
614 if (org.getIdentity(trans, dd.user) == null) {
\r
615 return Result.err(Status.ERR_UserNotFound,
\r
616 "[%s] is not a user in the company database.",
\r
619 if (!dd.user.equals(dd.delegate) && org.getIdentity(trans, dd.delegate) == null) {
\r
620 return Result.err(Status.ERR_UserNotFound,
\r
621 "[%s] is not a user in the company database.",
\r
624 if (!trans.forceRequested() && dd.user != null && dd.user.equals(dd.delegate)) {
\r
625 return Result.err(Status.ERR_BadData,
\r
626 "[%s] cannot be a delegate for self", dd.user);
\r
628 if (!isUser && !isGranted(trans, trans.user(), Define.ROOT_NS,DELG,
\r
629 org.getDomain(), Question.CREATE)) {
\r
630 return Result.err(Status.ERR_Denied,
\r
631 "[%s] may not create a delegate for [%s]",
\r
632 trans.user(), dd.user);
\r
637 if (!isUser && !isDelegate &&
\r
638 !isGranted(trans, trans.user(), Define.ROOT_NS,DELG,org.getDomain(), access.name())) {
\r
639 return Result.err(Status.ERR_Denied,
\r
640 "[%s] may not %s delegates for [%s]", trans.user(),
\r
641 access.name(), dd.user);
\r
645 return Result.err(Status.ERR_BadData,"Unknown Access type [%s]", access.name());
\r
647 } catch (Exception e) {
\r
648 return Result.err(e);
\r
650 return Result.ok();
\r
654 * Check (recursively, if necessary), if able to do something based on NS
\r
656 private Result<NsDAO.Data> mayUserVirtueOfNS(AuthzTrans trans, String user, NsDAO.Data nsd, String ns_and_type, String access) {
\r
657 String ns = nsd.name;
\r
659 // If an ADMIN of the Namespace, then allow
\r
661 Result<List<UserRoleDAO.Data>> rurd;
\r
662 if ((rurd = userRoleDAO.readUserInRole(trans, user, nsd.name+ADMIN)).isOKhasData()) {
\r
663 return Result.ok(nsd);
\r
664 } else if(rurd.status==Result.ERR_Backend) {
\r
665 return Result.err(rurd);
\r
668 // If Specially granted Global Permission
\r
669 if (isGranted(trans, user, Define.ROOT_NS,NS, ns_and_type, access)) {
\r
670 return Result.ok(nsd);
\r
675 int dot = ns.length();
\r
676 if ((dot = ns.lastIndexOf('.', dot - 1)) >= 0) {
\r
677 Result<NsDAO.Data> rnsd = deriveNs(trans, ns.substring(0, dot));
\r
679 rnsd = mayUserVirtueOfNS(trans, user, rnsd.value, ns_and_type,access);
\r
680 } else if(rnsd.status==Result.ERR_Backend) {
\r
681 return Result.err(rnsd);
\r
684 return Result.ok(nsd);
\r
685 } else if(rnsd.status==Result.ERR_Backend) {
\r
686 return Result.err(rnsd);
\r
689 return Result.err(Status.ERR_Denied, "%s may not %s %s", user, access,
\r
697 * Important function - Check internal Permission Schemes for Permission to
\r
706 public boolean isGranted(AuthzTrans trans, String user, String ns, String type,String instance, String action) {
\r
707 Result<List<PermDAO.Data>> perms = getPermsByUser(trans, user, false);
\r
708 if (perms.isOK()) {
\r
709 for (PermDAO.Data pd : perms.value) {
\r
710 if (ns.equals(pd.ns)) {
\r
711 if (type.equals(pd.type)) {
\r
712 if (PermEval.evalInstance(pd.instance, instance)) {
\r
713 if(PermEval.evalAction(pd.action, action)) { // don't return action here, might miss other action
\r
724 public Result<Date> doesUserCredMatch(AuthzTrans trans, String user, byte[] cred) throws DAOException {
\r
725 Result<List<CredDAO.Data>> result;
\r
726 TimeTaken tt = trans.start("Read DB Cred", Env.REMOTE);
\r
728 result = credDAO.readID(trans, user);
\r
733 Result<Date> rv = null;
\r
734 if(result.isOK()) {
\r
735 if (result.isEmpty()) {
\r
736 rv = Result.err(Status.ERR_UserNotFound, user);
\r
737 if (willSpecialLog(trans,user)) {
\r
738 trans.audit().log("Special DEBUG:", user, " does not exist in DB");
\r
741 Date now = new Date();//long now = System.currentTimeMillis();
\r
742 ByteBuffer md5=null;
\r
744 // Bug noticed 6/22. Sorting on the result can cause Concurrency Issues.
\r
745 List<CredDAO.Data> cddl;
\r
746 if(result.value.size() > 1) {
\r
747 cddl = new ArrayList<CredDAO.Data>(result.value.size());
\r
748 for(CredDAO.Data old : result.value) {
\r
749 if(old.type==CredDAO.BASIC_AUTH || old.type==CredDAO.BASIC_AUTH_SHA256) {
\r
753 if(cddl.size()>1) {
\r
754 Collections.sort(cddl,new Comparator<CredDAO.Data>() {
\r
756 public int compare(org.onap.aaf.dao.aaf.cass.CredDAO.Data a,
\r
757 org.onap.aaf.dao.aaf.cass.CredDAO.Data b) {
\r
758 return b.expires.compareTo(a.expires);
\r
763 cddl = result.value;
\r
766 for (CredDAO.Data cdd : cddl) {
\r
767 if (cdd.expires.after(now)) {
\r
770 case CredDAO.BASIC_AUTH:
\r
772 md5=ByteBuffer.wrap(Hash.encryptMD5(cred));
\r
774 if(md5.compareTo(cdd.cred)==0) {
\r
775 return Result.ok(cdd.expires);
\r
776 } else if (willSpecialLog(trans,user)) {
\r
777 trans.audit().log("Special DEBUG:", user, "Client sent: ", trans.encryptor().encrypt(new String(cred)) ,cdd.expires);
\r
780 case CredDAO.BASIC_AUTH_SHA256:
\r
781 ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE + cred.length);
\r
782 bb.putInt(cdd.other);
\r
784 byte[] hash = Hash.hashSHA256(bb.array());
\r
786 ByteBuffer sha256 = ByteBuffer.wrap(hash);
\r
787 if(sha256.compareTo(cdd.cred)==0) {
\r
788 return Result.ok(cdd.expires);
\r
789 } else if (willSpecialLog(trans,user)) {
\r
790 trans.audit().log("Special DEBUG:", user, "Client sent: ", trans.encryptor().encrypt(new String(cred)) ,cdd.expires);
\r
794 trans.error().log("Unknown Credential Type %s for %s, %s",Integer.toString(cdd.type),cdd.id, Chrono.dateTime(cdd.expires));
\r
796 } catch (NoSuchAlgorithmException e) {
\r
797 trans.error().log(e);
\r
800 rv = Result.err(Status.ERR_Security,
\r
801 "Credentials expired " + cdd.expires.toString());
\r
806 return Result.err(result);
\r
808 return rv == null ? Result.create((Date) null, Status.ERR_Security,
\r
809 "Wrong credential") : rv;
\r
813 public Result<CredDAO.Data> userCredSetup(AuthzTrans trans, CredDAO.Data cred) {
\r
814 if(cred.type==CredDAO.RAW) {
\r
815 TimeTaken tt = trans.start("Hash Cred", Env.SUB);
\r
817 cred.type = CredDAO.BASIC_AUTH_SHA256;
\r
818 cred.other = random.nextInt();
\r
819 ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE + cred.cred.capacity());
\r
820 bb.putInt(cred.other);
\r
822 byte[] hash = Hash.hashSHA256(bb.array());
\r
823 cred.cred = ByteBuffer.wrap(hash);
\r
824 return Result.ok(cred);
\r
825 } catch (NoSuchAlgorithmException e) {
\r
826 return Result.err(Status.ERR_General,e.getLocalizedMessage());
\r
832 return Result.err(Status.ERR_Security,"invalid/unreadable credential");
\r
836 public static final String APPROVED = "APPROVE";
\r
837 public static final String REJECT = "REJECT";
\r
838 public static final String PENDING = "PENDING";
\r
840 public Result<Void> canAddUser(AuthzTrans trans, UserRoleDAO.Data data,
\r
841 List<ApprovalDAO.Data> approvals) {
\r
842 // get the approval policy for the organization
\r
844 // get the list of approvals with an accept status
\r
846 // validate the approvals against the policy
\r
848 // for now check if all approvals are received and return
\r
849 // SUCCESS/FAILURE/SKIP
\r
850 boolean bReject = false;
\r
851 boolean bPending = false;
\r
853 for (ApprovalDAO.Data approval : approvals) {
\r
854 if (approval.status.equals(REJECT)) {
\r
856 } else if (approval.status.equals(PENDING)) {
\r
861 return Result.err(Status.ERR_Policy,
\r
862 "Approval Polocy not conformed");
\r
865 return Result.err(Status.ERR_ActionNotCompleted,
\r
866 "Required Approvals not received");
\r
869 return Result.ok();
\r
872 private static final String NO_CACHE_NAME = "No Cache Data named %s";
\r
874 public Result<Void> clearCache(AuthzTrans trans, String cname) {
\r
875 boolean all = "all".equals(cname);
\r
876 Result<Void> rv = null;
\r
878 if (all || NsDAO.TABLE.equals(cname)) {
\r
879 int seg[] = series(NsDAO.CACHE_SEG);
\r
880 for(int i: seg) {cacheClear(trans, NsDAO.TABLE,i);}
\r
881 rv = cacheInfoDAO.touch(trans, NsDAO.TABLE, seg);
\r
883 if (all || PermDAO.TABLE.equals(cname)) {
\r
884 int seg[] = series(NsDAO.CACHE_SEG);
\r
885 for(int i: seg) {cacheClear(trans, PermDAO.TABLE,i);}
\r
886 rv = cacheInfoDAO.touch(trans, PermDAO.TABLE,seg);
\r
888 if (all || RoleDAO.TABLE.equals(cname)) {
\r
889 int seg[] = series(NsDAO.CACHE_SEG);
\r
890 for(int i: seg) {cacheClear(trans, RoleDAO.TABLE,i);}
\r
891 rv = cacheInfoDAO.touch(trans, RoleDAO.TABLE,seg);
\r
893 if (all || UserRoleDAO.TABLE.equals(cname)) {
\r
894 int seg[] = series(NsDAO.CACHE_SEG);
\r
895 for(int i: seg) {cacheClear(trans, UserRoleDAO.TABLE,i);}
\r
896 rv = cacheInfoDAO.touch(trans, UserRoleDAO.TABLE,seg);
\r
898 if (all || CredDAO.TABLE.equals(cname)) {
\r
899 int seg[] = series(NsDAO.CACHE_SEG);
\r
900 for(int i: seg) {cacheClear(trans, CredDAO.TABLE,i);}
\r
901 rv = cacheInfoDAO.touch(trans, CredDAO.TABLE,seg);
\r
903 if (all || CertDAO.TABLE.equals(cname)) {
\r
904 int seg[] = series(NsDAO.CACHE_SEG);
\r
905 for(int i: seg) {cacheClear(trans, CertDAO.TABLE,i);}
\r
906 rv = cacheInfoDAO.touch(trans, CertDAO.TABLE,seg);
\r
910 rv = Result.err(Status.ERR_BadData, NO_CACHE_NAME, cname);
\r
915 public Result<Void> cacheClear(AuthzTrans trans, String cname,Integer segment) {
\r
917 if (NsDAO.TABLE.equals(cname)) {
\r
918 rv = nsDAO.invalidate(segment);
\r
919 } else if (PermDAO.TABLE.equals(cname)) {
\r
920 rv = permDAO.invalidate(segment);
\r
921 } else if (RoleDAO.TABLE.equals(cname)) {
\r
922 rv = roleDAO.invalidate(segment);
\r
923 } else if (UserRoleDAO.TABLE.equals(cname)) {
\r
924 rv = userRoleDAO.invalidate(segment);
\r
925 } else if (CredDAO.TABLE.equals(cname)) {
\r
926 rv = credDAO.invalidate(segment);
\r
927 } else if (CertDAO.TABLE.equals(cname)) {
\r
928 rv = certDAO.invalidate(segment);
\r
930 rv = Result.err(Status.ERR_BadData, NO_CACHE_NAME, cname);
\r
935 private int[] series(int max) {
\r
936 int[] series = new int[max];
\r
937 for (int i = 0; i < max; ++i)
\r
942 public boolean isDelegated(AuthzTrans trans, String user, String approver) {
\r
943 Result<List<DelegateDAO.Data>> userDelegatedFor = delegateDAO
\r
944 .readByDelegate(trans, user);
\r
945 for (DelegateDAO.Data curr : userDelegatedFor.value) {
\r
946 if (curr.user.equals(approver) && curr.delegate.equals(user)
\r
947 && curr.expires.after(new Date())) {
\r
954 public static boolean willSpecialLog(AuthzTrans trans, String user) {
\r
955 Boolean b = trans.get(specialLogSlot, null);
\r
957 if(specialLog==null) {
\r
960 b = specialLog.contains(user);
\r
961 trans.put(specialLogSlot, b);
\r
967 public static void logEncryptTrace(AuthzTrans trans, String data) {
\r
969 trans.put(transIDSlot, ti=nextTraceID());
\r
970 trans.trace().log("id="+Long.toHexString(ti)+",data=\""+trans.env().encryptor().encrypt(data)+'"');
\r
973 private synchronized static long nextTraceID() {
\r
977 public static synchronized boolean specialLogOn(AuthzTrans trans, String id) {
\r
978 if (specialLog == null) {
\r
979 specialLog = new HashSet<String>();
\r
981 boolean rc = specialLog.add(id);
\r
983 trans.trace().log("Trace on for",id);
\r
988 public static synchronized boolean specialLogOff(AuthzTrans trans, String id) {
\r
989 if(specialLog==null) {
\r
992 boolean rv = specialLog.remove(id);
\r
993 if (specialLog.isEmpty()) {
\r
997 trans.trace().log("Trace off for",id);
\r
1004 * Which Types can be moved
\r
1008 public boolean canMove(NsType nsType) {
\r
1023 public Result<String> isOwnerSponsor(AuthzTrans trans, String user, String ns, Identity mechID) {
\r
1026 Organization org = trans.org();
\r
1028 caller = org.getIdentity(trans, user);
\r
1029 if(caller==null || !caller.isFound()) {
\r
1030 return Result.err(Status.ERR_NotFound,"%s is not a registered %s entity",user,org.getName());
\r
1032 } catch (Exception e) {
\r
1033 return Result.err(e);
\r
1035 String sponsor = mechID.responsibleTo();
\r
1036 Result<List<UserRoleDAO.Data>> rur = userRoleDAO.read(trans, user,ns+DOT_OWNER);
\r
1037 boolean isOwner = false;
\r
1038 if(rur.isOKhasData()) {for(UserRoleDAO.Data urdd : rur.value){
\r
1039 if(urdd.expires.after(new Date())) {
\r
1044 return Result.err(Status.ERR_Policy,"%s is not a current owner of %s",user,ns);
\r
1047 if(!caller.id().equals(sponsor)) {
\r
1048 return Result.err(Status.ERR_Denied,"%s is not the sponsor of %s",user,mechID.id());
\r
1050 return Result.ok(sponsor);
\r
1053 public boolean isAdmin(AuthzTrans trans, String user, String ns) {
\r
1054 Date now = new Date();
\r
1055 Result<List<UserRoleDAO.Data>> rur = userRoleDAO.read(trans, user,ns+ADMIN);
\r
1056 if(rur.isOKhasData()) {for(UserRoleDAO.Data urdd : rur.value){
\r
1057 if(urdd.expires.after(now)) {
\r
1064 public boolean isOwner(AuthzTrans trans, String user, String ns) {
\r
1065 Result<List<UserRoleDAO.Data>> rur = userRoleDAO.read(trans, user,ns+DOT_OWNER);
\r
1066 Date now = new Date();
\r
1067 if(rur.isOKhasData()) {for(UserRoleDAO.Data urdd : rur.value){
\r
1068 if(urdd.expires.after(now)) {
\r
1075 public int countOwner(AuthzTrans trans, String user, String ns) {
\r
1076 Result<List<UserRoleDAO.Data>> rur = userRoleDAO.read(trans, user,ns+DOT_OWNER);
\r
1077 Date now = new Date();
\r
1079 if(rur.isOKhasData()) {for(UserRoleDAO.Data urdd : rur.value){
\r
1080 if(urdd.expires.after(now)) {
\r