AT&T 2.0.19 Code drop, stage 2
[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.CadiException;
34 import org.onap.aaf.cadi.Lur;
35 import org.onap.aaf.cadi.Permission;
36 import org.onap.aaf.cadi.User;
37 import org.onap.aaf.cadi.Access.Level;
38 import org.onap.aaf.cadi.CachedPrincipal.Resp;
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.misc.env.APIException;
46 import org.onap.aaf.misc.env.util.Split;
47
48 import aaf.v2_0.Perm;
49 import aaf.v2_0.Perms;
50
51 /**
52  * Use AAF Service as Permission Service.
53  * 
54  * This Lur goes after AAF Permissions, which are elements of Roles, not the Roles themselves.
55  * 
56  * If you want a simple Role Lur, use AAFRoleLur
57  * 
58  * @author Jonathan
59  *
60  */
61 public class AAFLurPerm extends AbsAAFLur<AAFPermission> {
62         /**
63          *  Need to be able to transmutate a Principal into either ATTUID or MechID, which are the only ones accepted at this
64          *  point by AAF.  There is no "domain", aka, no "@att.com" in "ab1234@att.com".  
65          *  
66          *  The only thing that matters here for AAF is that we don't waste calls with IDs that obviously aren't valid.
67          *  Thus, we validate that the ID portion follows the rules before we waste time accessing AAF remotely
68          * @throws APIException 
69          * @throws URISyntaxException 
70          * @throws DME2Exception 
71          */
72         // Package on purpose
73         AAFLurPerm(AAFCon<?> con) throws CadiException, APIException {
74                 super(con);
75                 attachOAuth2(con);
76         }
77
78         // Package on purpose
79         AAFLurPerm(AAFCon<?> con, AbsUserCache<AAFPermission> auc) throws APIException {
80                 super(con,auc);
81                 attachOAuth2(con);
82         }
83         
84         private void attachOAuth2(AAFCon<?> con) throws APIException {
85                 String oauth2_url;
86                 Class<?> tmcls = Config.loadClass(access,"org.osaaf.cadi.oauth.TokenMgr");
87                 if(tmcls!=null) {
88                         if((oauth2_url = con.access.getProperty(Config.CADI_OAUTH2_URL,null))!=null) {
89                                 try {
90                                         Constructor<?> tmconst = tmcls.getConstructor(AAFCon.class,String.class);
91                                         Object tokMangr = tmconst.newInstance(con,oauth2_url);
92                                         @SuppressWarnings("unchecked")
93                                         Class<Lur> oa2cls = (Class<Lur>)Config.loadClass(access,"org.osaaf.cadi.oauth.OAuth2Lur");
94                                         Constructor<Lur> oa2const = oa2cls.getConstructor(tmcls);
95                                         Lur oa2 = oa2const.newInstance(tokMangr);
96                                         setPreemptiveLur(oa2);
97                                 } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
98                                         throw new APIException(e);
99                                 }
100                         } else {
101                                 access.log(Level.INIT, "Both cadi-oauth jar and Property",Config.CADI_OAUTH2_URL,"is required to initialize OAuth2");
102                         }
103                 }
104         }
105
106         protected User<AAFPermission> loadUser(final Principal principal)  {
107                 final String name = principal.getName();
108 //              // Note: The rules for AAF is that it only stores permissions for ATTUID and MechIDs, which don't 
109 //              // have domains.  We are going to make the Transitive Class (see this.transmutative) to convert
110 //              final Principal tp = principal; //transmutate.mutate(principal);
111 //              if(tp==null) {
112 //                      return null; // if not a valid Transmutated credential, don't bother calling...
113 //              }
114 //              TODO Create a dynamic way to declare domains supported.
115                 final long start = System.nanoTime();
116                 final boolean[] success = new boolean[]{false};
117                 
118 //              new Exception("loadUser").printStackTrace();
119                 try {
120                         return aaf.best(new Retryable<User<AAFPermission>>() {
121                                 @Override
122                                 public User<AAFPermission> code(Rcli<?> client) throws CadiException, ConnectException, APIException {
123                                         Future<Perms> fp = client.read("/authz/perms/user/"+name,aaf.permsDF);
124                                         
125                                         // In the meantime, lookup User, create if necessary
126                                         User<AAFPermission> user = getUser(principal);
127                                         Principal p;
128                                         if(user!=null && user.principal == null) {
129                                                 p = new Principal() {// Create a holder for lookups
130                                                         private String n = name;
131                                                         public String getName() {
132                                                                 return n;
133                                                         }
134                                                 };
135                                         } else {
136                                                 p = principal;
137                                         }
138                                         
139                                         if(user==null) {
140                                                 addUser(user = new User<AAFPermission>(p,aaf.userExpires)); // no password
141                                         }
142                                         
143                                         // OK, done all we can, now get content
144                                         if(fp.get(aaf.timeout)) {
145                                                 success[0]=true;
146                                                 Map<String, Permission> newMap = user.newMap();
147                                                 boolean willLog = aaf.access.willLog(Level.DEBUG);
148                                                 for(Perm perm : fp.value.getPerm()) {
149                                                         user.add(newMap,new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction(),perm.getRoles()));
150                                                         if(willLog) {
151                                                                 aaf.access.log(Level.DEBUG, name,"has '",perm.getType(),'|',perm.getInstance(),'|',perm.getAction(),'\'');
152                                                         }
153                                                 }
154                                                 user.setMap(newMap);
155                                         } else {
156                                                 int code;
157                                                 switch(code=fp.code()) {
158                                                         case 401:
159                                                                 aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
160                                                                 break;
161                                                         case 404:
162                                                                 user.setNoPerms();
163                                                                 break;
164                                                         default:
165                                                                 aaf.access.log(Access.Level.ERROR, code, fp.body());
166                                                 }
167                                         }
168
169                                         return user;
170                                 }
171                         });
172                 } catch (Exception e) {
173                         aaf.access.log(e,"Calling","/authz/perms/user/"+name);
174                         success[0]=false;
175                         return null;
176                 } finally {
177                         float time = (System.nanoTime()-start)/1000000f;
178                         aaf.access.log(Level.INFO, success[0]?"Loaded":"Load Failure",name,"from AAF in",time,"ms");
179                 }
180         }
181
182         public Resp reload(User<AAFPermission> user) {
183                 final String name = user.name;
184                 long start = System.nanoTime();
185                 boolean success = false;
186                 try {
187                         Future<Perms> fp = aaf.client(Config.AAF_DEFAULT_VERSION).read(
188                                         "/authz/perms/user/"+name,
189                                         aaf.permsDF
190                                         );
191                         
192                         // OK, done all we can, now get content
193                         if(fp.get(aaf.timeout)) {
194                                 success = true;
195                                 Map<String,Permission> newMap = user.newMap(); 
196                                 boolean willLog = aaf.access.willLog(Level.DEBUG);
197                                 for(Perm perm : fp.value.getPerm()) {
198                                         user.add(newMap, new AAFPermission(perm.getType(),perm.getInstance(),perm.getAction(),perm.getRoles()));
199                                         if(willLog) {
200                                                 aaf.access.log(Level.DEBUG, name,"has",perm.getType(),perm.getInstance(),perm.getAction());
201                                         }
202                                 }
203                                 user.renewPerm();
204                                 return Resp.REVALIDATED;
205                         } else {
206                                 int code;
207                                 switch(code=fp.code()) {
208                                         case 401:
209                                                 aaf.access.log(Access.Level.ERROR, code, "Unauthorized to make AAF calls");
210                                                 break;
211                                         default:
212                                                 aaf.access.log(Access.Level.ERROR, code, fp.body());
213                                 }
214                                 return Resp.UNVALIDATED;
215                         }
216                 } catch (Exception e) {
217                         aaf.access.log(e,"Calling","/authz/perms/user/"+name);
218                         return Resp.INACCESSIBLE;
219                 } finally {
220                         float time = (System.nanoTime()-start)/1000000f;
221                         aaf.access.log(Level.AUDIT, success?"Reloaded":"Reload Failure",name,"from AAF in",time,"ms");
222                 }
223         }
224
225         @Override
226         protected boolean isCorrectPermType(Permission pond) {
227                 return pond instanceof AAFPermission;
228         }
229
230         /* (non-Javadoc)
231          * @see org.onap.aaf.cadi.Lur#createPerm(java.lang.String)
232          */
233         @Override
234         public Permission createPerm(String p) {
235                 String[] params = Split.split('|', p);
236                 if(params.length==3) {
237                         return new AAFPermission(params[0],params[1],params[2]);
238                 } else {
239                         return new LocalPermission(p);
240                 }
241         }
242         
243 }