Create and prepare non-deploy release 2.7.1
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / aaf / v2_0 / AAFLurPerm.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.cadi.aaf.v2_0;
23
24 import java.lang.reflect.Constructor;
25 import java.lang.reflect.InvocationTargetException;
26 import java.net.ConnectException;
27 import java.net.URISyntaxException;
28 import java.security.Principal;
29 import java.util.Map;
30
31 import org.onap.aaf.cadi.AbsUserCache;
32 import org.onap.aaf.cadi.Access;
33 import org.onap.aaf.cadi.Access.Level;
34 import org.onap.aaf.cadi.CachedPrincipal.Resp;
35 import org.onap.aaf.cadi.CadiException;
36 import org.onap.aaf.cadi.Lur;
37 import org.onap.aaf.cadi.Permission;
38 import org.onap.aaf.cadi.User;
39 import org.onap.aaf.cadi.aaf.AAFPermission;
40 import org.onap.aaf.cadi.client.Future;
41 import org.onap.aaf.cadi.client.Rcli;
42 import org.onap.aaf.cadi.client.Retryable;
43 import org.onap.aaf.cadi.config.Config;
44 import org.onap.aaf.cadi.lur.LocalPermission;
45 import org.onap.aaf.cadi.util.Holder;
46 import org.onap.aaf.cadi.util.Timing;
47 import org.onap.aaf.misc.env.APIException;
48 import org.onap.aaf.misc.env.util.Split;
49
50 import aaf.v2_0.Perm;
51 import aaf.v2_0.Perms;
52
53 /**
54  * Use AAF Service as Permission Service.
55  *
56  * This Lur goes after AAF Permissions, which are elements of Roles, not the Roles themselves.
57  *
58  * If you want a simple Role Lur, use AAFRoleLur
59  *
60  * @author Jonathan
61  *
62  */
63 public class AAFLurPerm extends AbsAAFLur<AAFPermission> {
64     private static final String ORG_ONAP_AAF_CADI_OAUTH_OAUTH_2_LUR = "org.onap.aaf.cadi.oauth.OAuth2Lur";
65
66     /**
67      *  Need to be able to transmutate a Principal into either Person or AppID, which are the only ones accepted at this
68      *  point by AAF.  There is no "domain", aka, no "@att.com" in "ab1234@att.com".
69      *
70      *  The only thing that matters here for AAF is that we don't waste calls with IDs that obviously aren't valid.
71      *  Thus, we validate that the ID portion follows the rules before we waste time accessing AAF remotely
72      * @throws APIException
73      * @throws URISyntaxException
74      * @throws DME2Exception
75      */
76     // Package on purpose
77     AAFLurPerm(AAFCon<?> con) throws CadiException, APIException {
78         super(con);
79         attachOAuth2(con);
80     }
81
82     // Package on purpose
83     AAFLurPerm(AAFCon<?> con, AbsUserCache<AAFPermission> auc) throws APIException {
84         super(con,auc);
85         attachOAuth2(con);
86     }
87
88     private void attachOAuth2(AAFCon<?> con) throws APIException {
89         String oauth2_url;
90         Class<?> tmcls = Config.loadClass(access,"org.onap.aaf.cadi.oauth.TokenMgr");
91         if (tmcls!=null) {
92             if ((oauth2_url = con.access.getProperty(Config.CADI_OAUTH2_URL,null))!=null) {
93                 try {
94                     Constructor<?> tmconst = tmcls.getConstructor(AAFCon.class,String.class);
95                     Object tokMangr = tmconst.newInstance(con,oauth2_url);
96                     @SuppressWarnings("unchecked")
97                     Class<Lur> oa2cls = (Class<Lur>)Config.loadClass(access, ORG_ONAP_AAF_CADI_OAUTH_OAUTH_2_LUR);
98                     Constructor<Lur> oa2const = oa2cls.getConstructor(tmcls);
99                     Lur oa2 = oa2const.newInstance(tokMangr);
100                     setPreemptiveLur(oa2);
101                 } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
102                     throw new APIException(e);
103                 }
104             } else {
105                 access.log(Level.INIT, "Both cadi-oauth jar and Property",Config.CADI_OAUTH2_URL,"is required to initialize OAuth2");
106             }
107         }
108     }
109
110     protected User<AAFPermission> loadUser(final Principal principal)  {
111         final String name = principal.getName();
112         final long start = System.nanoTime();
113         final Holder<Float> remote = new Holder<Float>(0f);
114
115         final boolean[] success = new boolean[]{false};
116
117         try {
118             return aaf.best(new Retryable<User<AAFPermission>>() {
119                 @Override
120                 public User<AAFPermission> code(Rcli<?> client) throws CadiException, ConnectException, APIException {
121                     final long remoteStart = System.nanoTime();
122                     StringBuilder sb = new StringBuilder("/authz/perms/user/");
123                     sb.append(name);
124                     if(details) {
125                         sb.append("?force");
126                     }
127                     Future<Perms> fp = client.read(sb.toString(),aaf.permsDF);
128
129                     // In the meantime, lookup User, create if necessary
130                     User<AAFPermission> user = getUser(principal);
131                     Principal p;
132                     if (user!=null && user.principal == null) {
133                         p = new Principal() {// Create a holder for lookups
134                             private String n = name;
135                             public String getName() {
136                                 return n;
137                             }
138                         };
139                     } else {
140                         p = principal;
141                     }
142
143                     if (user==null) {
144                         addUser(user = new User<AAFPermission>(p,aaf.userExpires)); // no password
145                     }
146
147                     // OK, done all we can, now get content
148                     boolean ok = fp.get(aaf.timeout);
149                     remote.set(Timing.millis(remoteStart));
150                     if (ok) {
151                         success[0]=true;
152                         Map<String, Permission> newMap = user.newMap();
153                         boolean willLog = aaf.access.willLog(Level.DEBUG);
154                         for (Perm perm : fp.value.getPerm()) {
155                             user.add(newMap,new AAFPermission(perm.getNs(),perm.getType(),perm.getInstance(),perm.getAction(),perm.getRoles()));
156                             if (willLog) {
157                                 aaf.access.log(Level.DEBUG, name,"has '",perm.getType(),'|',perm.getInstance(),'|',perm.getAction(),'\'');
158                             }
159                         }
160                         user.setMap(newMap);
161                     } else {
162                         int code;
163                         switch(code=fp.code()) {
164                             case 401:
165                                 aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
166                                 break;
167                             case 404:
168                                 user.setNoPerms();
169                                 break;
170                             default:
171                                 aaf.access.log(Access.Level.ERROR, code, fp.body());
172                         }
173                     }
174
175                     return user;
176                 }
177             });
178         } catch (Exception e) {
179             aaf.access.log(e,"Calling","/authz/perms/user/"+name);
180             success[0]=false;
181             return null;
182         } finally {
183             aaf.access.printf(Level.INFO, "AAFLurPerm: %s %s perms from AAF in %f ms, remote=%f",
184                     (success[0]?"Loaded":"Load Failure"),name,Timing.millis(start),remote.get());
185         }
186     }
187
188     public Resp reload(final User<AAFPermission> user) {
189         final String name = user.name;
190         long start = System.nanoTime();
191         final Holder<Float> remote = new Holder<Float>(0f);
192         final Holder<Boolean> success = new Holder<Boolean>(false);
193         try {
194             Resp rv = aaf.best(new Retryable<Resp>() {
195                 @Override
196                 public Resp code(Rcli<?> client) throws CadiException, ConnectException, APIException {
197                     final long remoteStart = System.nanoTime();
198                     Future<Perms> fp = aaf.client().read(
199                             "/authz/perms/user/"+name,
200                             aaf.permsDF
201                             );
202
203                     // OK, done all we can, now get content
204                     boolean ok = fp.get(aaf.timeout);
205                     remote.set(Timing.millis(remoteStart));
206                     if (ok) {
207                         success.set(true);
208                         Map<String,Permission> newMap = user.newMap();
209                         boolean willLog = aaf.access.willLog(Level.DEBUG);
210                         for (Perm perm : fp.value.getPerm()) {
211                             user.add(newMap, new AAFPermission(perm.getNs(),perm.getType(),perm.getInstance(),perm.getAction(),perm.getRoles()));
212                             if (willLog) {
213                                 aaf.access.log(Level.DEBUG, name,"has",perm.getType(),perm.getInstance(),perm.getAction());
214                             }
215                         }
216                         user.renewPerm();
217                         return Resp.REVALIDATED;
218                     } else {
219                         int code;
220                         switch(code=fp.code()) {
221                             case 401:
222                                 aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
223                                 break;
224                             default:
225                                 aaf.access.log(Access.Level.ERROR, code, fp.body());
226                         }
227                         return Resp.UNVALIDATED;
228                     }
229                 }
230             });
231             return rv;
232         } catch (Exception e) {
233             aaf.access.log(e,"Calling","/authz/perms/user/"+name);
234             return Resp.INACCESSIBLE;
235         } finally {
236             aaf.access.printf(Level.INFO, "AAFLurPerm: %s %s perms from AAF in %f ms (remote=%f)",
237                     (success.get()?"Reloaded":"Reload Failure"),name,Timing.millis(start),remote.get());
238         }
239     }
240
241     @Override
242     protected boolean isCorrectPermType(Permission pond) {
243         return pond instanceof AAFPermission;
244     }
245
246     /* (non-Javadoc)
247      * @see org.onap.aaf.cadi.Lur#createPerm(java.lang.String)
248      */
249     @Override
250     public Permission createPerm(String p) {
251         String[] params = Split.split('|', p);
252         switch(params.length) {
253             case 3:
254                 return new AAFPermission(null,params[0],params[1],params[2]);
255             case 4:
256                 return new AAFPermission(params[0],params[1],params[2],params[3]);
257             default:
258                 return new LocalPermission(p);
259         }
260     }
261
262 }