5a4e7f0ceb74f511e211dbc6e47dfa7b7f003aec
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / oauth / TokenMgr.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.oauth;
23
24 import java.io.IOException;
25 import java.nio.file.Path;
26 import java.security.GeneralSecurityException;
27 import java.security.Principal;
28 import java.util.HashMap;
29 import java.util.Map;
30 import java.util.concurrent.ConcurrentHashMap;
31
32 import org.onap.aaf.cadi.CadiException;
33 import org.onap.aaf.cadi.LocatorException;
34 import org.onap.aaf.cadi.PropAccess;
35 import org.onap.aaf.cadi.Access.Level;
36 import org.onap.aaf.cadi.client.Result;
37 import org.onap.aaf.cadi.config.Config;
38 import org.onap.aaf.cadi.persist.Persist;
39 import org.onap.aaf.misc.env.APIException;
40 import org.onap.aaf.misc.rosetta.env.RosettaDF;
41 import org.onap.aaf.misc.rosetta.env.RosettaEnv;
42
43 import aaf.v2_0.Perms;
44 import aafoauth.v2_0.Introspect;
45
46 public class TokenMgr extends Persist<Introspect, TokenPerm> {
47     protected static Map<String,TokenPerm> tpmap = new ConcurrentHashMap<>();
48     protected static Map<String,TokenMgr> tmmap = new HashMap<>(); // synchronized in getInstance
49     protected static Map<String,String> currentToken = new HashMap<>(); // synchronized in getTP
50     public static RosettaDF<Perms> permsDF;
51     public static RosettaDF<Introspect> introspectDF;
52
53     private final TokenPermLoader tpLoader;
54     
55     private TokenMgr(PropAccess access, String tokenURL, String introspectURL) throws APIException, CadiException {
56         super(access,new RosettaEnv(access.getProperties()),Introspect.class,"introspect");
57         synchronized(access) {
58             if (permsDF==null) {
59                 permsDF = env.newDataFactory(Perms.class);
60                 introspectDF = env.newDataFactory(Introspect.class);
61             }
62         }
63         if ("dbToken".equals(tokenURL) && "dbIntrospect".equals(introspectURL)) {
64             tpLoader = new TokenPermLoader() { // null Loader
65                 @Override
66                 public Result<TokenPerm> load(String accessToken, byte[] cred)
67                         throws APIException, CadiException, LocatorException {
68                     return Result.err(404, "DBLoader");
69                 }
70             };
71         } else {
72             RemoteTokenPermLoader rtpl = new RemoteTokenPermLoader(tokenURL, introspectURL); // default is remote
73             String i = access.getProperty(Config.AAF_APPID,null);
74             String p = access.getProperty(Config.AAF_APPPASS, null);
75             if (i==null || p==null) {
76                 throw new CadiException(Config.AAF_APPID + " and " + Config.AAF_APPPASS + " must be set to initialize TokenMgr");
77             }
78             rtpl.introCL.client_creds(i,p);
79             tpLoader = rtpl;
80         }
81     }
82
83     private TokenMgr(PropAccess access, TokenPermLoader tpl) throws APIException, CadiException {
84         super(access,new RosettaEnv(access.getProperties()),Introspect.class,"incoming");
85         synchronized(access) {
86             if (permsDF==null) {
87                 permsDF = env.newDataFactory(Perms.class);
88                 introspectDF = env.newDataFactory(Introspect.class);
89             }
90         }
91         tpLoader = tpl;
92     }
93
94     public static synchronized TokenMgr getInstance(final PropAccess access, final String tokenURL, final String introspectURL) throws APIException, CadiException {
95         String key;
96         TokenMgr tm = tmmap.get(key=tokenURL+'/'+introspectURL);
97         if (tm==null) {
98             tmmap.put(key, tm=new TokenMgr(access,tokenURL,introspectURL));
99         }
100         return tm;
101     }
102     
103     public Result<OAuth2Principal> toPrincipal(final String accessToken, final byte[] hash) throws APIException, CadiException, LocatorException {
104         Result<TokenPerm> tp = get(accessToken, hash, new Loader<TokenPerm>() {
105             @Override
106             public Result<TokenPerm> load(String key) throws APIException, CadiException, LocatorException {
107                 try {
108                     return tpLoader.load(accessToken,hash);
109                 } catch (APIException | LocatorException e) {
110                     throw new CadiException(e);
111                 }
112             }
113         });
114         if (tp.isOK()) {
115             return Result.ok(200, new OAuth2Principal(tp.value,hash));
116         } else {
117             return Result.err(tp);
118         }
119     }
120     
121     public Result<TokenPerm> get(final String accessToken, final byte[] hash) throws APIException, CadiException, LocatorException {
122         return get(accessToken,hash,new Loader<TokenPerm>() {
123             @Override
124             public Result<TokenPerm> load(String key) throws APIException, CadiException, LocatorException {
125                 return tpLoader.load(key,hash);
126             }
127             
128         });
129 //        return tpLoader.load(accessToken,hash);
130     }
131
132     public interface TokenPermLoader{
133         public Result<TokenPerm> load(final String accessToken, final byte[] cred) throws APIException, CadiException, LocatorException;
134     }
135     
136     private class RemoteTokenPermLoader implements TokenPermLoader {
137         private TokenClientFactory tcf;
138         private TokenClient tokenCL, introCL;
139
140         public RemoteTokenPermLoader(final String tokenURL, final String introspectURL) throws APIException, CadiException {
141             try {
142                 tcf = TokenClientFactory.instance(access);
143                 int timeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF));
144                 tokenCL = tcf.newClient(tokenURL, 
145                                         timeout);
146                 if (introspectURL.equals(tokenURL)) {
147                     introCL = tokenCL;
148                 } else {
149                     introCL = tcf.newClient(introspectURL, 
150                             timeout);
151                 }
152
153             } catch (GeneralSecurityException | IOException | NumberFormatException | LocatorException e) {
154                 throw new CadiException(e);
155             }
156         }
157          
158         public Result<TokenPerm> load(final String accessToken, final byte[] cred) throws APIException, CadiException, LocatorException {
159             long start = System.currentTimeMillis();
160             try {
161                 Result<Introspect> ri = introCL.introspect(accessToken);
162                 if (ri.isOK()) {
163                     return Result.ok(ri.code, new TokenPerm(TokenMgr.this,permsDF,ri.value,cred,getPath(accessToken)));
164                 } else {
165                     return Result.err(ri);
166                 }
167             } finally {
168                 access.printf(Level.INFO, "Token loaded in %d ms",System.currentTimeMillis()-start);
169             }
170         }
171     }
172
173     public void clear(Principal p, StringBuilder report) {
174         TokenPerm tp = tpmap.remove(p.getName());
175         if (tp==null) {
176             report.append("Nothing to clear");
177         } else {
178             report.append("Cleared ");
179             report.append(p.getName());
180         }
181     }
182
183     @Override
184     protected TokenPerm newCacheable(Introspect i, long expires, byte[] hash, Path path) throws APIException {
185         // Note: Introspect drives the Expiration... ignoring expires.
186         return new TokenPerm(this,permsDF,i,hash,path);
187     }
188
189     public TokenPerm putIntrospect(Introspect intro, byte[] cred) throws APIException {
190         return newCacheable(intro, intro.getExp(), cred, getPath(intro.getAccessToken()));
191     }
192
193 }