From 19afb93b23f264471c6e8db77b54e9a301a3114b Mon Sep 17 00:00:00 2001 From: Instrumental Date: Thu, 21 Jun 2018 15:08:47 -0500 Subject: Update REST Samples for required behavior Issue-ID: AAF-361 Change-Id: Ia6dabfa3eeec2253c3f017ddc2d70afe4afbd54b Signed-off-by: Instrumental --- .../main/java/org/onap/aaf/cadi/cm/CmAgent.java | 3 +- .../java/org/onap/aaf/cadi/oauth/TokenClient.java | 2 +- .../onap/aaf/cadi/oauth/TokenClientFactory.java | 5 +- .../main/java/org/onap/aaf/cadi/client/Rcli.java | 317 +++++++++++---------- .../aaf/cadi/locator/SingleEndpointLocator.java | 82 ++++++ .../org/onap/aaf/cadi/client/test/JU_Rcli.java | 40 ++- .../org/onap/aaf/cadi/enduser/ClientFactory.java | 56 ++++ .../onap/aaf/cadi/enduser/SimpleRESTClient.java | 133 +++++++++ .../java/com/att/cadi/enduser/OAuthExample.java | 238 ---------------- .../com/att/cadi/enduser/OnapClientExample.java | 210 -------------- .../onap/aaf/cadi/enduser/test/OAuthExample.java | 238 ++++++++++++++++ .../aaf/cadi/enduser/test/OnapClientExample.java | 210 ++++++++++++++ .../cadi/enduser/test/SimpleRestClientExample.java | 91 ++++++ 13 files changed, 998 insertions(+), 627 deletions(-) create mode 100644 cadi/client/src/main/java/org/onap/aaf/cadi/locator/SingleEndpointLocator.java create mode 100644 cadi/oauth-enduser/src/main/java/org/onap/aaf/cadi/enduser/ClientFactory.java create mode 100644 cadi/oauth-enduser/src/main/java/org/onap/aaf/cadi/enduser/SimpleRESTClient.java delete mode 100644 cadi/oauth-enduser/src/test/java/com/att/cadi/enduser/OAuthExample.java delete mode 100644 cadi/oauth-enduser/src/test/java/com/att/cadi/enduser/OnapClientExample.java create mode 100644 cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/OAuthExample.java create mode 100644 cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/OnapClientExample.java create mode 100644 cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/SimpleRestClientExample.java (limited to 'cadi') diff --git a/cadi/aaf/src/main/java/org/onap/aaf/cadi/cm/CmAgent.java b/cadi/aaf/src/main/java/org/onap/aaf/cadi/cm/CmAgent.java index bcc156c8..bdd95a77 100644 --- a/cadi/aaf/src/main/java/org/onap/aaf/cadi/cm/CmAgent.java +++ b/cadi/aaf/src/main/java/org/onap/aaf/cadi/cm/CmAgent.java @@ -497,8 +497,7 @@ public class CmAgent { cr.getFqdns().add(fqdns[i]); } Future f = aafcon.client(CM_VER) - .setQueryParams("withTrust") - .updateRespondString("/cert/" + a.getCa(),reqDF, cr); + .updateRespondString("/cert/" + a.getCa()+"?withTrust",reqDF, cr); if(f.get(TIMEOUT)) { CertInfo capi = certDF.newData().in(TYPE.JSON).load(f.body()).asObject(); for(String type : a.getType()) { diff --git a/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenClient.java b/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenClient.java index 0628d4d5..dec0b4e9 100644 --- a/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenClient.java +++ b/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenClient.java @@ -130,7 +130,7 @@ public class TokenClient { */ public void client_creds(final String client_id, final String client_secret) throws CadiException { if(client_id==null) { - throw new CadiException(Config.AAF_ALT_CLIENT_ID + " is null"); + throw new CadiException("client_creds:client_id is null"); } this.client_id = client_id; default_scope = FQI.reverseDomain(client_id); diff --git a/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenClientFactory.java b/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenClientFactory.java index 4f3fa87d..2b895761 100644 --- a/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenClientFactory.java +++ b/cadi/aaf/src/main/java/org/onap/aaf/cadi/oauth/TokenClientFactory.java @@ -43,6 +43,7 @@ import org.onap.aaf.cadi.aaf.v2_0.AAFLocator; import org.onap.aaf.cadi.config.Config; import org.onap.aaf.cadi.config.SecurityInfoC; import org.onap.aaf.cadi.locator.PropertyLocator; +import org.onap.aaf.cadi.locator.SingleEndpointLocator; import org.onap.aaf.cadi.oauth.TokenClient.AUTHN_METHOD; import org.onap.aaf.cadi.persist.Persist; import org.onap.aaf.cadi.principal.Kind; @@ -173,8 +174,10 @@ public class TokenClientFactory extends Persist { } if(locatorURL.startsWith("https://AAF_LOCATE_URL/") || locatePattern.matcher(locatorURL).matches()) { return new AAFLocator(hsi,new URI(locatorURL)); - } else { + } else if(locatorURL.indexOf(',')>0) { // multiple URLs is a Property Locator return new PropertyLocator(locatorURL); + } else { + return new SingleEndpointLocator(locatorURL); } // Note: Removed DME2Locator... If DME2 client is needed, use DME2Clients } diff --git a/cadi/client/src/main/java/org/onap/aaf/cadi/client/Rcli.java b/cadi/client/src/main/java/org/onap/aaf/cadi/client/Rcli.java index c93d233a..a98feb25 100644 --- a/cadi/client/src/main/java/org/onap/aaf/cadi/client/Rcli.java +++ b/cadi/client/src/main/java/org/onap/aaf/cadi/client/Rcli.java @@ -57,7 +57,7 @@ public abstract class Rcli { protected int readTimeout = 5000; protected int connectionTimeout = 3000; protected URI uri; - private String queryParams, fragment; + private String oneCallQueryParams; public static Pool buffPool = new Pool(new Pool.Creator() { @Override public byte[] create() throws APIException { @@ -132,15 +132,15 @@ public abstract class Rcli { protected abstract EClient client() throws CadiException; - public Future create(String pathinfo, String contentType, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + public Future create(final String pathinfo, final String contentType, final RosettaDF df, final T t) throws APIException, CadiException { + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(POST); client.addHeader(CONTENT_TYPE,contentType); - client.setPathInfo(pathinfo); - client.setQueryParams(qp); - client.setFragment(fragment); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -148,19 +148,18 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.futureCreate(df.getTypeClass()); } public Future create(String pathinfo, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(POST); client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass())); - client.setPathInfo(pathinfo); - client.setQueryParams(qp); - client.setFragment(fragment); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -168,19 +167,18 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.futureCreate(df.getTypeClass()); } public Future create(String pathinfo, Class cls, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(POST); client.addHeader(CONTENT_TYPE,typeString(cls)); - client.setPathInfo(pathinfo); - client.setQueryParams(qp); - client.setFragment(fragment); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -188,37 +186,34 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.futureCreate(df.getTypeClass()); } public Future create(String pathinfo, Class cls) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(POST); client.addHeader(CONTENT_TYPE,typeString(cls)); - client.setPathInfo(pathinfo); - client.setQueryParams(qp); - client.setFragment(fragment); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(null); client.send(); - queryParams = fragment = null; return client.futureCreate(cls); } public Future create(String pathinfo, String contentType) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(POST); client.addHeader(CONTENT_TYPE,contentType); - client.setPathInfo(pathinfo); - client.setQueryParams(qp); - client.setFragment(fragment); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(null); client.send(); - queryParams = fragment = null; return client.futureCreate(Void.class); } @@ -237,7 +232,7 @@ public abstract class Rcli { * @throws CadiException */ public Future postForm(String pathinfo, final RosettaDF df, final String ... formParam) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(POST); @@ -252,9 +247,9 @@ public abstract class Rcli { default: break; } - client.setPathInfo(pathinfo); - client.setQueryParams(qp); - client.setFragment(fragment); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -280,7 +275,6 @@ public abstract class Rcli { } }}); client.send(); - queryParams = fragment = null; return client.futureRead(df,TYPE.JSON); } @@ -296,14 +290,14 @@ public abstract class Rcli { * @throws CadiException */ public Future readPost(String pathinfo, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(POST); client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass())); - client.setPathInfo(pathinfo); - client.setQueryParams(qp); - client.setFragment(fragment); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -311,7 +305,6 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.futureReadString(); } @@ -327,14 +320,14 @@ public abstract class Rcli { * @throws CadiException */ public Future readPost(String pathinfo, final RosettaDF df, final T t, final RosettaDF resp) throws APIException, CadiException { - final String qp = setupParams(pathinfo); - + final ParsePath pp = new ParsePath(pathinfo); + EClient client = client(); client.setMethod(POST); client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass())); - client.setPathInfo(pathinfo); - client.setQueryParams(qp); - client.setFragment(fragment); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -342,30 +335,28 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.futureRead(resp,resp.getOutType()); } public Future readPost(String pathinfo, String contentType, String ... headers) throws CadiException, APIException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(POST); client.addHeader(CONTENT_TYPE,contentType); - client.setPathInfo(pathinfo); - client.setQueryParams(qp); - client.setFragment(fragment); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { }}); client.send(); - queryParams = fragment = null; return client.futureReadString(); } public Future read(String pathinfo, String accept, String ... headers) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(GET); @@ -374,19 +365,16 @@ public abstract class Rcli { for(int i=1;i Future read(String pathinfo, String accept, RosettaDF df, String ... headers) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(GET); @@ -394,18 +382,16 @@ public abstract class Rcli { for(int i=1;i Future read(String pathinfo, RosettaDF df,String ... headers) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(GET); @@ -413,41 +399,39 @@ public abstract class Rcli { for(int i=1;i Future read(String pathinfo, Class cls, RosettaDF df) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(GET); client.addHeader(ACCEPT, typeString(cls)); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); - + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); + client.setPayload(null); client.send(); - queryParams = fragment = null; return client.futureRead(df,type); } public Future update(String pathinfo, String contentType, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(PUT); client.addHeader(CONTENT_TYPE,contentType); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -455,19 +439,19 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.future(t); } public Future updateRespondString(String pathinfo, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); - + final ParsePath pp = new ParsePath(pathinfo); + EClient client = client(); client.setMethod(PUT); client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass())); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); + client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -475,20 +459,20 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.futureReadString(); } public Future update(String pathinfo, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(PUT); client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass())); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); + client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -496,19 +480,19 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.future(t); } public Future update(String pathinfo, Class cls, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); - + final ParsePath pp = new ParsePath(pathinfo); + EClient client = client(); client.setMethod(PUT); client.addHeader(CONTENT_TYPE, typeString(cls)); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); + client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -516,7 +500,6 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.future(t); } @@ -530,33 +513,34 @@ public abstract class Rcli { * @throws CadiException */ public Future update(String pathinfo) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(PUT); client.addHeader(CONTENT_TYPE, typeString(Void.class)); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); + // client.setPayload(new EClient.Transfer() { // @Override // public void transfer(OutputStream os) throws IOException, APIException { // } // }); client.send(); - queryParams = fragment = null; return client.future(null); } public Future delete(String pathinfo, String contentType, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(DELETE); client.addHeader(CONTENT_TYPE, contentType); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); + client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -564,19 +548,18 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.future(t); } public Future delete(String pathinfo, Class cls, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(DELETE); client.addHeader(CONTENT_TYPE, typeString(cls)); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -584,19 +567,18 @@ public abstract class Rcli { } }); client.send(); - queryParams = fragment = null; return client.future(t); } public Future delete(String pathinfo, final RosettaDF df, final T t) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(DELETE); client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass())); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); client.setPayload(new EClient.Transfer() { @Override public void transfer(OutputStream os) throws IOException, APIException { @@ -605,38 +587,37 @@ public abstract class Rcli { }); client.send(); - queryParams = fragment = null; return client.future(t); } public Future delete(String pathinfo, Class cls) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(DELETE); client.addHeader(CONTENT_TYPE, typeString(cls)); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); + client.setPayload(null); client.send(); - queryParams = fragment = null; return client.future((T)null); } public Future delete(String pathinfo, String contentType) throws APIException, CadiException { - final String qp = setupParams(pathinfo); + final ParsePath pp = new ParsePath(pathinfo); EClient client = client(); client.setMethod(DELETE); client.addHeader(CONTENT_TYPE, contentType); - client.setQueryParams(qp); - client.setFragment(fragment); - client.setPathInfo(pathinfo); + client.setPathInfo(pp.path()); + client.setQueryParams(pp.query()); + client.setFragment(pp.frag()); + client.setPayload(null); client.send(); - queryParams = fragment = null; return client.future(null); } @@ -680,47 +661,75 @@ public abstract class Rcli { return client.future(resp, expected); } - private String setupParams(String pathinfo) { - final String qp; - if(pathinfo==null) { - qp=queryParams; - } else { - final int idx = pathinfo.indexOf('?'); - if(idx>=0) { - qp=pathinfo.substring(idx+1); - pathinfo=pathinfo.substring(0,idx); + private class ParsePath { + private final String path; + private final int query; + private final int queryEnd; + private final int pound; + private final String queryParams; + + public ParsePath(final String origPath) { + path = origPath; + if(origPath==null) { + query=queryEnd=pound=-1; + queryParams=null; } else { - qp=queryParams; + query = origPath.indexOf('?'); + pound = origPath.indexOf('#'); + queryEnd = pound>=0?pound:path.length(); + if(oneCallQueryParams==null) { + if(query>=0) { + queryParams = path.substring(query+1,queryEnd); + } else { + queryParams=null; + } + } else { + if(query>=0) { + queryParams = oneCallQueryParams + '&' + path.substring(query+1,queryEnd); + } else { + queryParams = oneCallQueryParams; + } + oneCallQueryParams = null; + } + } + } + + public String path() { + if(query>=0) { + if(pound>=0) { + return path.substring(pound+1); + } + return path.substring(0,query); + } else if(pound>=0) { + return path.substring(0,pound); + } else { + return path; + } + } + + public String query() { + return queryParams; + } + + public String frag() { + if(pound>=0) { + return path.substring(pound+1); + } else { + return null; } } - return qp; } public String toString() { return uri.toString(); } - /** - * @param queryParams the queryParams to set - * @return - */ - public Rcli setQueryParams(String queryParams) { - this.queryParams = queryParams; - return this; - } - - - /** - * @param fragment the fragment to set - * @return - */ - public Rcli setFragment(String fragment) { - this.fragment = fragment; - return this; - } - public URI getURI() { return uri; } + public void setQueryParams(final String queryParams) { + oneCallQueryParams=queryParams; + } + } \ No newline at end of file diff --git a/cadi/client/src/main/java/org/onap/aaf/cadi/locator/SingleEndpointLocator.java b/cadi/client/src/main/java/org/onap/aaf/cadi/locator/SingleEndpointLocator.java new file mode 100644 index 00000000..b0c830f6 --- /dev/null +++ b/cadi/client/src/main/java/org/onap/aaf/cadi/locator/SingleEndpointLocator.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.cadi.locator; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.onap.aaf.cadi.Locator; +import org.onap.aaf.cadi.LocatorException; + +public class SingleEndpointLocator implements Locator { + private final URI uri; + private final static Item item = new Item() {}; + + public SingleEndpointLocator(final URI uri) { + this.uri = uri; + } + + public SingleEndpointLocator(final String endpoint) throws URISyntaxException { + this.uri = new URI(endpoint); + } + + @Override + public URI get(Item item) throws LocatorException { + return uri; + } + + @Override + public boolean hasItems() { + return true; + } + + @Override + public void invalidate(Item item) throws LocatorException { + // Endpoints cannot be invalidated + } + + @Override + public Item best() throws LocatorException { + return item; + } + + @Override + public Item first() throws LocatorException { + return item; + } + + @Override + public Item next(Item inItem) throws LocatorException { + // only one item + return null; + } + + @Override + public boolean refresh() { + // Never refreshed + return true; + } + + @Override + public void destroy() { + // Nothing to do here + } +} diff --git a/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Rcli.java b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Rcli.java index f957878b..886c5d84 100644 --- a/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Rcli.java +++ b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Rcli.java @@ -21,22 +21,10 @@ package org.onap.aaf.cadi.client.test; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; -import static org.hamcrest.CoreMatchers.*; -import org.junit.*; -import org.mockito.*; - -import org.onap.aaf.cadi.CadiException; -import org.onap.aaf.cadi.SecuritySetter; -import org.onap.aaf.cadi.client.EClient; -import org.onap.aaf.cadi.client.Future; -import org.onap.aaf.cadi.client.Rcli; -import org.onap.aaf.misc.env.APIException; -import org.onap.aaf.misc.env.Data; -import org.onap.aaf.misc.env.Data.TYPE; -import org.onap.aaf.misc.rosetta.env.RosettaDF; -import org.onap.aaf.misc.rosetta.env.RosettaData; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -50,6 +38,21 @@ import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.SecuritySetter; +import org.onap.aaf.cadi.client.EClient; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Data.TYPE; +import org.onap.aaf.misc.rosetta.env.RosettaDF; +import org.onap.aaf.misc.rosetta.env.RosettaData; + public class JU_Rcli { @Mock RosettaDF dfMock; @@ -61,8 +64,6 @@ public class JU_Rcli { private final static String uriString = "example.com"; private final static String apiVersion = "v1.0"; - private final static String fragment = "framgent"; - private final static String queryParams = "queryParams"; private final static String contentType = "contentType"; private static URI uri; @@ -224,9 +225,6 @@ public class JU_Rcli { rcli.apiVersion(null); assertThat(rcli.typeString(HttpURLConnection.class), is("application/HttpURLConnection+xml")); - rcli.setFragment(fragment); - rcli.setQueryParams(queryParams); - rcliClone = rcli.forUser(null); assertThat(rcliClone.toString(), is(uriString)); } diff --git a/cadi/oauth-enduser/src/main/java/org/onap/aaf/cadi/enduser/ClientFactory.java b/cadi/oauth-enduser/src/main/java/org/onap/aaf/cadi/enduser/ClientFactory.java new file mode 100644 index 00000000..50eaa759 --- /dev/null +++ b/cadi/oauth-enduser/src/main/java/org/onap/aaf/cadi/enduser/ClientFactory.java @@ -0,0 +1,56 @@ +/** + * ============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.enduser; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.GeneralSecurityException; + +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.oauth.TokenClientFactory; +import org.onap.aaf.misc.env.APIException; + +public class ClientFactory { + private final TokenClientFactory tcf; + public ClientFactory(final PropAccess access) throws APIException, CadiException { + try { + tcf = TokenClientFactory.instance(access); + } catch (GeneralSecurityException | IOException e) { + throw new CadiException(e); + } + } + + public ClientFactory(String[] args) throws APIException, CadiException { + this(new PropAccess(args)); + } + + public SimpleRESTClient simpleRESTClient(final String endpoint, final String ... scopes) throws URISyntaxException, LocatorException, CadiException, APIException { + return new SimpleRESTClient(tcf, Config.AAF_OAUTH2_TOKEN_URL, endpoint, scopes); + } + + public Access getAccess() { + return tcf.access; + } +} diff --git a/cadi/oauth-enduser/src/main/java/org/onap/aaf/cadi/enduser/SimpleRESTClient.java b/cadi/oauth-enduser/src/main/java/org/onap/aaf/cadi/enduser/SimpleRESTClient.java new file mode 100644 index 00000000..9535ad64 --- /dev/null +++ b/cadi/oauth-enduser/src/main/java/org/onap/aaf/cadi/enduser/SimpleRESTClient.java @@ -0,0 +1,133 @@ +/** + * ============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.enduser; + +import java.io.IOException; +import java.net.ConnectException; +import java.security.Principal; + +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Result; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.oauth.TimedToken; +import org.onap.aaf.cadi.oauth.TokenClient; +import org.onap.aaf.cadi.oauth.TokenClientFactory; +import org.onap.aaf.cadi.oauth.TzClient; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.APIException; + +public class SimpleRESTClient { + private static final String[] EMPTY = new String[0]; + private final TokenClient tokenClient; + private final TzClient restClient; + private int callTimeout; + private String client_id; + private String app; + private String chain; + private Headers headers = new Headers() { + @Override + public String[] headers() { + return EMPTY; + }}; + + public SimpleRESTClient(final TokenClientFactory tcf, final String tokenURL, final String endpoint, final String[] scope) throws CadiException, LocatorException, APIException { + callTimeout = Integer.parseInt(tcf.access.getProperty(Config.AAF_CALL_TIMEOUT,Config.AAF_CALL_TIMEOUT_DEF)); + tokenClient = tcf.newClient(tokenURL); + Result rtt = tokenClient.getToken(scope); + if(rtt.isOK()) { + restClient = tcf.newTzClient(endpoint); + + if((client_id = tcf.access.getProperty(Config.AAF_APPID, null))==null) { + if((client_id = tcf.access.getProperty(Config.CADI_ALIAS, null))==null) { + throw new CadiException(Config.AAF_APPID + " or " + Config.CADI_ALIAS + " needs to be defined"); + } + } + try { + restClient.setToken(client_id,rtt.value); + } catch (IOException e) { + throw new CadiException(e); + } + } else { + throw new CadiException(rtt.error); + } + } + + public SimpleRESTClient timeout(int newTimeout) { + callTimeout = newTimeout; + return this; + } + + //Format:::[:AS][,::]* + public SimpleRESTClient as(Principal principal) { + if(principal==null) { + chain = null; + } else { + if(principal instanceof TaggedPrincipal) { + TaggedPrincipal tp = (TaggedPrincipal)principal; + chain = tp.getName() + ':' + (app==null?"":app) + ':' + tp.tag() + ":AS"; + } else { + chain = principal.getName() + (app==null?"":':'+app); + } + } + return this; + } + + public String get(final String path) throws CadiException, LocatorException, APIException { + return get(path,"application/json"); + } + + public String get(final String path, final String accepts) throws CadiException, LocatorException, APIException { + return restClient.best(new Retryable() { + @Override + public String code(Rcli client) throws CadiException, ConnectException, APIException { + Future future = client.read(path,accepts, headers()); + if(future.get(callTimeout)) { + return future.value; + } else { + throw new APIException(future.code() + future.body()); + } + } + }); + } + + public interface Headers { + String[] headers(); + } + + public String[] headers() { + if(chain==null) { + return headers.headers(); + } else { + String[] strs = headers.headers(); + String[] rv = new String[strs.length+2]; + rv[0]=Config.CADI_USER_CHAIN; + rv[1]=chain; + for(int i = 0;i rtt = tc.getToken(ns,"org.onap.test"); - - // Note: you can clear a Token's Disk/Memory presence by - // 1) removing the Token from the "token/outgoing" directory on the O/S - // 2) programmatically by calling "clearToken" with exact params as "getToken", when it has the same credentials set - // tc.clearToken("org.onap.aaf","org.onap.test"); - - // Result Object can be queried for success - if(rtt.isOK()) { - TimedToken token = rtt.value; - print(token); // Take a look at what's in a Token - - // Use this Token in your client calls with "Tokenized Client" (TzClient) - // These should NOT be used cross thread. - TzClient helloClient = tcf.newTzClient(endServicesURL); - helloClient.setToken(client_id, token); - - // This client call style, "best" call with "Retryable" inner class covers finding an available Service - // (when Multi-services exist) for the best service, based (currently) on distance. - // - // the "Generic" in Type gives a Return Value for the Code, which you can set on the "best" method - // Note that variables used in the inner class from this part of the code must be "final", see "CALL_TIMEOUT" - String rv = helloClient.best(new Retryable() { - @Override - public String code(Rcli client) throws CadiException, ConnectException, APIException { - Future future = client.read("hello","text/plain"); - // The "future" calling method allows you to do other processing, such as call more than one backend - // client before picking up the result - // If "get" matches the HTTP Code for the method (i.e. read HTTP Return value is 200), then - if(future.get(CALL_TIMEOUT)) { - // Client Returned expected value - return future.value; - } else { - throw new APIException(future.code() + future.body()); - } - } - }); - - // You want to do something with returned value. Here, we say "hello" - System.out.printf("\nPositive Response from Hello: %s\n",rv); - - - ////////////////////////////////////////////////////////////////////// - // Scenario 2: - // As a Service, read Introspection information as proof of Authenticated Authorization - ////////////////////////////////////////////////////////////////////// - // CADI Framework (i.e. CadiFilter) works with the Introspection to drive the J2EE interfaces ( - // i.e. if(isUserInRole("ns.perm|instance|action")) {... - // - // Here, however, is a way to introspect via Java - // - // now, call Introspect (making sure right URLs are set in properties) - // We need a Different Introspect TokenClient, because different Endpoint (and usually different Services) - TokenClient tci = tcf.newClient(tokenIntrospectURL); - tci.client_creds(client_id, client_secret); - Result is = tci.introspect(token.getAccessToken()); - if(is.isOK()) { - // Note that AAF will add JSON set of Permissions as part of "Content:", legitimate extension of OAuth Structure - print(is.value); // do something with Introspect Object - } else { - access.printf(Level.ERROR, "Unable to introspect OAuth Token %s: %d %s\n", - token.getAccessToken(),rtt.code,rtt.error); - } - } else { - access.printf(Level.ERROR, "Unable to obtain OAuth Token: %d %s\n",rtt.code,rtt.error); - } - - } catch (CadiException | LocatorException | APIException | IOException e) { - e.printStackTrace(); - } - } - - ///////////////////////////////////////////////////////////// - // Examples of Object Access - ///////////////////////////////////////////////////////////// - private static void print(Token t) { - GregorianCalendar exp_date = new GregorianCalendar(); - exp_date.add(GregorianCalendar.SECOND, t.getExpiresIn()); - System.out.printf("Access Token\n\tToken:\t\t%s\n\tToken Type:\t%s\n\tExpires In:\t%d (%s)\n\tScope:\t\t%s\n\tRefresh Token:\t%s\n", - t.getAccessToken(), - t.getTokenType(), - t.getExpiresIn(), - Chrono.timeStamp(new Date(System.currentTimeMillis()+(t.getExpiresIn()*1000))), - t.getScope(), - t.getRefreshToken()); - } - - private static void print(Introspect ti) { - if(ti==null || ti.getClientId()==null) { - System.out.println("Empty Introspect"); - return; - } - Date exp = new Date(ti.getExp()*1000); // seconds - System.out.printf("Introspect\n" - + "\tAccessToken:\t%s\n" - + "\tClient-id:\t%s\n" - + "\tClient Type:\t%s\n" - + "\tActive: \t%s\n" - + "\tUserName:\t%s\n" - + "\tExpires: \t%d (%s)\n" - + "\tScope:\t\t%s\n" - + "\tContent:\t%s\n", - ti.getAccessToken(), - ti.getClientId(), - ti.getClientType(), - ti.isActive()?Boolean.TRUE.toString():Boolean.FALSE.toString(), - ti.getUsername(), - ti.getExp(), - Chrono.timeStamp(exp), - ti.getScope(), - ti.getContent()==null?"":ti.getContent()); - - System.out.println(); - } - -} diff --git a/cadi/oauth-enduser/src/test/java/com/att/cadi/enduser/OnapClientExample.java b/cadi/oauth-enduser/src/test/java/com/att/cadi/enduser/OnapClientExample.java deleted file mode 100644 index ca1bb948..00000000 --- a/cadi/oauth-enduser/src/test/java/com/att/cadi/enduser/OnapClientExample.java +++ /dev/null @@ -1,210 +0,0 @@ -/** - * ============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 com.att.cadi.enduser; - -import java.io.IOException; -import java.net.ConnectException; -import java.security.GeneralSecurityException; -import java.util.Date; -import java.util.GregorianCalendar; - -import org.onap.aaf.cadi.Access.Level; -import org.onap.aaf.cadi.CadiException; -import org.onap.aaf.cadi.LocatorException; -import org.onap.aaf.cadi.PropAccess; -import org.onap.aaf.cadi.client.Future; -import org.onap.aaf.cadi.client.Rcli; -import org.onap.aaf.cadi.client.Result; -import org.onap.aaf.cadi.client.Retryable; -import org.onap.aaf.cadi.config.Config; -import org.onap.aaf.cadi.oauth.TimedToken; -import org.onap.aaf.cadi.oauth.TokenClient; -import org.onap.aaf.cadi.oauth.TokenClientFactory; -import org.onap.aaf.cadi.oauth.TzClient; -import org.onap.aaf.cadi.util.FQI; -import org.onap.aaf.misc.env.APIException; -import org.onap.aaf.misc.env.util.Chrono; - -import aafoauth.v2_0.Introspect; -import aafoauth.v2_0.Token; - - -public class OnapClientExample { - private static TokenClientFactory tcf; - private static PropAccess access; - - public final static void main(final String args[]) { - // These Objects are expected to be Long-Lived... Construct once - - // Property Access - // This method will allow you to set "cadi_prop_files" (or any other property) on Command line - access = new PropAccess(args); - - // access = PropAccess(); - // Note: This style will load "cadi_prop_files" from VM Args - - // Token aware Client Factory - try { - tcf = TokenClientFactory.instance(access); - } catch (APIException | GeneralSecurityException | IOException | CadiException e1) { - access.log(e1, "Unable to setup OAuth Client Factory, Fail Fast"); - System.exit(1); - } - - final int CALL_TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CALL_TIMEOUT,Config.AAF_CALL_TIMEOUT_DEF)); - - try { - ////////////////////////////////////////////////////////////////////// - // Scenario 1: - // Get and use an OAuth Client, which understands Token Management - ////////////////////////////////////////////////////////////////////// - // Create a Token Client, that gets its tokens from expected OAuth Server - // In this example, it is AAF, but it can be the Alternate OAuth - - TokenClient tc = tcf.newClient(Config.AAF_OAUTH2_TOKEN_URL); // can set your own timeout here (url, timeoutMilliseconds) - - // Here's a trick to get the namespace out of a Fully Qualified AAF Identity (your MechID) - String ns = FQI.reverseDomain(tc.client_id()); - System.out.printf("\nNote: The AAF Namespace of FQI (Fully Qualified Identity) %s is %s\n\n",tc.client_id(), ns); - - // Now, we can get a Token. Note: for "scope", use AAF Namespaces to get AAF Permissions embedded in - // Note: getToken checks if Token is expired, if so, then refreshes before handing back. - Result rtt = tc.getToken(ns,"org.onap.test"); // get multiple scopes - - // Note: you can clear a Token's Disk/Memory presence by - // 1) removing the Token from the "token/outgoing" directory on the O/S - // 2) programmatically by calling "clearToken" with exact params as "getToken", when it has the same credentials set - // tc.clearToken("org.onap.aaf","org.onap.test"); - - // Result Object can be queried for success - if(rtt.isOK()) { - TimedToken token = rtt.value; - print(token); // Take a look at what's in a Token - - // Use this Token in your client calls with "Tokenized Client" (TzClient) - // These should NOT be used cross thread. - // Get Hello Service URL... roll your own in your own world. - final String endServicesURL = access.getProperty(Config.AAF_OAUTH2_HELLO_URL, - "https://AAF_LOCATE_URL/AAF_NS.hello/2.0"); - - - TzClient helloClient = tcf.newTzClient(endServicesURL); - helloClient.setToken(tc.client_id(), token); - - // This client call style, "best" call with "Retryable" inner class covers finding an available Service - // (when Multi-services exist) for the best service, based (currently) on distance. - // - // the "Generic" in Type gives a Return Value for the Code, which you can set on the "best" method - // Note that variables used in the inner class from this part of the code must be "final", see "CALL_TIMEOUT" - String rv = helloClient.best(new Retryable() { - @Override - public String code(Rcli client) throws CadiException, ConnectException, APIException { - Future future = client.read("hello","text/plain"); - // The "future" calling method allows you to do other processing, such as call more than one backend - // client before picking up the result - // If "get" matches the HTTP Code for the method (i.e. read HTTP Return value is 200), then - if(future.get(CALL_TIMEOUT)) { - // Client Returned expected value - return future.value; - } else { - throw new APIException(future.code() + future.body()); - } - } - }); - - // You want to do something with returned value. Here, we say "hello" - System.out.printf("\nPositive Response from Hello: %s\n",rv); - - - ////////////////////////////////////////////////////////////////////// - // Scenario 2: - // As a Service, read Introspection information as proof of Authenticated Authorization - ////////////////////////////////////////////////////////////////////// - // CADI Framework (i.e. CadiFilter) works with the Introspection to drive the J2EE interfaces ( - // i.e. if(isUserInRole("ns.perm|instance|action")) {... - // - // Here, however, is a way to introspect via Java - // - // now, call Introspect (making sure right URLs are set in properties) - // We need a Different Introspect TokenClient, because different Endpoint (and usually different Services) - TokenClient tci = tcf.newClient(Config.AAF_OAUTH2_INTROSPECT_URL); - Result is = tci.introspect(token.getAccessToken()); - if(is.isOK()) { - // Note that AAF will add JSON set of Permissions as part of "Content:", legitimate extension of OAuth Structure - print(is.value); // do something with Introspect Object - } else { - access.printf(Level.ERROR, "Unable to introspect OAuth Token %s: %d %s\n", - token.getAccessToken(),rtt.code,rtt.error); - } - } else { - access.printf(Level.ERROR, "Unable to obtain OAuth Token: %d %s\n",rtt.code,rtt.error); - } - - } catch (CadiException | LocatorException | APIException | IOException e) { - e.printStackTrace(); - } - } - - ///////////////////////////////////////////////////////////// - // Examples of Object Access - ///////////////////////////////////////////////////////////// - private static void print(Token t) { - GregorianCalendar exp_date = new GregorianCalendar(); - exp_date.add(GregorianCalendar.SECOND, t.getExpiresIn()); - System.out.printf("Access Token\n\tToken:\t\t%s\n\tToken Type:\t%s\n\tExpires In:\t%d (%s)\n\tScope:\t\t%s\n\tRefresh Token:\t%s\n", - t.getAccessToken(), - t.getTokenType(), - t.getExpiresIn(), - Chrono.timeStamp(new Date(System.currentTimeMillis()+(t.getExpiresIn()*1000))), - t.getScope(), - t.getRefreshToken()); - } - - private static void print(Introspect ti) { - if(ti==null || ti.getClientId()==null) { - System.out.println("Empty Introspect"); - return; - } - Date exp = new Date(ti.getExp()*1000); // seconds - System.out.printf("Introspect\n" - + "\tAccessToken:\t%s\n" - + "\tClient-id:\t%s\n" - + "\tClient Type:\t%s\n" - + "\tActive: \t%s\n" - + "\tUserName:\t%s\n" - + "\tExpires: \t%d (%s)\n" - + "\tScope:\t\t%s\n" - + "\tContent:\t%s\n", - ti.getAccessToken(), - ti.getClientId(), - ti.getClientType(), - ti.isActive()?Boolean.TRUE.toString():Boolean.FALSE.toString(), - ti.getUsername(), - ti.getExp(), - Chrono.timeStamp(exp), - ti.getScope(), - ti.getContent()==null?"":ti.getContent()); - - System.out.println(); - } - -} diff --git a/cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/OAuthExample.java b/cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/OAuthExample.java new file mode 100644 index 00000000..39e7b5b6 --- /dev/null +++ b/cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/OAuthExample.java @@ -0,0 +1,238 @@ +/** + * ============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.enduser.test; + +import java.io.IOException; +import java.net.ConnectException; +import java.security.GeneralSecurityException; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Result; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.oauth.TimedToken; +import org.onap.aaf.cadi.oauth.TokenClient; +import org.onap.aaf.cadi.oauth.TokenClientFactory; +import org.onap.aaf.cadi.oauth.TzClient; +import org.onap.aaf.cadi.util.FQI; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import aafoauth.v2_0.Introspect; +import aafoauth.v2_0.Token; + + +public class OAuthExample { + private static TokenClientFactory tcf; + private static PropAccess access; + + public final static void main(final String args[]) { + // These Objects are expected to be Long-Lived... Construct once + + // Property Access + // This method will allow you to set "cadi_prop_files" (or any other property) on Command line + access = new PropAccess(args); + + // access = PropAccess(); + // Note: This style will load "cadi_prop_files" from VM Args + + // Token aware Client Factory + try { + tcf = TokenClientFactory.instance(access); + } catch (APIException | GeneralSecurityException | IOException | CadiException e1) { + access.log(e1, "Unable to setup OAuth Client Factory, Fail Fast"); + System.exit(1); + } + + + // Obtain Endpoints for OAuth2 from Properties. Expected is "cadi.properties" file, pointed to by "cadi_prop_files" + String tokenServiceURL = access.getProperty(Config.AAF_OAUTH2_TOKEN_URL, + "https://AAF_LOCATE_URL/AAF_NS.token/2.0"); // Default to AAF + String tokenIntrospectURL = access.getProperty(Config.AAF_OAUTH2_INTROSPECT_URL, + "https://AAF_LOCATE_URL/AAF_NS.introspect/2.0"); // Default to AAF); + // Get Hello Service + final String endServicesURL = access.getProperty(Config.AAF_OAUTH2_HELLO_URL, + "https://AAF_LOCATE_URL/AAF_NS.hello/2.0"); + + final int CALL_TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CALL_TIMEOUT,Config.AAF_CALL_TIMEOUT_DEF)); + + try { + ////////////////////////////////////////////////////////////////////// + // Scenario 1: + // Get and use an OAuth Client, which understands Token Management + ////////////////////////////////////////////////////////////////////// + // Create a Token Client, that gets its tokens from expected OAuth Server + // In this example, it is AAF, but it can be the Alternate OAuth + + TokenClient tc = tcf.newClient(tokenServiceURL); // can set your own timeout here (url, timeoutMilliseconds) + // Set your Application (MicroService, whatever) Credentials here + // These are how your Application is known, particularly to the OAuth Server. + // If AAF Token server, then its just the same as your other AAF MechID creds + // If it is the Alternate OAUTH, you'll need THOSE credentials. See that tool's Onboarding procedures. + String client_id = access.getProperty(Config.AAF_APPID); + if(client_id==null) { + // For AAF, client_id CAN be Certificate. This is not necessarily true elsewhere + client_id = access.getProperty(Config.CADI_ALIAS); + } + String client_secret = access.getProperty(Config.AAF_APPPASS); + tc.client_creds(client_id, client_secret); + + // If you are working with Credentials the End User, set username/password as appropriate to the OAuth Server + // tc.password(end_user_id, end_user_password); + // IMPORTANT: + // if you are setting client Credentials, you MAY NOT reuse this Client mid-transaction. You CAN reuse after setting + // tc.clearEndUser(); + // You may want to see "Pooled Client" example, using special CADI utility + + // With AAF, the Scopes you put in are the AAF Namespaces you want access to. Your Token will contain the + // AAF Permissions of the Namespaces (you can put in more than one), the user name (or client_id if no user_name), + // is allowed to see. + + // Here's a trick to get the namespace out of a Fully Qualified AAF Identity (your MechID) + String ns = FQI.reverseDomain(client_id); + System.out.printf("\nNote: The AAF Namespace of FQI (Fully Qualified Identity) %s is %s\n\n",client_id, ns); + + // Now, we can get a Token. Note: for "scope", use AAF Namespaces to get AAF Permissions embedded in + // Note: getToken checks if Token is expired, if so, then refreshes before handing back. + Result rtt = tc.getToken(ns,"org.onap.test"); + + // Note: you can clear a Token's Disk/Memory presence by + // 1) removing the Token from the "token/outgoing" directory on the O/S + // 2) programmatically by calling "clearToken" with exact params as "getToken", when it has the same credentials set + // tc.clearToken("org.onap.aaf","org.onap.test"); + + // Result Object can be queried for success + if(rtt.isOK()) { + TimedToken token = rtt.value; + print(token); // Take a look at what's in a Token + + // Use this Token in your client calls with "Tokenized Client" (TzClient) + // These should NOT be used cross thread. + TzClient helloClient = tcf.newTzClient(endServicesURL); + helloClient.setToken(client_id, token); + + // This client call style, "best" call with "Retryable" inner class covers finding an available Service + // (when Multi-services exist) for the best service, based (currently) on distance. + // + // the "Generic" in Type gives a Return Value for the Code, which you can set on the "best" method + // Note that variables used in the inner class from this part of the code must be "final", see "CALL_TIMEOUT" + String rv = helloClient.best(new Retryable() { + @Override + public String code(Rcli client) throws CadiException, ConnectException, APIException { + Future future = client.read("hello","text/plain"); + // The "future" calling method allows you to do other processing, such as call more than one backend + // client before picking up the result + // If "get" matches the HTTP Code for the method (i.e. read HTTP Return value is 200), then + if(future.get(CALL_TIMEOUT)) { + // Client Returned expected value + return future.value; + } else { + throw new APIException(future.code() + future.body()); + } + } + }); + + // You want to do something with returned value. Here, we say "hello" + System.out.printf("\nPositive Response from Hello: %s\n",rv); + + + ////////////////////////////////////////////////////////////////////// + // Scenario 2: + // As a Service, read Introspection information as proof of Authenticated Authorization + ////////////////////////////////////////////////////////////////////// + // CADI Framework (i.e. CadiFilter) works with the Introspection to drive the J2EE interfaces ( + // i.e. if(isUserInRole("ns.perm|instance|action")) {... + // + // Here, however, is a way to introspect via Java + // + // now, call Introspect (making sure right URLs are set in properties) + // We need a Different Introspect TokenClient, because different Endpoint (and usually different Services) + TokenClient tci = tcf.newClient(tokenIntrospectURL); + tci.client_creds(client_id, client_secret); + Result is = tci.introspect(token.getAccessToken()); + if(is.isOK()) { + // Note that AAF will add JSON set of Permissions as part of "Content:", legitimate extension of OAuth Structure + print(is.value); // do something with Introspect Object + } else { + access.printf(Level.ERROR, "Unable to introspect OAuth Token %s: %d %s\n", + token.getAccessToken(),rtt.code,rtt.error); + } + } else { + access.printf(Level.ERROR, "Unable to obtain OAuth Token: %d %s\n",rtt.code,rtt.error); + } + + } catch (CadiException | LocatorException | APIException | IOException e) { + e.printStackTrace(); + } + } + + ///////////////////////////////////////////////////////////// + // Examples of Object Access + ///////////////////////////////////////////////////////////// + private static void print(Token t) { + GregorianCalendar exp_date = new GregorianCalendar(); + exp_date.add(GregorianCalendar.SECOND, t.getExpiresIn()); + System.out.printf("Access Token\n\tToken:\t\t%s\n\tToken Type:\t%s\n\tExpires In:\t%d (%s)\n\tScope:\t\t%s\n\tRefresh Token:\t%s\n", + t.getAccessToken(), + t.getTokenType(), + t.getExpiresIn(), + Chrono.timeStamp(new Date(System.currentTimeMillis()+(t.getExpiresIn()*1000))), + t.getScope(), + t.getRefreshToken()); + } + + private static void print(Introspect ti) { + if(ti==null || ti.getClientId()==null) { + System.out.println("Empty Introspect"); + return; + } + Date exp = new Date(ti.getExp()*1000); // seconds + System.out.printf("Introspect\n" + + "\tAccessToken:\t%s\n" + + "\tClient-id:\t%s\n" + + "\tClient Type:\t%s\n" + + "\tActive: \t%s\n" + + "\tUserName:\t%s\n" + + "\tExpires: \t%d (%s)\n" + + "\tScope:\t\t%s\n" + + "\tContent:\t%s\n", + ti.getAccessToken(), + ti.getClientId(), + ti.getClientType(), + ti.isActive()?Boolean.TRUE.toString():Boolean.FALSE.toString(), + ti.getUsername(), + ti.getExp(), + Chrono.timeStamp(exp), + ti.getScope(), + ti.getContent()==null?"":ti.getContent()); + + System.out.println(); + } + +} diff --git a/cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/OnapClientExample.java b/cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/OnapClientExample.java new file mode 100644 index 00000000..441be4d2 --- /dev/null +++ b/cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/OnapClientExample.java @@ -0,0 +1,210 @@ +/** + * ============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.enduser.test; + +import java.io.IOException; +import java.net.ConnectException; +import java.security.GeneralSecurityException; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Result; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.oauth.TimedToken; +import org.onap.aaf.cadi.oauth.TokenClient; +import org.onap.aaf.cadi.oauth.TokenClientFactory; +import org.onap.aaf.cadi.oauth.TzClient; +import org.onap.aaf.cadi.util.FQI; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import aafoauth.v2_0.Introspect; +import aafoauth.v2_0.Token; + + +public class OnapClientExample { + private static TokenClientFactory tcf; + private static PropAccess access; + + public final static void main(final String args[]) { + // These Objects are expected to be Long-Lived... Construct once + + // Property Access + // This method will allow you to set "cadi_prop_files" (or any other property) on Command line + access = new PropAccess(args); + + // access = PropAccess(); + // Note: This style will load "cadi_prop_files" from VM Args + + // Token aware Client Factory + try { + tcf = TokenClientFactory.instance(access); + } catch (APIException | GeneralSecurityException | IOException | CadiException e1) { + access.log(e1, "Unable to setup OAuth Client Factory, Fail Fast"); + System.exit(1); + } + + final int CALL_TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CALL_TIMEOUT,Config.AAF_CALL_TIMEOUT_DEF)); + + try { + ////////////////////////////////////////////////////////////////////// + // Scenario 1: + // Get and use an OAuth Client, which understands Token Management + ////////////////////////////////////////////////////////////////////// + // Create a Token Client, that gets its tokens from expected OAuth Server + // In this example, it is AAF, but it can be the Alternate OAuth + + TokenClient tc = tcf.newClient(Config.AAF_OAUTH2_TOKEN_URL); // can set your own timeout here (url, timeoutMilliseconds) + + // Here's a trick to get the namespace out of a Fully Qualified AAF Identity (your MechID) + String ns = FQI.reverseDomain(tc.client_id()); + System.out.printf("\nNote: The AAF Namespace of FQI (Fully Qualified Identity) %s is %s\n\n",tc.client_id(), ns); + + // Now, we can get a Token. Note: for "scope", use AAF Namespaces to get AAF Permissions embedded in + // Note: getToken checks if Token is expired, if so, then refreshes before handing back. + Result rtt = tc.getToken(ns,"org.onap.test"); // get multiple scopes + + // Note: you can clear a Token's Disk/Memory presence by + // 1) removing the Token from the "token/outgoing" directory on the O/S + // 2) programmatically by calling "clearToken" with exact params as "getToken", when it has the same credentials set + // tc.clearToken("org.onap.aaf","org.onap.test"); + + // Result Object can be queried for success + if(rtt.isOK()) { + TimedToken token = rtt.value; + print(token); // Take a look at what's in a Token + + // Use this Token in your client calls with "Tokenized Client" (TzClient) + // These should NOT be used cross thread. + // Get Hello Service URL... roll your own in your own world. + final String endServicesURL = access.getProperty(Config.AAF_OAUTH2_HELLO_URL, + "https://AAF_LOCATE_URL/AAF_NS.hello/2.0"); + + + TzClient helloClient = tcf.newTzClient(endServicesURL); + helloClient.setToken(tc.client_id(), token); + + // This client call style, "best" call with "Retryable" inner class covers finding an available Service + // (when Multi-services exist) for the best service, based (currently) on distance. + // + // the "Generic" in Type gives a Return Value for the Code, which you can set on the "best" method + // Note that variables used in the inner class from this part of the code must be "final", see "CALL_TIMEOUT" + String rv = helloClient.best(new Retryable() { + @Override + public String code(Rcli client) throws CadiException, ConnectException, APIException { + Future future = client.read("hello","text/plain"); + // The "future" calling method allows you to do other processing, such as call more than one backend + // client before picking up the result + // If "get" matches the HTTP Code for the method (i.e. read HTTP Return value is 200), then + if(future.get(CALL_TIMEOUT)) { + // Client Returned expected value + return future.value; + } else { + throw new APIException(future.code() + future.body()); + } + } + }); + + // You want to do something with returned value. Here, we say "hello" + System.out.printf("\nPositive Response from Hello: %s\n",rv); + + + ////////////////////////////////////////////////////////////////////// + // Scenario 2: + // As a Service, read Introspection information as proof of Authenticated Authorization + ////////////////////////////////////////////////////////////////////// + // CADI Framework (i.e. CadiFilter) works with the Introspection to drive the J2EE interfaces ( + // i.e. if(isUserInRole("ns.perm|instance|action")) {... + // + // Here, however, is a way to introspect via Java + // + // now, call Introspect (making sure right URLs are set in properties) + // We need a Different Introspect TokenClient, because different Endpoint (and usually different Services) + TokenClient tci = tcf.newClient(Config.AAF_OAUTH2_INTROSPECT_URL); + Result is = tci.introspect(token.getAccessToken()); + if(is.isOK()) { + // Note that AAF will add JSON set of Permissions as part of "Content:", legitimate extension of OAuth Structure + print(is.value); // do something with Introspect Object + } else { + access.printf(Level.ERROR, "Unable to introspect OAuth Token %s: %d %s\n", + token.getAccessToken(),rtt.code,rtt.error); + } + } else { + access.printf(Level.ERROR, "Unable to obtain OAuth Token: %d %s\n",rtt.code,rtt.error); + } + + } catch (CadiException | LocatorException | APIException | IOException e) { + e.printStackTrace(); + } + } + + ///////////////////////////////////////////////////////////// + // Examples of Object Access + ///////////////////////////////////////////////////////////// + private static void print(Token t) { + GregorianCalendar exp_date = new GregorianCalendar(); + exp_date.add(GregorianCalendar.SECOND, t.getExpiresIn()); + System.out.printf("Access Token\n\tToken:\t\t%s\n\tToken Type:\t%s\n\tExpires In:\t%d (%s)\n\tScope:\t\t%s\n\tRefresh Token:\t%s\n", + t.getAccessToken(), + t.getTokenType(), + t.getExpiresIn(), + Chrono.timeStamp(new Date(System.currentTimeMillis()+(t.getExpiresIn()*1000))), + t.getScope(), + t.getRefreshToken()); + } + + private static void print(Introspect ti) { + if(ti==null || ti.getClientId()==null) { + System.out.println("Empty Introspect"); + return; + } + Date exp = new Date(ti.getExp()*1000); // seconds + System.out.printf("Introspect\n" + + "\tAccessToken:\t%s\n" + + "\tClient-id:\t%s\n" + + "\tClient Type:\t%s\n" + + "\tActive: \t%s\n" + + "\tUserName:\t%s\n" + + "\tExpires: \t%d (%s)\n" + + "\tScope:\t\t%s\n" + + "\tContent:\t%s\n", + ti.getAccessToken(), + ti.getClientId(), + ti.getClientType(), + ti.isActive()?Boolean.TRUE.toString():Boolean.FALSE.toString(), + ti.getUsername(), + ti.getExp(), + Chrono.timeStamp(exp), + ti.getScope(), + ti.getContent()==null?"":ti.getContent()); + + System.out.println(); + } + +} diff --git a/cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/SimpleRestClientExample.java b/cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/SimpleRestClientExample.java new file mode 100644 index 00000000..7340618f --- /dev/null +++ b/cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/SimpleRestClientExample.java @@ -0,0 +1,91 @@ +/** + * ============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.enduser.test; + +import java.net.URISyntaxException; +import java.security.Principal; + +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.enduser.ClientFactory; +import org.onap.aaf.cadi.enduser.SimpleRESTClient; +import org.onap.aaf.misc.env.APIException; + + +public class SimpleRestClientExample { + public final static void main(final String args[]) throws URISyntaxException, LocatorException { + try { + // Note: Expect ClientFactory to be long-lived... do NOT create more than once. + ClientFactory cf = new ClientFactory(args); + + + String urlString = cf.getAccess().getProperty("myurl", null); + if(urlString==null) { + System.out.println("Note: In your startup, add \"myurl=https://:8130\" to command line\n\t" + + "OR\n\t" + + " add -Dmyurl=https://:8130 to VM Args\n\t" + + "where \"aaf hello machine\" is an aaf Installation you know about."); + } else { + SimpleRESTClient restClient = cf.simpleRESTClient(urlString,"org.osaaf.aaf"); + + // Make some calls + + // Call with no Queries + String rv = restClient.get("resthello"); + System.out.println(rv); + + // Call with Queries + rv = restClient.get("resthello?perm=org.osaaf.people|*|read"); + System.out.println(rv); + + // Call setting ID from principal coming from Trans + // Pretend Transaction + HRequest req = new HRequest("demo@people.osaaf.org"); // Pretend Trans has Jonathan as Identity + + rv = restClient.as(req.userPrincipal()).get("resthello?perm=org.osaaf.people|*|read"); + System.out.println(rv); + } + } catch (CadiException | APIException e) { + e.printStackTrace(); + } + } + + private static class HRequest { + + public HRequest(String fqi) { + name = fqi; + } + protected final String name; + + // fake out HttpServletRequest, only for get Principal + public Principal userPrincipal() { + return new Principal() { + + @Override + public String getName() { + return name; + } + + }; + } + } +} -- cgit 1.2.3-korg