Merge "Change: Spelling Mistake Issue-ID: AAF-456"
[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.Holder;
42 import org.onap.aaf.cadi.client.Rcli;
43 import org.onap.aaf.cadi.client.Retryable;
44 import org.onap.aaf.cadi.config.Config;
45 import org.onap.aaf.cadi.lur.LocalPermission;
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_OSAAF_CADI_OAUTH_O_AUTH2_LUR = "org.osaaf.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.osaaf.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_OSAAF_CADI_OAUTH_O_AUTH2_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                                         Future<Perms> fp = client.read("/authz/perms/user/"+name,aaf.permsDF);
123                                         
124                                         // In the meantime, lookup User, create if necessary
125                                         User<AAFPermission> user = getUser(principal);
126                                         Principal p;
127                                         if(user!=null && user.principal == null) {
128                                                 p = new Principal() {// Create a holder for lookups
129                                                         private String n = name;
130                                                         public String getName() {
131                                                                 return n;
132                                                         }
133                                                 };
134                                         } else {
135                                                 p = principal;
136                                         }
137                                         
138                                         if(user==null) {
139                                                 addUser(user = new User<AAFPermission>(p,aaf.userExpires)); // no password
140                                         }
141                                         
142                                         // OK, done all we can, now get content
143                                         boolean ok = fp.get(aaf.timeout);
144                                         remote.set(Timing.millis(remoteStart));
145                                         if(ok) {
146                                                 success[0]=true;
147                                                 Map<String, Permission> newMap = user.newMap();
148                                                 boolean willLog = aaf.access.willLog(Level.DEBUG);
149                                                 for(Perm perm : fp.value.getPerm()) {
150                                                         user.add(newMap,new AAFPermission(perm.getNs(),perm.getType(),perm.getInstance(),perm.getAction(),perm.getRoles()));
151                                                         if(willLog) {
152                                                                 aaf.access.log(Level.DEBUG, name,"has '",perm.getType(),'|',perm.getInstance(),'|',perm.getAction(),'\'');
153                                                         }
154                                                 }
155                                                 user.setMap(newMap);
156                                         } else {
157                                                 int code;
158                                                 switch(code=fp.code()) {
159                                                         case 401:
160                                                                 aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
161                                                                 break;
162                                                         case 404:
163                                                                 user.setNoPerms();
164                                                                 break;
165                                                         default:
166                                                                 aaf.access.log(Access.Level.ERROR, code, fp.body());
167                                                 }
168                                         }
169
170                                         return user;
171                                 }
172                         });
173                 } catch (Exception e) {
174                         aaf.access.log(e,"Calling","/authz/perms/user/"+name);
175                         success[0]=false;
176                         return null;
177                 } finally {
178                         aaf.access.printf(Level.INFO, "AAFLurPerm: %s %s perms from AAF in %f ms, remote=%f",
179                                         (success[0]?"Loaded":"Load Failure"),name,Timing.millis(start),remote.get());
180                 }
181         }
182
183         public Resp reload(final User<AAFPermission> user) {
184                 final String name = user.name;
185                 long start = System.nanoTime();
186                 final Holder<Float> remote = new Holder<Float>(0f);
187                 final Holder<Boolean> success = new Holder<Boolean>(false);
188                 try {
189                         Resp rv = aaf.best(new Retryable<Resp>() {
190                                 @Override
191                                 public Resp code(Rcli<?> client) throws CadiException, ConnectException, APIException {
192                                         final long remoteStart = System.nanoTime();
193                                         Future<Perms> fp = aaf.client(Config.AAF_DEFAULT_VERSION).read(
194                                                         "/authz/perms/user/"+name,
195                                                         aaf.permsDF
196                                                         );
197                                         
198                                         // OK, done all we can, now get content
199                                         boolean ok = fp.get(aaf.timeout);
200                                         remote.set(Timing.millis(remoteStart));
201                                         if(ok) {
202                                                 success.set(true);
203                                                 Map<String,Permission> newMap = user.newMap(); 
204                                                 boolean willLog = aaf.access.willLog(Level.DEBUG);
205                                                 for(Perm perm : fp.value.getPerm()) {
206                                                         user.add(newMap, new AAFPermission(perm.getNs(),perm.getType(),perm.getInstance(),perm.getAction(),perm.getRoles()));
207                                                         if(willLog) {
208                                                                 aaf.access.log(Level.DEBUG, name,"has",perm.getType(),perm.getInstance(),perm.getAction());
209                                                         }
210                                                 }
211                                                 user.renewPerm();
212                                                 return Resp.REVALIDATED;
213                                         } else {
214                                                 int code;
215                                                 switch(code=fp.code()) {
216                                                         case 401:
217                                                                 aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
218                                                                 break;
219                                                         default:
220                                                                 aaf.access.log(Access.Level.ERROR, code, fp.body());
221                                                 }
222                                                 return Resp.UNVALIDATED;
223                                         }
224                                 }
225                         });
226                         return rv;
227                 } catch (Exception e) {
228                         aaf.access.log(e,"Calling","/authz/perms/user/"+name);
229                         return Resp.INACCESSIBLE;
230                 } finally {
231                         aaf.access.printf(Level.INFO, "AAFLurPerm: %s %s perms from AAF in %f ms (remote=%f)",
232                                         (success.get()?"Reloaded":"Reload Failure"),name,Timing.millis(start),remote.get());
233                 }
234         }
235
236         @Override
237         protected boolean isCorrectPermType(Permission pond) {
238                 return pond instanceof AAFPermission;
239         }
240
241         /* (non-Javadoc)
242          * @see org.onap.aaf.cadi.Lur#createPerm(java.lang.String)
243          */
244         @Override
245         public Permission createPerm(String p) {
246                 String[] params = Split.split('|', p);
247                 switch(params.length) {
248                         case 3:
249                                 return new AAFPermission(null,params[0],params[1],params[2]);
250                         case 4:
251                                 return new AAFPermission(params[0],params[1],params[2],params[3]);
252                         default:
253                                 return new LocalPermission(p);
254                 }
255         }
256         
257 }