summaryrefslogtreecommitdiffstats
path: root/auth/auth-oauth/src/main
diff options
context:
space:
mode:
authorInstrumental <jcgmisc@stl.gathman.org>2018-03-26 13:51:48 -0700
committerInstrumental <jcgmisc@stl.gathman.org>2018-03-26 13:52:07 -0700
commit71037c39a37d3549dcfe31926832a657744fbe05 (patch)
tree78911b2b5e86e4e44228f7a27b3a8cd954b7f3e2 /auth/auth-oauth/src/main
parenta20accc73189d8e5454cd26049c0e6fae75da16f (diff)
AT&T 2.0.19 Code drop, stage 3
Issue-ID: AAF-197 Change-Id: I8b02cb073ccba318ccaf6ea0276446bdce88fb82 Signed-off-by: Instrumental <jcgmisc@stl.gathman.org>
Diffstat (limited to 'auth/auth-oauth/src/main')
-rw-r--r--auth/auth-oauth/src/main/config/.gitignore1
-rw-r--r--auth/auth-oauth/src/main/config/oauth.props26
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/AAF_OAuth.java196
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/DirectOAuthTAF.java224
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OACode.java45
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2Filter.java64
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2FormHttpTafResp.java65
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/api/API_Token.java82
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospect.java29
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospectImpl.java57
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectOAFacadeImpl.java28
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade.java67
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade1_0.java47
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeFactory.java47
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeImpl.java333
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper.java47
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper1_0.java225
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect.java29
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect1_0.java74
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoader.java34
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoaderFactory.java119
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OAuthService.java301
-rw-r--r--auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OCreds.java33
23 files changed, 2173 insertions, 0 deletions
diff --git a/auth/auth-oauth/src/main/config/.gitignore b/auth/auth-oauth/src/main/config/.gitignore
new file mode 100644
index 00000000..e53ef90a
--- /dev/null
+++ b/auth/auth-oauth/src/main/config/.gitignore
@@ -0,0 +1 @@
+/log4j.properties
diff --git a/auth/auth-oauth/src/main/config/oauth.props b/auth/auth-oauth/src/main/config/oauth.props
new file mode 100644
index 00000000..cdd382d1
--- /dev/null
+++ b/auth/auth-oauth/src/main/config/oauth.props
@@ -0,0 +1,26 @@
+##
+## AAF OAUTH2 API (authz-oauth) Properties
+##
+
+# Standard AFT for this box
+hostname=_HOSTNAME_
+
+## DISCOVERY (DME2) Parameters on the Command Line
+AFT_LATITUDE=_AFT_LATITUDE_
+AFT_LONGITUDE=_AFT_LONGITUDE_
+AFT_ENVIRONMENT=_AFT_ENVIRONMENT_
+DEPLOYED_VERSION=_ARTIFACT_VERSION_
+
+## Pull in common/security properties
+
+cadi_prop_files=_COMMON_DIR_/com.att.aaf.common.props:_COMMON_DIR_/com.att.aaf.props
+
+##DME2 related parameters
+
+DMEServiceName=service=com.att.authz.oauth/version=_MAJOR_VER_._MINOR_VER_._PATCH_VER_/envContext=_ENV_CONTEXT_/routeOffer=_ROUTE_OFFER_
+AFT_DME2_PORT_RANGE=_AUTHZ_OAUTH_PORT_RANGE_
+
+
+
+
+
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/AAF_OAuth.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/AAF_OAuth.java
new file mode 100644
index 00000000..1dac22fc
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/AAF_OAuth.java
@@ -0,0 +1,196 @@
+/**
+ * ============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.auth.oauth;
+
+import java.util.Map;
+
+import javax.servlet.Filter;
+
+import org.onap.aaf.auth.cache.Cache;
+import org.onap.aaf.auth.cache.Cache.Dated;
+import org.onap.aaf.auth.dao.CassAccess;
+import org.onap.aaf.auth.dao.hl.Question;
+import org.onap.aaf.auth.direct.DirectLocatorCreator;
+import org.onap.aaf.auth.direct.DirectRegistrar;
+import org.onap.aaf.auth.env.AuthzEnv;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.env.AuthzTransFilter;
+import org.onap.aaf.auth.oauth.api.API_Token;
+import org.onap.aaf.auth.oauth.facade.OAFacade;
+import org.onap.aaf.auth.oauth.facade.OAFacade1_0;
+import org.onap.aaf.auth.oauth.facade.OAFacadeFactory;
+import org.onap.aaf.auth.oauth.mapper.Mapper.API;
+import org.onap.aaf.auth.oauth.service.OAuthService;
+import org.onap.aaf.auth.rserv.HttpCode;
+import org.onap.aaf.auth.rserv.HttpMethods;
+import org.onap.aaf.auth.server.AbsService;
+import org.onap.aaf.auth.server.JettyServiceStarter;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.LocatorException;
+import org.onap.aaf.cadi.PropAccess;
+import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
+import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
+import org.onap.aaf.cadi.aaf.v2_0.AAFTrustChecker;
+import org.onap.aaf.cadi.aaf.v2_0.AbsAAFLocator;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.oauth.TokenMgr;
+import org.onap.aaf.cadi.oauth.TokenMgr.TokenPermLoader;
+import org.onap.aaf.cadi.register.Registrant;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Env;
+import org.onap.aaf.misc.env.Data.TYPE;
+
+import com.datastax.driver.core.Cluster;
+
+import aafoauth.v2_0.Introspect;
+
+public class AAF_OAuth extends AbsService<AuthzEnv,AuthzTrans> {
+ private static final String DOT_OAUTH = ".oauth";
+ public Map<String, Dated> cacheUser;
+ public AAFAuthn<?> aafAuthn;
+ public AAFLurPerm aafLurPerm;
+ private final OAuthService service;
+ private OAFacade1_0 facade1_0;
+ private final Question question;
+ private TokenPermLoader tpLoader;
+ private final Cluster cluster;
+
+ /**
+ * Construct AuthzAPI with all the Context Supporting Routes that Authz needs
+ *
+ * @param env
+ * @param si
+ * @param dm
+ * @param decryptor
+ * @throws APIException
+ */
+ public AAF_OAuth(final AuthzEnv env) throws Exception {
+ super(env.access(),env);
+
+ String aaf_env = env.getProperty(Config.AAF_ENV);
+ if(aaf_env==null) {
+ throw new APIException("aaf_env needs to be set");
+ }
+
+ // Initialize Facade for all uses
+ AuthzTrans trans = env.newTrans();
+ cluster = org.onap.aaf.auth.dao.CassAccess.cluster(env,null);
+
+ aafLurPerm = aafCon().newLur();
+ // Note: If you need both Authn and Authz construct the following:
+ aafAuthn = aafCon().newAuthn(aafLurPerm);
+
+ // Start Background Processing
+ // Question question =
+ question = new Question(trans, cluster, CassAccess.KEYSPACE, true);
+
+ // Have AAFLocator object Create DirectLocators for Location needs
+ AbsAAFLocator.setCreator(new DirectLocatorCreator(env, question.locateDAO));
+
+
+ service = new OAuthService(env.access(),trans,question);
+ facade1_0 = OAFacadeFactory.v1_0(this, trans, service, TYPE.JSON);
+ StringBuilder sb = new StringBuilder();
+ trans.auditTrail(2, sb);
+ trans.init().log(sb);
+
+ API_Token.init(this, facade1_0);
+ }
+
+ /**
+ * Setup XML and JSON implementations for each supported Version type
+ *
+ * We do this by taking the Code passed in and creating clones of these with the appropriate Facades and properties
+ * to do Versions and Content switches
+ *
+ */
+ public void route(HttpMethods meth, String path, API api, HttpCode<AuthzTrans, OAFacade<Introspect>> code) throws Exception {
+ String version = "1.0";
+ // Get Correct API Class from Mapper
+ Class<?> respCls = facade1_0.mapper().getClass(api);
+ if(respCls==null) throw new Exception("Unknown class associated with " + api.getClass().getName() + ' ' + api.name());
+ // setup Application API HTML ContentTypes for JSON and Route
+ String application = applicationJSON(respCls, version);
+ if(meth.equals(HttpMethods.POST)) {
+ route(env,meth,path,code,application,"application/json;version="+version,"application/x-www-form-urlencoded","*/*");
+ } else {
+ route(env,meth,path,code,application,"application/json;version="+version,"*/*");
+ }
+ }
+
+ @Override
+ public Filter[] filters() throws CadiException, LocatorException {
+ try {
+ DirectOAuthTAF doat;
+ return new Filter[] {new AuthzTransFilter(env,aafCon(),
+ new AAFTrustChecker((Env)env),
+ doat = new DirectOAuthTAF(env,question,facade1_0),
+ doat.directUserPass()
+ )};
+ } catch (NumberFormatException | APIException e) {
+ throw new CadiException("Invalid Property information", e);
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Registrant<AuthzEnv>[] registrants(final int port) throws CadiException {
+ return new Registrant[] {
+ new DirectRegistrar(access,question.locateDAO,app_name,app_version,port),
+ new DirectRegistrar(access,question.locateDAO,app_name.replace(DOT_OAUTH, ".token"),app_version,port),
+ new DirectRegistrar(access,question.locateDAO,app_name.replace(DOT_OAUTH, ".introspect"),app_version,port)
+
+ };
+ }
+
+
+ @Override
+ public void destroy() {
+ Cache.stopTimer();
+ if(service!=null) {
+ service.close();
+ }
+ if(cluster!=null) {
+ cluster.close();
+ }
+ super.destroy();
+ }
+
+ // For use in CADI ONLY
+ public TokenMgr.TokenPermLoader tpLoader() {
+ return tpLoader;
+ }
+
+ public static void main(final String[] args) {
+ PropAccess propAccess = new PropAccess(args);
+ try {
+ AAF_OAuth service = new AAF_OAuth(new AuthzEnv(propAccess));
+// env.setLog4JNames("log4j.properties","authz","oauth","audit","init","trace");
+ JettyServiceStarter<AuthzEnv,AuthzTrans> jss = new JettyServiceStarter<AuthzEnv,AuthzTrans>(service);
+ jss.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/DirectOAuthTAF.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/DirectOAuthTAF.java
new file mode 100644
index 00000000..74c9947d
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/DirectOAuthTAF.java
@@ -0,0 +1,224 @@
+/**
+ * ============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.auth.oauth;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aaf.auth.dao.hl.Question;
+import org.onap.aaf.auth.direct.DirectAAFUserPass;
+import org.onap.aaf.auth.env.AuthzEnv;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.oauth.facade.DirectIntrospect;
+import org.onap.aaf.auth.rserv.TransFilter;
+import org.onap.aaf.cadi.CachedPrincipal;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.Hash;
+import org.onap.aaf.cadi.LocatorException;
+import org.onap.aaf.cadi.PropAccess;
+import org.onap.aaf.cadi.CachedPrincipal.Resp;
+import org.onap.aaf.cadi.CredVal.Type;
+import org.onap.aaf.cadi.Taf.LifeForm;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.oauth.OAuth2HttpTafResp;
+import org.onap.aaf.cadi.oauth.OAuth2Principal;
+import org.onap.aaf.cadi.oauth.TokenClient;
+import org.onap.aaf.cadi.oauth.TokenClientFactory;
+import org.onap.aaf.cadi.oauth.TokenMgr;
+import org.onap.aaf.cadi.oauth.TokenPerm;
+import org.onap.aaf.cadi.oauth.TokenMgr.TokenPermLoader;
+import org.onap.aaf.cadi.principal.OAuth2FormPrincipal;
+import org.onap.aaf.cadi.taf.HttpTaf;
+import org.onap.aaf.cadi.taf.TafResp;
+import org.onap.aaf.cadi.taf.TafResp.RESP;
+import org.onap.aaf.cadi.util.Split;
+import org.onap.aaf.misc.env.APIException;
+
+import aafoauth.v2_0.Introspect;
+
+public class DirectOAuthTAF implements HttpTaf {
+ private PropAccess access;
+ private DirectIntrospect<Introspect> oaFacade;
+ private TokenMgr tkMgr;
+ private final DirectAAFUserPass directUserPass;
+ private TokenClient altIntrospectClient;
+
+ public DirectOAuthTAF(AuthzEnv env, Question q, DirectIntrospect<Introspect> facade) throws APIException, CadiException {
+ access = env.access();
+ oaFacade = facade;
+ tkMgr = TokenMgr.getInstance(access,"dbToken","dbIntrospect");
+ String alt_url = access.getProperty(Config.AAF_ALT_OAUTH2_INTROSPECT_URL,null);
+ TokenClientFactory tcf;
+ if(alt_url!=null) {
+ try {
+ tcf = TokenClientFactory.instance(access);
+ String[] split = Split.split(',', alt_url);
+ int timeout = split.length>1?Integer.parseInt(split[1]):3000;
+ altIntrospectClient = tcf.newClient(split[0], timeout);
+ altIntrospectClient.client_creds(access.getProperty(Config.AAF_ALT_CLIENT_ID,null),
+ access.getProperty(Config.AAF_ALT_CLIENT_SECRET,null));
+ } catch (GeneralSecurityException | IOException | LocatorException e) {
+ throw new CadiException(e);
+ }
+ }
+
+ directUserPass = new DirectAAFUserPass(env,q);
+ }
+
+ @Override
+ public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
+ String value;
+ String token;
+ if((value=req.getHeader("Authorization"))!=null && value.startsWith("Bearer ")) {
+ token = value.substring(7);
+ } else {
+ token = null;
+ }
+
+ if("application/x-www-form-urlencoded".equals(req.getContentType())) {
+ Map<String, String[]> map = req.getParameterMap();
+ String client_id=null,client_secret=null,username=null,password=null;
+ for(Map.Entry<String, String[]> es : map.entrySet()) {
+ switch(es.getKey()) {
+ case "client_id":
+ for(String s : es.getValue()) {
+ client_id=s;
+ }
+ break;
+ case "client_secret":
+ for(String s : es.getValue()) {
+ client_secret=s;
+ }
+ break;
+ case "username":
+ for(String s : es.getValue()) {
+ username=s;
+ }
+ break;
+ case "password":
+ for(String s : es.getValue()) {
+ password=s;
+ }
+ break;
+ case "token":
+ if(token!=null) { // Defined as both Bearer and Form Encoded - Error
+ return new OAuth2HttpTafResp(access, null, "Token Info found as both Bearer Token and Form Info", RESP.FAIL, resp, true);
+ }
+ for(String s : es.getValue()) {
+ token=s;
+ }
+ break;
+ // Ignore others
+ }
+ }
+
+ if(client_id==null && client_secret==null) {
+ return new OAuth2HttpTafResp(access, null, "client_id and client_secret required", RESP.TRY_ANOTHER_TAF, resp, false);
+ }
+
+ if(token==null) { // No Token to work with, use only Client_ID and Client_Secret
+ AuthzTrans trans = (AuthzTrans)req.getAttribute(TransFilter.TRANS_TAG);
+
+ if(directUserPass.validate(client_id, Type.PASSWORD, client_secret.getBytes(), trans)) {
+ // Client_ID is valid
+ if(username==null) { // Validating just the Client_ID
+ return new OAuth2FormHttpTafResp(access,new OAuth2FormPrincipal(client_id,client_id),"OAuth client_id authenticated",RESP.IS_AUTHENTICATED,resp,false);
+ } else {
+ //TODO - Does a clientID need specific Authorization to pair authentication with user name? At the moment, no.
+ // username is ok.
+ if(password!=null) {
+ if(directUserPass.validate(username, Type.PASSWORD, password.getBytes(), trans)) {
+ return new OAuth2FormHttpTafResp(access,new OAuth2FormPrincipal(client_id, username),"OAuth username authenticated",RESP.IS_AUTHENTICATED,resp,false);
+ } else {
+ return new OAuth2HttpTafResp(access,null,"OAuth username " + username + " not authenticated ",RESP.FAIL,resp,true);
+ }
+ } else { // no Password
+ //TODO Check for Trust Permission, which requires looking up Perms?
+ return new OAuth2HttpTafResp(access,null,"OAuth username " + username + " not authenticated ",RESP.FAIL,resp,true);
+ }
+ }
+ } else {
+ return new OAuth2HttpTafResp(access,null,"OAuth client_id " + client_id + " not authenticated ",RESP.FAIL,resp,true);
+ }
+ }
+ }
+
+ // OK, have only a Token to validate
+ if(token!=null) {
+ AuthzTrans trans = (AuthzTrans)req.getAttribute(TransFilter.TRANS_TAG);
+
+ try {
+ Result<Introspect> ri = oaFacade.mappedIntrospect(trans, token);
+ if(ri.isOK()) {
+ TokenPerm tp = tkMgr.putIntrospect(ri.value, Hash.hashSHA256(token.getBytes()));
+ if(tp==null) {
+ return new OAuth2HttpTafResp(access, null, "TokenPerm persistence failure", RESP.FAIL, resp, false);
+ } else {
+ return new OAuth2HttpTafResp(access,new OAuth2Principal(tp,Hash.hashSHA256(token.getBytes())),"Token Authenticated",RESP.IS_AUTHENTICATED,resp,false);
+ }
+ } else {
+ return new OAuth2HttpTafResp(access, null, ri.errorString(), RESP.FAIL, resp, false);
+ }
+ } catch (APIException e) {
+ trans.error().log(e,"Error getting token");
+ return new OAuth2HttpTafResp(access, null, "Error getting token: " + e.getMessage(), RESP.TRY_ANOTHER_TAF, resp, false);
+ } catch (NoSuchAlgorithmException e) {
+ return new OAuth2HttpTafResp(access, null, "Error in security algorithm: " + e.getMessage(), RESP.TRY_ANOTHER_TAF, resp, false);
+ }
+ }
+ return new OAuth2HttpTafResp(access, null, "No OAuth2 Credentials in OAuthForm", RESP.TRY_ANOTHER_TAF, resp, false);
+ }
+
+ @Override
+ public Resp revalidate(CachedPrincipal prin, Object state) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ class ServiceTPL implements TokenPermLoader {
+ private final AuthzTrans trans;
+ public ServiceTPL(AuthzTrans atrans) {
+ trans = atrans;
+ }
+
+ @Override
+ public org.onap.aaf.cadi.client.Result<TokenPerm> load(String accessToken, byte[] cred) throws APIException, CadiException, LocatorException {
+ Result<Introspect> ri = oaFacade.mappedIntrospect(trans, accessToken);
+ if(ri.notOK()) {
+ //TODO what should the status mapping be?
+ return org.onap.aaf.cadi.client.Result.err(ri.status,ri.errorString());
+ }
+ return org.onap.aaf.cadi.client.Result.ok(200,tkMgr.putIntrospect(ri.value, cred));
+ }
+ }
+
+ public DirectAAFUserPass directUserPass() {
+ return directUserPass;
+ }
+}
+
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OACode.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OACode.java
new file mode 100644
index 00000000..f60c689b
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OACode.java
@@ -0,0 +1,45 @@
+/**
+ * ============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.auth.oauth;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.oauth.facade.OAFacade;
+import org.onap.aaf.auth.rserv.HttpCode;
+
+import aafoauth.v2_0.Introspect;
+
+public abstract class OACode extends HttpCode<AuthzTrans, OAFacade<Introspect>> implements Cloneable {
+ public boolean useJSON;
+
+ public OACode(OAFacade<Introspect> facade, String description, boolean useJSON, String ... roles) {
+ super(facade, description, roles);
+ this.useJSON = useJSON;
+ }
+
+ public <D extends OACode> D clone(OAFacade<Introspect> facade, boolean useJSON) throws Exception {
+ @SuppressWarnings("unchecked")
+ D d = (D)clone();
+ d.useJSON = useJSON;
+ d.context = facade;
+ return d;
+ }
+
+} \ No newline at end of file
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2Filter.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2Filter.java
new file mode 100644
index 00000000..4442e36f
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2Filter.java
@@ -0,0 +1,64 @@
+/**
+ * ============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.auth.oauth;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.onap.aaf.cadi.principal.BearerPrincipal;
+import org.onap.aaf.cadi.util.Split;
+
+public class OAuth2Filter implements Filter {
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest hreq = (HttpServletRequest)request;
+ Principal p = hreq.getUserPrincipal();
+ if(request.getContentType().equals("application/x-www-form-urlencoded")) {
+
+ } else if(p instanceof BearerPrincipal) {
+ for(String authz : Split.splitTrim(';', hreq.getHeader("Authorization"))) {
+ if(authz.startsWith("Bearer ")) {
+ ((BearerPrincipal)p).setBearer(authz.substring(7));
+ }
+ }
+ }
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2FormHttpTafResp.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2FormHttpTafResp.java
new file mode 100644
index 00000000..23d87e3e
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2FormHttpTafResp.java
@@ -0,0 +1,65 @@
+/**
+ * ============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.auth.oauth;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.principal.OAuth2FormPrincipal;
+import org.onap.aaf.cadi.principal.TrustPrincipal;
+import org.onap.aaf.cadi.taf.AbsTafResp;
+import org.onap.aaf.cadi.taf.TafResp;
+
+public class OAuth2FormHttpTafResp extends AbsTafResp implements TafResp {
+ private HttpServletResponse httpResp;
+ private RESP status;
+ private final boolean wasFailed;
+
+ public OAuth2FormHttpTafResp(Access access, OAuth2FormPrincipal principal, String desc, RESP status, HttpServletResponse resp, boolean wasFailed) {
+ super(access,principal, desc);
+ httpResp = resp;
+ this.status = status;
+ this.wasFailed = wasFailed;
+ }
+
+ public OAuth2FormHttpTafResp(Access access, TrustPrincipal principal, String desc, RESP status,HttpServletResponse resp) {
+ super(access,principal, desc);
+ httpResp = resp;
+ this.status = status;
+ wasFailed = true; // if Trust Principal added, must be good
+ }
+
+ public RESP authenticate() throws IOException {
+ httpResp.setStatus(401); // Unauthorized
+ return RESP.HTTP_REDIRECT_INVOKED;
+ }
+
+ public RESP isAuthenticated() {
+ return status;
+ }
+
+ public boolean isFailedAttempt() {
+ return wasFailed;
+ }
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/api/API_Token.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/api/API_Token.java
new file mode 100644
index 00000000..f2836a7b
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/api/API_Token.java
@@ -0,0 +1,82 @@
+/**
+ * ============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.auth.oauth.api;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.oauth.AAF_OAuth;
+import org.onap.aaf.auth.oauth.OACode;
+import org.onap.aaf.auth.oauth.facade.OAFacade;
+import org.onap.aaf.auth.oauth.mapper.Mapper.API;
+import org.onap.aaf.auth.rserv.HttpMethods;
+
+import aafoauth.v2_0.Introspect;
+
+/**
+ * API Apis
+ * @author Jonathan
+ *
+ */
+public class API_Token {
+ // Hide Public Constructor
+ private API_Token() {}
+
+ /**
+ * Normal Init level APIs
+ *
+ * @param authzAPI
+ * @param facade
+ * @throws Exception
+ */
+ public static void init(final AAF_OAuth authzAPI, OAFacade<Introspect> facade) throws Exception {
+ ////////
+ // Overall APIs
+ ///////
+ authzAPI.route(HttpMethods.POST,"/token",API.TOKEN,new OACode(facade,"OAuth Token", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ Result<Void> r = context.createBearerToken(trans,req, resp);
+ if(r.isOK()) {
+ resp.setStatus(201/*HttpStatus.CREATED_201*/);
+ } else {
+ context.error(trans,resp,r);
+ }
+ }
+ });
+
+ authzAPI.route(HttpMethods.POST,"/introspect",API.INTROSPECT,new OACode(facade,"AAF Token Information", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ Result<Void> r = context.introspect(trans,req, resp);
+ if(r.isOK()) {
+ resp.setStatus(200 /*HttpStatus.OK_200*/);
+ } else {
+ context.error(trans,resp,r);
+ }
+ }
+ });
+
+ }
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospect.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospect.java
new file mode 100644
index 00000000..91423cef
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospect.java
@@ -0,0 +1,29 @@
+/**
+ * ============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.auth.oauth.facade;
+
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+
+public interface DirectIntrospect<INTROSPECT> {
+ Result<INTROSPECT> mappedIntrospect(AuthzTrans trans, String token);
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospectImpl.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospectImpl.java
new file mode 100644
index 00000000..91431c34
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospectImpl.java
@@ -0,0 +1,57 @@
+/**
+ * ============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.auth.oauth.facade;
+
+import org.onap.aaf.auth.dao.cass.OAuthTokenDAO;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.FacadeImpl;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.oauth.mapper.MapperIntrospect;
+import org.onap.aaf.auth.oauth.service.OAuthService;
+
+public class DirectIntrospectImpl<INTROSPECT> extends FacadeImpl implements DirectIntrospect<INTROSPECT> {
+ protected OAuthService service;
+ private MapperIntrospect<INTROSPECT> mapper;
+
+ public DirectIntrospectImpl(OAuthService service, MapperIntrospect<INTROSPECT> mapper) {
+ this.service = service;
+ this.mapper = mapper;
+ }
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.oauth.facade.OAFacade#mappedIntrospect(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
+ */
+ @Override
+ public Result<INTROSPECT> mappedIntrospect(AuthzTrans trans, String token) {
+ Result<INTROSPECT> rti;
+ Result<OAuthTokenDAO.Data> rs = service.introspect(trans,token);
+ if(rs.notOK()) {
+ rti = Result.err(rs);
+ } else if(rs.isEmpty()) {
+ rti = Result.err(Result.ERR_NotFound,"No Token %s found",token);
+ } else {
+ rti = mapper.introspect(rs);
+ }
+ return rti;
+ }
+
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectOAFacadeImpl.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectOAFacadeImpl.java
new file mode 100644
index 00000000..f71f7c15
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectOAFacadeImpl.java
@@ -0,0 +1,28 @@
+/**
+ * ============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.auth.oauth.facade;
+
+import org.onap.aaf.auth.layer.FacadeImpl;
+
+public class DirectOAFacadeImpl extends FacadeImpl {
+
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade.java
new file mode 100644
index 00000000..52ff38b7
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade.java
@@ -0,0 +1,67 @@
+/**
+ * ============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.auth.oauth.facade;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.oauth.service.OAuthService;
+
+
+/**
+ *
+ * @author Jonathan
+ *
+ */
+public interface OAFacade<INTROSPECT> {
+
+///////////////////// STANDARD ELEMENTS //////////////////
+ /**
+ * @param trans
+ * @param response
+ * @param result
+ */
+ public void error(AuthzTrans trans, HttpServletResponse response, Result<?> result);
+
+ /**
+ *
+ * @param trans
+ * @param response
+ * @param status
+ */
+ public void error(AuthzTrans trans, HttpServletResponse response, int status, String msg, String ... detail);
+
+ public Result<Void> createBearerToken(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp);
+
+ public Result<Void> introspect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp);
+
+ public OAuthService service();
+
+
+///////////////////// STANDARD ELEMENTS //////////////////
+
+
+
+
+} \ No newline at end of file
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade1_0.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade1_0.java
new file mode 100644
index 00000000..204a104a
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade1_0.java
@@ -0,0 +1,47 @@
+/**
+ * ============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.auth.oauth.facade;
+
+import org.onap.aaf.auth.oauth.AAF_OAuth;
+import org.onap.aaf.auth.oauth.mapper.Mapper;
+import org.onap.aaf.auth.oauth.service.OAuthService;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Data;
+
+import aaf.v2_0.Error;
+import aafoauth.v2_0.Introspect;
+import aafoauth.v2_0.Token;
+import aafoauth.v2_0.TokenRequest;
+
+/**
+ * @author Jonathan
+ *
+ */
+public class OAFacade1_0 extends OAFacadeImpl<TokenRequest,Token,Introspect,Error> {
+ public OAFacade1_0(AAF_OAuth api,
+ OAuthService service,
+ Mapper<TokenRequest,Token,Introspect,Error> mapper,
+ Data.TYPE type) throws APIException {
+ super(api, service, mapper, type);
+ }
+
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeFactory.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeFactory.java
new file mode 100644
index 00000000..ff586007
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeFactory.java
@@ -0,0 +1,47 @@
+/**
+ * ============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.auth.oauth.facade;
+
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.oauth.AAF_OAuth;
+import org.onap.aaf.auth.oauth.mapper.Mapper1_0;
+import org.onap.aaf.auth.oauth.mapper.MapperIntrospect1_0;
+import org.onap.aaf.auth.oauth.service.OAuthService;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Data;
+
+import aafoauth.v2_0.Introspect;
+
+
+public class OAFacadeFactory {
+ public static OAFacade1_0 v1_0(AAF_OAuth certman, AuthzTrans trans, OAuthService service, Data.TYPE type) throws APIException {
+ return new OAFacade1_0(
+ certman,
+ service,
+ new Mapper1_0(),
+ type);
+ }
+
+ public static DirectIntrospect<Introspect> directV1_0(OAuthService service) {
+ return new DirectIntrospectImpl<Introspect>(service, new MapperIntrospect1_0());
+ }
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeImpl.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeImpl.java
new file mode 100644
index 00000000..ee35b8bf
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeImpl.java
@@ -0,0 +1,333 @@
+/**
+ * ============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.auth.oauth.facade;
+
+import static org.onap.aaf.auth.layer.Result.ERR_ActionNotCompleted;
+import static org.onap.aaf.auth.layer.Result.ERR_BadData;
+import static org.onap.aaf.auth.layer.Result.ERR_ConflictAlreadyExists;
+import static org.onap.aaf.auth.layer.Result.ERR_Denied;
+import static org.onap.aaf.auth.layer.Result.ERR_NotFound;
+import static org.onap.aaf.auth.layer.Result.ERR_NotImplemented;
+import static org.onap.aaf.auth.layer.Result.ERR_Policy;
+import static org.onap.aaf.auth.layer.Result.ERR_Security;
+import static org.onap.aaf.auth.layer.Result.OK;
+
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aaf.auth.dao.cass.OAuthTokenDAO;
+import org.onap.aaf.auth.dao.cass.Status;
+import org.onap.aaf.auth.dao.hl.Question;
+import org.onap.aaf.auth.env.AuthzEnv;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.oauth.AAF_OAuth;
+import org.onap.aaf.auth.oauth.mapper.Mapper;
+import org.onap.aaf.auth.oauth.mapper.Mapper.API;
+import org.onap.aaf.auth.oauth.service.OAuthService;
+import org.onap.aaf.auth.oauth.service.OAuthService.GRANT_TYPE;
+import org.onap.aaf.cadi.client.Holder;
+import org.onap.aaf.cadi.oauth.OAuth2Principal;
+import org.onap.aaf.cadi.principal.OAuth2FormPrincipal;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Data;
+import org.onap.aaf.misc.env.Env;
+import org.onap.aaf.misc.env.TimeTaken;
+import org.onap.aaf.misc.rosetta.env.RosettaDF;
+import org.onap.aaf.misc.rosetta.env.RosettaData;
+
+import aaf.v2_0.Perms;
+
+/**
+ * AuthzFacade
+ *
+ * This Service Facade encapsulates the essence of the API Service can do, and provides
+ * a single created object for elements such as RosettaDF.
+ *
+ * The Responsibilities of this class are to:
+ * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage)
+ * 2) Validate incoming data (if applicable)
+ * 3) Convert the Service response into the right Format, and mark the Content Type
+ * a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request.
+ * 4) Log Service info, warnings and exceptions as necessary
+ * 5) When asked by the API layer, this will create and write Error content to the OutputStream
+ *
+ * Note: This Class does NOT set the HTTP Status Code. That is up to the API layer, so that it can be
+ * clearly coordinated with the API Documentation
+ *
+ * @author Jonathan
+ *
+ */
+public abstract class OAFacadeImpl<TOKEN_REQ,TOKEN,INTROSPECT,ERROR>
+ extends DirectIntrospectImpl<INTROSPECT> implements OAFacade<INTROSPECT> {
+ private static final String INVALID_INPUT = "Invalid Input";
+ private final RosettaDF<TOKEN> tokenDF;
+ private final RosettaDF<TOKEN_REQ> tokenReqDF;
+ private final RosettaDF<INTROSPECT> introspectDF;
+ private final RosettaDF<ERROR> errDF;
+ public final RosettaDF<Perms> permsDF;
+ private final Mapper<TOKEN_REQ, TOKEN, INTROSPECT, ERROR> mapper;
+
+ public OAFacadeImpl(AAF_OAuth api,
+ OAuthService service,
+ Mapper<TOKEN_REQ,TOKEN,INTROSPECT,ERROR> mapper,
+ Data.TYPE dataType) throws APIException {
+ super(service, mapper);
+ this.mapper = mapper;
+ AuthzEnv env = api.env;
+ (tokenReqDF = env.newDataFactory(mapper.getClass(API.TOKEN_REQ))).in(dataType).out(dataType);
+ (tokenDF = env.newDataFactory(mapper.getClass(API.TOKEN))).in(dataType).out(dataType);
+ (introspectDF = env.newDataFactory(mapper.getClass(API.INTROSPECT))).in(dataType).out(dataType);
+ (permsDF = env.newDataFactory(Perms.class)).in(dataType).out(dataType);
+ (errDF = env.newDataFactory(mapper.getClass(API.ERROR))).in(dataType).out(dataType);
+ }
+
+ ///////////////////////////
+ // Tokens
+ ///////////////////////////
+ public static final String CREATE_TOKEN = "createToken";
+ public static final String INTROSPECT = "introspect";
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.oauth.facade.OAFacade#getToken(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, org.onap.aaf.auth.oauth.service.OAuthAPI)
+ */
+ @Override
+ public Result<Void> createBearerToken(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
+ TimeTaken tt = trans.start(CREATE_TOKEN, Env.SUB|Env.ALWAYS);
+ try {
+ TOKEN_REQ request;
+ try {
+ request = mapper.tokenReqFromParams(req);
+ if(request==null) {
+ Data<TOKEN_REQ> rd = tokenReqDF.newData().load(req.getInputStream());
+ if(Question.willSpecialLog(trans, trans.user())) {
+ Question.logEncryptTrace(trans,rd.asString());
+ }
+ request = rd.asObject();
+ }
+ } catch(APIException e) {
+ trans.error().log(INVALID_INPUT,IN,CREATE_TOKEN);
+ return Result.err(Status.ERR_BadData,INVALID_INPUT);
+ }
+
+ // Already validated for Oauth2FormPrincipal
+// Result<Void> rv = service.validate(trans,mapper.credsFromReq(request));
+// if(rv.notOK()) {
+// return rv;
+// }
+ Holder<GRANT_TYPE> hgt = new Holder<GRANT_TYPE>(GRANT_TYPE.unknown);
+ Result<OAuthTokenDAO.Data> rs = service.createToken(trans,req,mapper.clientTokenReq(request,hgt),hgt);
+ Result<TOKEN> rp;
+ if(rs.isOKhasData()) {
+ rp = mapper.tokenFromData(rs);
+ } else {
+ rp = Result.err(rs);
+ }
+ switch(rp.status) {
+ case OK:
+ RosettaData<TOKEN> data = tokenDF.newData(trans).load(rp.value);
+ if(Question.willSpecialLog(trans, trans.user())) {
+ Question.logEncryptTrace(trans,data.asString());
+ }
+ data.to(resp.getOutputStream());
+ resp.getOutputStream().print('\n');
+ setContentType(resp,tokenDF.getOutType());
+ return Result.ok();
+ default:
+ return Result.err(rp);
+ }
+ } catch (Exception e) {
+ trans.error().log(e,IN,CREATE_TOKEN);
+ return Result.err(e);
+ } finally {
+ tt.done();
+ }
+
+ }
+
+/* (non-Javadoc)
+ * @see org.onap.aaf.auth.oauth.facade.OAFacade#Introspect(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public Result<Void> introspect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
+ TimeTaken tt = trans.start(INTROSPECT, Env.SUB|Env.ALWAYS);
+ try {
+ Principal p = req.getUserPrincipal();
+ String token=null;
+ if(p != null) {
+ if(p instanceof OAuth2Principal) {
+ RosettaData<INTROSPECT> data = introspectDF.newData(trans).load(mapper.fromPrincipal((OAuth2Principal)p));
+ if(Question.willSpecialLog(trans, trans.user())) {
+ Question.logEncryptTrace(trans,data.asString());
+ }
+ data.to(resp.getOutputStream());
+ resp.getOutputStream().print('\n');
+ setContentType(resp,tokenDF.getOutType());
+ return Result.ok();
+ } else if(p instanceof OAuth2FormPrincipal) {
+ token = req.getParameter("token");
+ }
+ }
+
+ if(token==null) {
+ token = req.getParameter("access_token");
+ if(token==null || token.isEmpty()) {
+ token = req.getHeader("Authorization");
+ if(token != null && token.startsWith("Bearer ")) {
+ token = token.substring(7);
+ } else {
+ token = req.getParameter("token");
+ if(token==null) {
+ return Result.err(Result.ERR_Security,"token is required");
+ }
+ }
+ }
+ }
+
+ Result<INTROSPECT> rti = mappedIntrospect(trans,token);
+ switch(rti.status) {
+ case OK:
+ RosettaData<INTROSPECT> data = introspectDF.newData(trans).load(rti.value);
+ if(Question.willSpecialLog(trans, trans.user())) {
+ Question.logEncryptTrace(trans,data.asString());
+ }
+ data.to(resp.getOutputStream());
+ resp.getOutputStream().print('\n');
+ setContentType(resp,tokenDF.getOutType());
+ return Result.ok();
+ default:
+ return Result.err(rti);
+ }
+ } catch (Exception e) {
+ trans.error().log(e,IN,INTROSPECT);
+ return Result.err(e);
+ } finally {
+ tt.done();
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.att.authz.facade.AuthzFacade#error(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, int)
+ *
+ * Note: Conforms to AT&T TSS RESTful Error Structure
+ */
+ @Override
+ public void error(AuthzTrans trans, HttpServletResponse response, Result<?> result) {
+ error(trans, response, result.status,
+ result.details==null?"":result.details.trim(),
+ result.variables==null?new String[0]:result.variables);
+ }
+
+ @Override
+ public void error(AuthzTrans trans, HttpServletResponse response, int status, final String _msg, final String ... _detail) {
+ String msgId;
+ String prefix;
+ boolean hidemsg=false;
+ switch(status) {
+ case 202:
+ case ERR_ActionNotCompleted:
+ msgId = "SVC1202";
+ prefix = "Accepted, Action not complete";
+ response.setStatus(/*httpstatus=*/202);
+ break;
+
+ case 403:
+ case ERR_Policy:
+ case ERR_Security:
+ case ERR_Denied:
+ msgId = "SVC1403";
+ prefix = "Forbidden";
+ response.setStatus(/*httpstatus=*/403);
+ break;
+
+ case 404:
+ case ERR_NotFound:
+ msgId = "SVC1404";
+ prefix = "Not Found";
+ response.setStatus(/*httpstatus=*/404);
+ break;
+
+ case 406:
+ case ERR_BadData:
+ msgId="SVC1406";
+ prefix = "Not Acceptable";
+ response.setStatus(/*httpstatus=*/406);
+ break;
+
+ case 409:
+ case ERR_ConflictAlreadyExists:
+ msgId = "SVC1409";
+ prefix = "Conflict Already Exists";
+ response.setStatus(/*httpstatus=*/409);
+ break;
+
+ case 501:
+ case ERR_NotImplemented:
+ msgId = "SVC1501";
+ prefix = "Not Implemented";
+ response.setStatus(/*httpstatus=*/501);
+ break;
+
+
+ default:
+ msgId = "SVC1500";
+ prefix = "General Service Error";
+ response.setStatus(/*httpstatus=*/500);
+ hidemsg=true;
+ break;
+ }
+
+ try {
+ StringBuilder holder = new StringBuilder();
+ ERROR em = mapper.errorFromMessage(holder, msgId,prefix + ": " + _msg,_detail);
+ trans.checkpoint(
+ "ErrResp [" +
+ msgId +
+ "] " +
+ holder.toString(),
+ Env.ALWAYS);
+ if(hidemsg) {
+ holder.setLength(0);
+ em = mapper.errorFromMessage(holder, msgId, "Server had an issue processing this request");
+ }
+ errDF.newData(trans).load(em).to(response.getOutputStream());
+
+ } catch (Exception e) {
+ trans.error().log(e,"unable to send response for",_msg);
+ }
+ }
+
+ public Mapper<TOKEN_REQ,TOKEN,INTROSPECT,ERROR> mapper() {
+ return mapper;
+ }
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.oauth.facade.OAFacade#service()
+ */
+ @Override
+ public OAuthService service() {
+ return service;
+ }
+} \ No newline at end of file
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper.java
new file mode 100644
index 00000000..55100e21
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper.java
@@ -0,0 +1,47 @@
+/**
+ * ============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.auth.oauth.mapper;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.onap.aaf.auth.dao.cass.OAuthTokenDAO;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.oauth.service.OCreds;
+import org.onap.aaf.auth.oauth.service.OAuthService.GRANT_TYPE;
+import org.onap.aaf.cadi.client.Holder;
+import org.onap.aaf.cadi.oauth.OAuth2Principal;
+
+public interface Mapper<TOKEN_REQ,TOKEN,INTROSPECT,ERROR> extends MapperIntrospect<INTROSPECT>
+{
+ public enum API{TOKEN_REQ, TOKEN,INTROSPECT, ERROR,VOID};
+
+ public Class<?> getClass(API api);
+ public<A> A newInstance(API api);
+
+ public ERROR errorFromMessage(StringBuilder holder, String msgID, String text, String... detail);
+ public TOKEN_REQ tokenReqFromParams(HttpServletRequest req);
+ public OCreds credsFromReq(TOKEN_REQ tokReq);
+
+ public OAuthTokenDAO.Data clientTokenReq(TOKEN_REQ tokReq, Holder<GRANT_TYPE> hgt);
+ public Result<TOKEN> tokenFromData(Result<OAuthTokenDAO.Data> rs);
+ public INTROSPECT fromPrincipal(OAuth2Principal p);
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper1_0.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper1_0.java
new file mode 100644
index 00000000..ee4237c8
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper1_0.java
@@ -0,0 +1,225 @@
+/**
+ * ============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.auth.oauth.mapper;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.onap.aaf.auth.dao.cass.OAuthTokenDAO;
+import org.onap.aaf.auth.dao.cass.OAuthTokenDAO.Data;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.oauth.service.OAuthService;
+import org.onap.aaf.auth.oauth.service.OCreds;
+import org.onap.aaf.auth.oauth.service.OAuthService.CLIENT_TYPE;
+import org.onap.aaf.auth.oauth.service.OAuthService.GRANT_TYPE;
+import org.onap.aaf.cadi.client.Holder;
+import org.onap.aaf.cadi.oauth.OAuth2Principal;
+import org.onap.aaf.cadi.util.Vars;
+import org.onap.aaf.misc.env.util.Split;
+
+import aaf.v2_0.Error;
+import aafoauth.v2_0.Introspect;
+import aafoauth.v2_0.Token;
+import aafoauth.v2_0.TokenRequest;
+
+
+public class Mapper1_0 extends MapperIntrospect1_0 implements Mapper<TokenRequest,Token,Introspect,Error> {
+ @Override
+ public Class<?> getClass(API api) {
+ switch(api) {
+ case TOKEN_REQ: return TokenRequest.class;
+ case TOKEN: return Token.class;
+ case INTROSPECT: return Introspect.class;
+ case ERROR: return Error.class;
+ case VOID: return Void.class;
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <A> A newInstance(API api) {
+ switch(api) {
+ case TOKEN_REQ: return (A)new TokenRequest();
+ case TOKEN: return (A)new Token();
+ case INTROSPECT: return (A)new Introspect();
+ case ERROR: return (A)new Error();
+ case VOID: return null;
+ }
+ return null;
+ }
+
+ ////////////// Mapping Functions /////////////
+ @Override
+ public Error errorFromMessage(StringBuilder holder, String msgID, String text, String... var) {
+ Error err = new Error();
+ err.setMessageId(msgID);
+ // AT&T Restful Error Format requires numbers "%" placements
+ err.setText(Vars.convert(holder, text, var));
+ for(String s : var) {
+ err.getVariables().add(s);
+ }
+ return err;
+ }
+
+ @Override
+ public TokenRequest tokenReqFromParams(HttpServletRequest req) {
+ TokenRequest tr = new TokenRequest();
+ boolean data = false;
+ @SuppressWarnings("unchecked")
+ Map<String, String[]> map = req.getParameterMap();
+ for(Entry<String, String[]> es : map.entrySet()) {
+ switch(es.getKey()) {
+ case "client_id":
+ if(es.getValue().length==1) {
+ tr.setClientId(es.getValue()[0]);
+ data = true;
+ }
+ break;
+ case "client_secret":
+ if(es.getValue().length==1) {
+ tr.setClientSecret(es.getValue()[0]);
+ data = true;
+ }
+ break;
+ case "username":
+ if(es.getValue().length==1) {
+ tr.setUsername(es.getValue()[0]);
+ data = true;
+ }
+ break;
+ case "password":
+ if(es.getValue().length==1) {
+ tr.setPassword(es.getValue()[0]);
+ data = true;
+ }
+ break;
+ case "scope":
+ if(es.getValue().length==1) {
+ tr.setScope(es.getValue()[0]);
+ data = true;
+ }
+ break;
+ case "grant_type":
+ if(es.getValue().length==1) {
+ tr.setGrantType(es.getValue()[0]);
+ data = true;
+ }
+ break;
+ case "refresh_token":
+ if(es.getValue().length==1) {
+ tr.setRefreshToken(es.getValue()[0]);
+ data = true;
+ }
+ break;
+
+ }
+ }
+ return data?tr:null;
+ }
+
+
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.oauth.mapper.Mapper#credsFromReq(javax.servlet.http.HttpServletRequest)
+ */
+ @Override
+ public OCreds credsFromReq(TokenRequest tokReq) {
+ return new OCreds(tokReq.getClientId(),tokReq.getClientSecret(),
+ tokReq.getUsername(),tokReq.getPassword());
+ }
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.oauth.mapper.Mapper#tokenReq(java.lang.Object)
+ */
+ @Override
+ public Data clientTokenReq(TokenRequest tokReq, Holder<GRANT_TYPE> hgt) {
+ OAuthTokenDAO.Data tdd = new OAuthTokenDAO.Data();
+ tdd.client_id = tokReq.getClientId();
+ tdd.user = tokReq.getUsername();
+ if(tokReq.getRefreshToken()!=null) {
+ tdd.refresh=tokReq.getRefreshToken();
+ }
+
+ for(GRANT_TYPE ttt : GRANT_TYPE.values()) {
+ if(ttt.name().equals(tokReq.getGrantType())) {
+ hgt.set(ttt);
+ break;
+ }
+ }
+
+ switch(hgt.get()) {
+ case client_credentials:
+ case password:
+ case refresh_token:
+ tdd.type = CLIENT_TYPE.confidential.ordinal();
+ break;
+ default:
+ tdd.type = CLIENT_TYPE.unknown.ordinal();
+ break;
+ }
+ String scopes=tokReq.getScope();
+ if(scopes!=null) {
+ Set<String> ss = tdd.scopes(true);
+ for(String s: Split.split(' ', tokReq.getScope())) {
+ ss.add(s);
+ }
+ }
+
+ tdd.state = tokReq.getState();
+ return tdd;
+ }
+
+ @Override
+ public Result<Token> tokenFromData(Result<Data> rd) {
+ if(rd.notOK()) {
+ return Result.err(rd);
+ }
+ Data d = rd.value;
+ Token token = new Token();
+ if(OAuthService.TOKEN_TYPE.values().length>d.type) {
+ token.setTokenType(OAuthService.TOKEN_TYPE.values()[d.type].name());
+ } else {
+ token.setTokenType("Invalid");
+ }
+ token.setAccessToken(d.id);
+ token.setRefreshToken(d.refresh);
+ token.setExpiresIn((int)(d.exp_sec-(System.currentTimeMillis())/1000));
+ token.setScope(getScopes(d.scopes(false)));
+ token.setState(d.state);
+ return Result.ok(token);
+ }
+
+
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.oauth.mapper.Mapper#fromPrincipal(org.onap.aaf.cadi.oauth.OAuth2Principal)
+ */
+ @Override
+ public Introspect fromPrincipal(OAuth2Principal p) {
+ return p.tokenPerm().getIntrospect();
+ }
+
+} \ No newline at end of file
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect.java
new file mode 100644
index 00000000..bf558799
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect.java
@@ -0,0 +1,29 @@
+/**
+ * ============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.auth.oauth.mapper;
+
+import org.onap.aaf.auth.dao.cass.OAuthTokenDAO;
+import org.onap.aaf.auth.layer.Result;
+
+public interface MapperIntrospect<INTROSPECT> {
+ public Result<INTROSPECT> introspect(Result<OAuthTokenDAO.Data> rs);
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect1_0.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect1_0.java
new file mode 100644
index 00000000..00a94fdf
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect1_0.java
@@ -0,0 +1,74 @@
+/**
+ * ============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.auth.oauth.mapper;
+
+import java.util.Set;
+
+import org.onap.aaf.auth.dao.cass.OAuthTokenDAO.Data;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.oauth.service.OAuthService.CLIENT_TYPE;
+
+import aafoauth.v2_0.Introspect;
+
+public class MapperIntrospect1_0 implements MapperIntrospect<Introspect> {
+
+ public Result<Introspect> introspect(Result<Data> rs) {
+ if(rs.isOKhasData()) {
+ Data data = rs.value;
+ Introspect ti = new Introspect();
+ ti.setAccessToken(data.id);
+ ti.setActive(data.active);
+ ti.setClientId(data.client_id);
+ for(CLIENT_TYPE ct : CLIENT_TYPE.values()) {
+ if(data.type==ct.ordinal()) {
+ ti.setClientType(ct.name());
+ break;
+ }
+ }
+ if(ti.getClientType()==null) {
+ ti.setClientType(CLIENT_TYPE.unknown.name());
+ }
+ ti.setActive(data.active);
+ ti.setScope(getScopes(data.scopes(false)));
+ ti.setContent(data.content);
+ ti.setUsername(data.user);
+ ti.setExp(data.exp_sec); // want seconds from Jan 1, 1970
+ return Result.ok(ti);
+ }
+ return Result.err(rs);
+ }
+
+ protected static String getScopes(Set<String> scopes) {
+ StringBuilder sb = new StringBuilder();
+ boolean start = true;
+ for(String s : scopes) {
+ if(start) {
+ start = false;
+ } else {
+ sb.append(' ');
+ }
+ sb.append(s);
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoader.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoader.java
new file mode 100644
index 00000000..bf04472b
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoader.java
@@ -0,0 +1,34 @@
+/**
+ * ============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.auth.oauth.service;
+
+import java.util.Set;
+
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.misc.env.APIException;
+
+public interface JSONPermLoader {
+ public Result<String> loadJSONPerms(AuthzTrans trans, String user, Set<String> scopes) throws APIException, CadiException;
+
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoaderFactory.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoaderFactory.java
new file mode 100644
index 00000000..ea5c595c
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoaderFactory.java
@@ -0,0 +1,119 @@
+/**
+ * ============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.auth.oauth.service;
+
+import java.util.List;
+import java.util.Set;
+
+import org.onap.aaf.auth.dao.cass.PermDAO;
+import org.onap.aaf.auth.dao.hl.Question;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
+import org.onap.aaf.cadi.client.Future;
+import org.onap.aaf.cadi.client.Rcli;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Env;
+import org.onap.aaf.misc.env.TimeTaken;
+
+public class JSONPermLoaderFactory {
+ /**
+ * Load JSON Perms from AAF Service (Remotely)
+ * @param aafcon
+ * @param timeout
+ * @return
+ */
+ public static JSONPermLoader remote(final AAFCon<?> aafcon, final int timeout) {
+ return new JSONPermLoader() {
+ public Result<String> loadJSONPerms(AuthzTrans trans, String user, Set<String> scopes) throws APIException, CadiException {
+ Rcli<?> c = aafcon.clientAs(Config.AAF_DEFAULT_VERSION,trans.getUserPrincipal());
+ StringBuilder pathinfo = new StringBuilder("/authz/perms/user/");
+ pathinfo.append(user);
+ pathinfo.append("?scopes=");
+ boolean first = true;
+ for(String s : scopes) {
+ if(first) {
+ first = false;
+ } else {
+ pathinfo.append(':');
+ }
+ pathinfo.append(s);
+ }
+ TimeTaken tt = trans.start("Call AAF Service", Env.REMOTE);
+ try {
+ Future<String> fs = c.read(pathinfo.toString(), "application/Perms+json;charset=utf-8;version=2.0");
+ if(fs.get(timeout)) {
+ return Result.ok(fs.body());
+ } else if(fs.code()==404) {
+ return Result.err(Result.ERR_NotFound,fs.body());
+ } else {
+ return Result.err(Result.ERR_Backend,"Error accessing AAF %s: %s",Integer.toString(fs.code()),fs.body());
+ }
+ } finally {
+ tt.done();
+ }
+ }
+ };
+ }
+ public static JSONPermLoader direct(final Question question) {
+ return new JSONPermLoader() {
+ public Result<String> loadJSONPerms(AuthzTrans trans, String user, Set<String> scopes) throws APIException, CadiException {
+ TimeTaken tt = trans.start("Cached DB Perm lookup", Env.SUB);
+ Result<List<PermDAO.Data>> pd;
+ try {
+ pd = question.getPermsByUser(trans, user, false);
+ } finally {
+ tt.done();
+ }
+ if(pd.notOK()) {
+ return Result.err(pd);
+ }
+ // Since we know it is
+ StringBuilder sb = new StringBuilder("{\"perm\":[");
+ boolean first = true;
+ for(PermDAO.Data d : pd.value) {
+ if(scopes.contains(d.ns)) {
+ if(first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append("{\"type\":\"");
+ sb.append(d.ns);
+ sb.append('.');
+ sb.append(d.type);
+ sb.append("\",\"instance\":\"");
+ sb.append(d.instance);
+ sb.append("\",\"action\":\"");
+ sb.append(d.action);
+ sb.append("\"}");
+ }
+ }
+ sb.append("]}");
+ return Result.ok(sb.toString());
+ }
+ };
+ }
+
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OAuthService.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OAuthService.java
new file mode 100644
index 00000000..052b292e
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OAuthService.java
@@ -0,0 +1,301 @@
+/**
+ * ============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.auth.oauth.service;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.onap.aaf.auth.dao.DAO;
+import org.onap.aaf.auth.dao.cass.OAuthTokenDAO;
+import org.onap.aaf.auth.dao.cass.Status;
+import org.onap.aaf.auth.dao.cass.OAuthTokenDAO.Data;
+import org.onap.aaf.auth.dao.hl.Question;
+import org.onap.aaf.auth.direct.DirectAAFUserPass;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.env.NullTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.LocatorException;
+import org.onap.aaf.cadi.CredVal.Type;
+import org.onap.aaf.cadi.client.Holder;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.oauth.AAFToken;
+import org.onap.aaf.cadi.oauth.TokenClient;
+import org.onap.aaf.cadi.oauth.TokenClientFactory;
+import org.onap.aaf.cadi.util.Split;
+import org.onap.aaf.misc.env.APIException;
+
+import aafoauth.v2_0.Introspect;
+
+public class OAuthService {
+
+ private static final int TOK_EXP = 60*60*1000; // 1 hour, millis.
+
+ public enum TOKEN_TYPE {unknown,bearer,refresh}
+ public enum GRANT_TYPE {unknown,password,client_credentials,refresh_token};
+ public enum CLIENT_TYPE {unknown,confidential};
+
+ // Additional Expires
+ private final DAO<AuthzTrans, ?>[] daos;
+ public final OAuthTokenDAO tokenDAO;
+ private final DirectAAFUserPass directUserPass;
+ private final TokenClientFactory tcf;
+ private TokenClient altIntrospectClient;
+ private String altDomain;
+ private final JSONPermLoader permLoader;
+
+
+ // If we add more CAs, may want to parameterize
+
+ @SuppressWarnings("unchecked")
+ public OAuthService(final Access access, final AuthzTrans trans, final Question q) throws APIException, IOException {
+ permLoader = JSONPermLoaderFactory.direct(q);
+ tokenDAO = new OAuthTokenDAO(trans, q.historyDAO);
+ daos =(DAO<AuthzTrans, ?>[]) new DAO<?,?>[] {
+ tokenDAO
+ };
+ try {
+ String alt_url = access.getProperty(Config.AAF_ALT_OAUTH2_INTROSPECT_URL,null);
+ if(alt_url!=null) {
+ tcf = TokenClientFactory.instance(access);
+ String[] split = Split.split(',', alt_url);
+ int timeout = split.length>1?Integer.parseInt(split[1]):3000;
+ altIntrospectClient = tcf.newClient(split[0], timeout);
+ altIntrospectClient.client_creds(access.getProperty(Config.AAF_ALT_CLIENT_ID,null),
+ access.getProperty(Config.AAF_ALT_CLIENT_SECRET,null));
+ altDomain = '@'+access.getProperty(Config.AAF_ALT_OAUTH2_DOMAIN,null);
+ } else {
+ tcf = null;
+ }
+ directUserPass = new DirectAAFUserPass(trans.env(), q);
+ } catch (GeneralSecurityException | CadiException | LocatorException e) {
+ throw new APIException("Could not construct TokenClientFactory",e);
+ }
+
+ }
+
+ public Result<Void> validate(AuthzTrans trans, OCreds creds) {
+ if(directUserPass.validate(creds.username, Type.PASSWORD, creds.password, trans)) {
+ return Result.ok();
+ } else {
+ return Result.err(Result.ERR_Security, "Invalid Credential for ",creds.username);
+ }
+ }
+
+ public Result<Data> createToken(AuthzTrans trans, HttpServletRequest req, OAuthTokenDAO.Data odd, Holder<GRANT_TYPE> hgt) {
+ switch(hgt.get()) {
+ case client_credentials:
+ case password:
+ return createBearerToken(trans, odd);
+ case refresh_token:
+ return refreshBearerToken(trans, odd);
+ default:
+ return Result.err(Result.ERR_BadData, "Unknown Grant Type");
+ }
+ }
+
+ private Result<Data> createBearerToken(AuthzTrans trans, OAuthTokenDAO.Data odd) {
+ if(odd.user==null) {
+ odd.user = trans.user();
+ }
+ odd.id = AAFToken.toToken(UUID.randomUUID());
+ odd.refresh = AAFToken.toToken(UUID.randomUUID());
+ odd.active = true;
+ long exp;
+ odd.expires = new Date(exp=(System.currentTimeMillis()+TOK_EXP));
+ odd.exp_sec = exp/1000;
+ odd.req_ip = trans.ip();
+
+ try {
+ Result<Data> rd = loadToken(trans, odd);
+ if(rd.notOK()) {
+ return rd;
+ }
+ } catch (APIException | CadiException e) {
+ return Result.err(e);
+ }
+ return tokenDAO.create(trans, odd);
+ }
+
+ private Result<Data> loadToken(AuthzTrans trans, Data odd) throws APIException, CadiException {
+ Result<String> rs = permLoader.loadJSONPerms(trans,odd.user,odd.scopes(false));
+ if(rs.isOK()) {
+ odd.content = rs.value;
+ odd.type = TOKEN_TYPE.bearer.ordinal();
+ return Result.ok(odd);
+ } else if(rs.status == Result.ERR_NotFound || rs.status==Status.ERR_UserRoleNotFound) {
+ odd.type = TOKEN_TYPE.bearer.ordinal();
+ return Result.ok(odd);
+ } else {
+ return Result.err(Result.ERR_Backend,"Error accessing AAF Info: %s",rs.errorString());
+ }
+ }
+
+
+
+ private Result<Data> refreshBearerToken(AuthzTrans trans, Data odd) {
+ Result<List<Data>> rld = tokenDAO.readByUser(trans, trans.user());
+ if(rld.notOK()) {
+ return Result.err(rld);
+ }
+ if(rld.isEmpty()) {
+ return Result.err(Result.ERR_NotFound,"Data not Found for %1 %2",trans.user(),odd.refresh==null?"":odd.refresh.toString());
+ }
+ Data token = null;
+ for(Data d : rld.value) {
+ if(d.refresh.equals(odd.refresh)) {
+ token = d;
+ boolean scopesNE = false;
+ Set<String> scopes = odd.scopes(false);
+ if(scopes.size()>0) { // only check if Scopes listed, RFC 6749, Section 6
+ if(scopesNE=!(scopes.size() == d.scopes(false).size())) {
+ for(String s : odd.scopes(false)) {
+ if(!d.scopes(false).contains(s)) {
+ scopesNE=true;
+ break;
+ }
+ }
+ }
+ if(scopesNE) {
+ return Result.err(Result.ERR_BadData,"Requested Scopes do not match existing Token");
+ }
+ }
+ break;
+ }
+ }
+
+ if(token==null) {
+ trans.audit().printf("Duplicate Refresh Token (%s) attempted for %s. Possible Replay Attack",odd.refresh.toString(),trans.user());
+ return Result.err(Result.ERR_Security,"Invalid Refresh Token");
+ } else {
+ // Got the Result
+ Data deleteMe = new Data();
+ deleteMe.id = token.id;
+ token.id = AAFToken.toToken(UUID.randomUUID());
+ token.client_id = trans.user();
+ token.refresh = AAFToken.toToken(UUID.randomUUID());
+ long exp;
+ token.expires = new Date(exp=(System.currentTimeMillis()+TOK_EXP));
+ token.exp_sec = exp/1000;
+ token.req_ip = trans.ip();
+ Result<Data> rd = tokenDAO.create(trans, token);
+ if(rd.notOK()) {
+ return Result.err(rd);
+ }
+ Result<Void> rv = tokenDAO.delete(trans, deleteMe,false);
+ if(rv.notOK()) {
+ trans.error().log("Unable to delete token", token);
+ }
+ }
+ return Result.ok(token);
+ }
+
+ public Result<OAuthTokenDAO.Data> introspect(AuthzTrans trans, String token) {
+ Result<List<Data>> rld;
+ try {
+ UUID uuid = AAFToken.fromToken(token);
+ if(uuid==null) { // not an AAF Token
+ // Attempt to get Alternative Token
+ if(altIntrospectClient!=null) {
+ org.onap.aaf.cadi.client.Result<Introspect> rai = altIntrospectClient.introspect(token);
+ if(rai.isOK()) {
+ Introspect in = rai.value;
+ if(in.getExp()==null) {
+ trans.audit().printf("Alt OAuth sent back inactive, empty token: requesting_id,%s,access_token=%s,ip=%s\n",trans.user(),token,trans.ip());
+ }
+ long expires = in.getExp()*1000;
+ if(in.isActive() && expires>System.currentTimeMillis()) {
+ // We have a good Token, modify to be Fully Qualified
+ String fqid = in.getUsername()+altDomain;
+ // read contents
+ rld = tokenDAO.read(trans, token);
+ if(rld.isOKhasData()) {
+ Data td = rld.value.get(0);
+ in.setContent(td.content);
+ } else {
+ Data td = new Data();
+ td.id = token;
+ td.client_id = in.getClientId();
+ td.user = fqid;
+ td.active=true;
+ td.type = TOKEN_TYPE.bearer.ordinal();
+ td.expires = new Date(expires);
+ td.exp_sec = in.getExp();
+ Set<String> scopes = td.scopes(true);
+ if(in.getScope()!=null) {
+ for(String s : Split.split(' ', in.getScope())) {
+ scopes.add(s);
+ }
+ }
+ // td.state = nothing to add at this point
+ td.req_ip = trans.ip();
+ trans.checkpoint(td.user + ':' + td.client_id + ", " + td.id);
+ return loadToken(trans, td);
+ }
+ }
+// System.out.println(rai.value.getClientId());
+ } else {
+ trans.audit().printf("Alt OAuth rejects: requesting_id,%s,access_token=%s,ip=%s,code=%d,error=%s\n",trans.user(),token,trans.ip(),rai.code,rai.error);
+ }
+ } else {
+ trans.audit().printf("Bad Token: requesting_id,%s,access_token=%s,ip=%s\n",trans.user(),token,trans.ip());
+ }
+ return Result.err(Result.ERR_Denied,"Bad Token");
+ } else {
+ return dbIntrospect(trans,token);
+ }
+ } catch (CadiException | APIException | LocatorException e) {
+ return Result.err(e);
+ }
+ }
+
+ public Result<Data> dbIntrospect(final AuthzTrans trans, final String token) {
+ Result<List<Data>> rld = tokenDAO.read(trans, token);
+ if(rld.notOKorIsEmpty()) {
+ return Result.err(rld);
+ }
+ OAuthTokenDAO.Data odd = rld.value.get(0);
+ trans.checkpoint(odd.user + ':' + odd.client_id + ", " + odd.id);
+ if(odd.active) {
+ if(odd.expires.before(trans.now())) {
+ return Result.err(Result.ERR_Policy,"Token %1 has expired",token);
+ }
+ return Result.ok(rld.value.get(0)); // ok keyed on id/token.
+ } else {
+ return Result.err(Result.ERR_Denied,"Token %1 is inactive",token);
+ }
+ }
+
+ public void close() {
+ for(DAO<AuthzTrans,?> dao : daos) {
+ dao.close(NullTrans.singleton());
+ }
+ }
+
+}
diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OCreds.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OCreds.java
new file mode 100644
index 00000000..becb746a
--- /dev/null
+++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OCreds.java
@@ -0,0 +1,33 @@
+/**
+ * ============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.auth.oauth.service;
+
+public class OCreds {
+ public final String client_id, username;
+ public final byte[] client_secret, password;
+ public OCreds(String client_id, String client_secret, String username, String password) {
+ this.client_id = client_id;
+ this.client_secret = client_secret==null?null:client_secret.getBytes();
+ this.username = username;
+ this.password = password==null?null:password.getBytes();
+ }
+}