AT&T 2.0.19 Code drop, stage 2
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / oauth / TokenMgr.java
diff --git a/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenMgr.java b/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenMgr.java
new file mode 100644 (file)
index 0000000..d8fd88f
--- /dev/null
@@ -0,0 +1,193 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.cadi.oauth;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.LocatorException;
+import org.onap.aaf.cadi.PropAccess;
+import org.onap.aaf.cadi.Access.Level;
+import org.onap.aaf.cadi.client.Result;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.persist.Persist;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.rosetta.env.RosettaDF;
+import org.onap.aaf.misc.rosetta.env.RosettaEnv;
+
+import aaf.v2_0.Perms;
+import aafoauth.v2_0.Introspect;
+
+public class TokenMgr extends Persist<Introspect, TokenPerm> {
+       protected static Map<String,TokenPerm> tpmap = new ConcurrentHashMap<String, TokenPerm>();
+       protected static Map<String,TokenMgr> tmmap = new HashMap<String, TokenMgr>(); // synchronized in getInstance
+       protected static Map<String,String> currentToken = new HashMap<String,String>(); // synchronized in getTP
+       public static RosettaDF<Perms> permsDF;
+       public static RosettaDF<Introspect> introspectDF;
+
+       private final TokenPermLoader tpLoader;
+       
+       private TokenMgr(PropAccess access, String tokenURL, String introspectURL) throws APIException, CadiException {
+               super(access,new RosettaEnv(access.getProperties()),Introspect.class,"introspect");
+               synchronized(access) {
+                       if(permsDF==null) {
+                               permsDF = env.newDataFactory(Perms.class);
+                               introspectDF = env.newDataFactory(Introspect.class);
+                       }
+               }
+               if("dbToken".equals(tokenURL) && "dbIntrospect".equals(introspectURL)) {
+                       tpLoader = new TokenPermLoader() { // null Loader
+                               @Override
+                               public Result<TokenPerm> load(String accessToken, byte[] cred)
+                                               throws APIException, CadiException, LocatorException {
+                                       return Result.err(404, "DBLoader");
+                               }
+                       };
+               } else {
+                       RemoteTokenPermLoader rtpl = new RemoteTokenPermLoader(tokenURL, introspectURL); // default is remote
+                       String i = access.getProperty(Config.AAF_APPID,null);
+                       String p = access.getProperty(Config.AAF_APPPASS, null);
+                       if(i==null || p==null) {
+                               throw new CadiException(Config.AAF_APPID + " and " + Config.AAF_APPPASS + " must be set to initialize TokenMgr");
+                       }
+                       rtpl.introCL.client_creds(i,p);
+                       tpLoader = rtpl;
+               }
+       }
+
+       private TokenMgr(PropAccess access, TokenPermLoader tpl) throws APIException, CadiException {
+               super(access,new RosettaEnv(access.getProperties()),Introspect.class,"incoming");
+               synchronized(access) {
+                       if(permsDF==null) {
+                               permsDF = env.newDataFactory(Perms.class);
+                               introspectDF = env.newDataFactory(Introspect.class);
+                       }
+               }
+               tpLoader = tpl;
+       }
+
+       public static synchronized TokenMgr getInstance(final PropAccess access, final String tokenURL, final String introspectURL) throws APIException, CadiException {
+               String key;
+               TokenMgr tm = tmmap.get(key=tokenURL+'/'+introspectURL);
+               if(tm==null) {
+                       tmmap.put(key, tm=new TokenMgr(access,tokenURL,introspectURL));
+               }
+               return tm;
+       }
+       
+       public Result<OAuth2Principal> toPrincipal(final String accessToken, final byte[] hash) throws APIException, CadiException, LocatorException {
+               Result<TokenPerm> tp = get(accessToken, hash, new Loader<TokenPerm>() {
+                       @Override
+                       public Result<TokenPerm> load(String key) throws APIException, CadiException, LocatorException {
+                               try {
+                                       return tpLoader.load(accessToken,hash);
+                               } catch (APIException | LocatorException e) {
+                                       throw new CadiException(e);
+                               }
+                       }
+               });
+               if(tp.isOK()) {
+                       return Result.ok(200, new OAuth2Principal(tp.value,hash));
+               } else {
+                       return Result.err(tp);
+               }
+       }
+       
+       public Result<TokenPerm> get(final String accessToken, final byte[] hash) throws APIException, CadiException, LocatorException {
+               return get(accessToken,hash,new Loader<TokenPerm>() {
+                       @Override
+                       public Result<TokenPerm> load(String key) throws APIException, CadiException, LocatorException {
+                               return tpLoader.load(key,hash);
+                       }
+                       
+               });
+//             return tpLoader.load(accessToken,hash);
+       }
+
+       public interface TokenPermLoader{
+               public Result<TokenPerm> load(final String accessToken, final byte[] cred) throws APIException, CadiException, LocatorException;
+       }
+       
+       private class RemoteTokenPermLoader implements TokenPermLoader {
+               private TokenClientFactory tcf;
+               private TokenClient tokenCL, introCL;
+
+               public RemoteTokenPermLoader(final String tokenURL, final String introspectURL) throws APIException, CadiException {
+                       try {
+                               tcf = TokenClientFactory.instance(access);
+                               int timeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF));
+                               tokenCL = tcf.newClient(tokenURL, 
+                                                                               timeout);
+                               if(introspectURL.equals(tokenURL)) {
+                                       introCL = tokenCL;
+                               } else {
+                                       introCL = tcf.newClient(introspectURL, 
+                                                       timeout);
+                               }
+
+                       } catch (GeneralSecurityException | IOException | NumberFormatException | LocatorException e) {
+                               throw new CadiException(e);
+                       }
+               }
+                
+               public Result<TokenPerm> load(final String accessToken, final byte[] cred) throws APIException, CadiException, LocatorException {
+                       long start = System.currentTimeMillis();
+                       try {
+                               Result<Introspect> ri = introCL.introspect(accessToken);
+                               if(ri.isOK()) {
+                                       return Result.ok(ri.code, new TokenPerm(TokenMgr.this,permsDF,ri.value,cred,getPath(accessToken)));
+                               } else {
+                                       return Result.err(ri);
+                               }
+                       } finally {
+                               access.printf(Level.INFO, "Token loaded in %d ms",System.currentTimeMillis()-start);
+                       }
+               }
+       }
+
+       public void clear(Principal p, StringBuilder report) {
+               TokenPerm tp = tpmap.remove(p.getName());
+               if(tp==null) {
+                       report.append("Nothing to clear");
+               } else {
+                       report.append("Cleared ");
+                       report.append(p.getName());
+               }
+       }
+
+       @Override
+       protected TokenPerm newCacheable(Introspect i, long expires, byte[] hash, Path path) throws APIException {
+               // Note: Introspect drives the Expiration... ignoring expires.
+               return new TokenPerm(this,permsDF,i,hash,path);
+       }
+
+       public TokenPerm putIntrospect(Introspect intro, byte[] cred) throws APIException {
+               return newCacheable(intro, intro.getExp(), cred, getPath(intro.getAccessToken()));
+       }
+
+}