X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=auth%2Fauth-gui%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Faaf%2Fauth%2Fgui%2Fpages%2FApiDocs.java;h=b171695e5b22c4868f0483bf9cf78847a04f7ee4;hb=1296352d8eafee57f982a4342ad79ada4aa56d28;hp=95aa0525a8fc8552fe7bbc939e6df9f4efa0dc52;hpb=f85f0889b3b0e5e9694afab4dd01a4a97a155188;p=aaf%2Fauthz.git diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiDocs.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiDocs.java index 95aa0525..b171695e 100644 --- a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiDocs.java +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiDocs.java @@ -7,9 +7,9 @@ * 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. @@ -25,7 +25,6 @@ import java.io.IOException; import java.net.ConnectException; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import org.onap.aaf.auth.env.AuthzTrans; import org.onap.aaf.auth.gui.AAF_GUI; @@ -43,6 +42,7 @@ import org.onap.aaf.cadi.Symm; import org.onap.aaf.cadi.client.Future; import org.onap.aaf.cadi.client.Rcli; import org.onap.aaf.cadi.client.Retryable; +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; @@ -53,279 +53,276 @@ import aaf.v2_0.Api; import aaf.v2_0.Api.Route; public class ApiDocs extends Page { - // Package on purpose - private static final String HREF = "/gui/api"; - private static final String NAME = "AAF RESTful API"; - private static final String fields[] = {}; - private static final String ERROR_LINK = "JSON " - + "XML "; - - - public ApiDocs(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { - super(gui.env,NAME,HREF, fields, - new BreadCrumbs(breadcrumbs), - new Preamble(gui), - new Table("AAF API Reference",gui.env.newTransNoAvg(),new Model(), "class=std") - ); - } - - private static class Preamble extends NamedCode { - - private static final String I = "i"; - private final String fs_url; - - public Preamble(AAF_GUI gui) { - super(false, "preamble"); - fs_url = gui.access.getProperty("fs_url", ""); - } - - @Override - public void code(Cache cache, HTMLGen xgen) throws APIException, IOException { - xgen.leaf(HTMLGen.H1).text("AAF 2.0 RESTful interface").end() - .hr(); - xgen.leaf(HTMLGen.H2).text("Accessing RESTful").end(); - xgen.incr(HTMLGen.UL) - .leaf(HTMLGen.LI).text("AAF RESTful service is secured by the following:").end() - .incr(HTMLGen.UL) - .leaf(HTMLGen.LI).text("The Client must utilize HTTP/S. Non Secure HTTP is not acceptable").end() - .leaf(HTMLGen.LI).text("The Client MUST supply an Identity validated by one of the following mechanisms").end() - .incr(HTMLGen.UL) - .leaf(HTMLGen.LI).text("BASIC AUTH protocol using Organization Registered AppID, provisioned in AAF").end() - .leaf(HTMLGen.LI).text("(Near Future) Application level Certificate").end() - .end() - .end() - .leaf(HTMLGen.LI).text("Responses").end() - .incr(HTMLGen.UL) - .leaf(HTMLGen.LI).text("Each API Entity listed shows what structure will be accepted by service (ContentType) " - + "or responded with by service (Accept). Therefore, use these in making your call. Critical for PUT/POST.").end() - .leaf(HTMLGen.LI).text("Each API call may respond with JSON or XML. Choose the ContentType/Accept that has " - + "+json after the type for JSON or +xml after the Type for XML").end() - .leaf(HTMLGen.LI).text("XSDs for Versions").end() - .incr(HTMLGen.UL) - .leaf(HTMLGen.LI).leaf(HTMLGen.A,"href=" + fs_url + "/aaf_2_0.xsd").text("API 2.0").end().end() - .end() - .leaf(HTMLGen.LI).text("AAF can support multiple Versions of the API. Choose the ContentType/Accept that has " - + "the appropriate version=?.?").end() - .leaf(HTMLGen.LI).text("All Errors coming from AAF return AT&T Standard Error Message as a String: " + ERROR_LINK - + " (does not apply to errors from Container)").end() - .end() - .leaf(HTMLGen.LI).text("Character Restrictions").end() - .incr(HTMLGen.UL) - .leaf(HTMLGen.LI).text("Character Restrictions must depend on the Enforcement Point used").end() - .leaf(HTMLGen.LI).text("Most AAF usage will be AAF Enforcement Point Characters for Instance and Action are:") - .br().br().leaf(I).text("a-zA-Z0-9,.()_-=%").end() - .br().br().text("For Instance, you may declare a multi-dimensional key with : (colon) separator, example:").end() - .br().leaf(I).text(":myCluster:myKeyspace").end() - .br().br().text("The * (asterix) may be used as a wild-card by itself or within the multi-dimensional key, example:") - .br().leaf(I).text(":myCluster:*").end() - .br().br().text("The % (percent) character can be used as an Escape Character. Applications can use % followed by 2 hexadecimal " - + "digits to cover odd keys. It is their code, however, which must translate.") - .br().br().text("The = (equals) is allowed so that Applications can pass Base64 encodations of binary keys").end() - .leaf(HTMLGen.LI).text("Ask for a Consultation on how these are typically used, or, if your tool is the only Enforcement Point, if set may be expanded").end() - .end() - .end(); - /* - - The Content is defined in the AAF XSD - TODO Add aaf.xsd”; - Character Restrictions - - URLs impose restrictions on characters which have specific meanings. This means you cannot have these characters in the Field Content you send - “#” is a “Fragment URL”, or anchor. Content after this Character is not sent. AAF cannot do anything about this… don’t use it. - “?=&”. These are used to delineate Parameters. - “/“ is used to separate fields - */ - } - - }; - /** - * Implement the Table Content for Permissions by User - * - * @author Jonathan - * - */ - private static class Model extends TableData { - public static final String[] HEADERS = new String[] {"Entity","Method","Path Info","Description"}; - private static final TextCell BLANK = new TextCell(""); - - @Override - public String[] headers() { - return HEADERS; - } - - - @Override - public Cells get(final AuthzTrans trans, final AAF_GUI gui) { - final ArrayList ns = new ArrayList<>(); - final ArrayList perms = new ArrayList<>(); - final ArrayList roles = new ArrayList<>(); - final ArrayList user = new ArrayList<>(); - final ArrayList aafOnly = new ArrayList<>(); - final ArrayList rv = new ArrayList<>(); - - - final TimeTaken tt = trans.start("AAF APIs",Env.REMOTE); - try { - gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { - @SuppressWarnings("unchecked") - @Override - public Void code(Rcli client) throws CadiException, ConnectException, APIException { - Future fa = client.read("/api",gui.getDF(Api.class)); - if(fa.get(5000)) { - tt.done(); - TimeTaken tt2 = trans.start("Load Data", Env.SUB); - try { - if(fa.value!=null)for(Route r : fa.value.getRoute()) { - String path = r.getPath(); - // Build info - StringBuilder desc = new StringBuilder(); - - desc.append("

"); - desc.append(r.getDesc()); - - if(r.getComments().size()>0) { - for(String ct : r.getComments()) { - desc.append("

"); - desc.append(ct); - } - } - - if(r.getParam().size()>0) { - desc.append("


Parameters

"); - - for(String params : r.getParam()) { - String param[] = params.split("\\s*\\|\\s*"); - desc.append("

"); - desc.append(param[0]); - desc.append(" : "); - desc.append(param[1]); - if("true".equalsIgnoreCase(param[2])) { - desc.append(" (Required)"); - } - } - } - - - if(r.getExpected()!=0) { - desc.append("

Expected HTTP Code

"); - desc.append(r.getExpected()); - } - - if(r.getExplicitErr().size()!=0) { - desc.append("

Explicit HTTP Error Codes

"); - boolean first = true; - for(int ee : r.getExplicitErr()) { - if(first) { - first = false; - } else { - desc.append(", "); - } - desc.append(ee); - } - } - - desc.append("

"); - desc.append("GET".equals(r.getMeth())?"Accept:":"ContentType:"); - Collections.sort(r.getContentType()); - if(r.getPath().startsWith("/authn/basicAuth")) { - desc.append("

text/plain"); - } - for(String ct : r.getContentType()) { - if(ct.contains("version=2")) { - desc.append("

"); - desc.append(ct); - desc.append(""); - } - } - desc.append("

"); - - - AbsCell[] sa = new AbsCell[] { - null, - new TextCell(r.getMeth(),"class=right"), - new TextCell(r.getPath()), - new TextCell(desc.toString()), - }; - - if(path.startsWith("/authz/perm")) { - sa[0] = perms.size()==0?new TextCell("PERMISSION"):BLANK; - perms.add(sa); - } else if(path.startsWith("/authz/role") || path.startsWith("/authz/userRole")) { - sa[0] = roles.size()==0?new TextCell("ROLE"):BLANK; - roles.add(sa); - } else if(path.startsWith("/authz/ns")) { - sa[0] = ns.size()==0?new TextCell("NAMESPACE"):BLANK; - ns.add(sa); - } else if(path.startsWith("/authn/basicAuth") - || path.startsWith("/authn/validate") - || path.startsWith("/authz/user")) { - sa[0] = user.size()==0?new TextCell("USER"):BLANK; - user.add(sa); - } else { - sa[0] = aafOnly.size()==0?new TextCell("AAF ONLY"):BLANK; - aafOnly.add(sa); - } - } - //TODO if(trans.fish(p)) - prepare(rv, perms,roles,ns,user); - } finally { - tt2.done(); - } - } else { - gui.writeError(trans, fa, null, 0); - } - return null; - } - }); - } catch (Exception e) { - trans.error().log(e.getMessage()); - } finally { - tt.done(); - } - - return new Cells(rv,null); - } - - @SuppressWarnings("unchecked") - private void prepare(ArrayList rv, ArrayList ... all) { - AbsCell lead; - AbsCell[] row; - for(ArrayList al : all) { - if(al.size()>1) { - row = al.get(0); - lead = row[0]; - row[0]=BLANK; - al.get(0).clone()[0]=BLANK; - Collections.sort(al, new Comparator() { - @Override - public int compare(AbsCell[] ca1, AbsCell[] ca2) { - int meth = ((TextCell)ca1[2]).name.compareTo( - ((TextCell)ca2[2]).name); - if(meth == 0) { - return (HttpMethods.valueOf(((TextCell)ca1[1]).name).compareTo( - HttpMethods.valueOf(((TextCell)ca2[1]).name))); - } else { - return meth; - } - } - }); - // set new first row - al.get(0)[0]=lead; - - rv.addAll(al); - } - } - } - } + // Package on purpose + private static final String HREF = "/gui/api"; + private static final String NAME = "AAF RESTful API"; + private static final String fields[] = {}; + private static final String ERROR_LINK = "JSON " + + "XML "; + + + public ApiDocs(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, fields, + new BreadCrumbs(breadcrumbs), + new Preamble(gui), + new Table("AAF API Reference",gui.env.newTransNoAvg(),new Model(), "class=std") + ); + } + + private static class Preamble extends NamedCode { + + private static final String I = "i"; + private final String fsUrl; + + public Preamble(AAF_GUI gui) { + super(false, "preamble"); + fsUrl = gui.access.getProperty(Config.AAF_URL_FS, "/theme"); + } + + @Override + public void code(Cache cache, HTMLGen xgen) throws APIException, IOException { + xgen.leaf(HTMLGen.H1).text("AAF 2.0 RESTful interface").end() + .hr(); + xgen.leaf(HTMLGen.H2).text("Accessing RESTful").end(); + xgen.incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("AAF RESTful service is secured by the following:").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("The Client must utilize HTTP/S. Non Secure HTTP is not acceptable").end() + .leaf(HTMLGen.LI).text("The Client MUST supply an Identity validated by one of the following mechanisms").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("BASIC AUTH protocol using Organization Registered AppID, provisioned in AAF").end() + .leaf(HTMLGen.LI).text("(Near Future) Application level Certificate").end() + .end() + .end() + .leaf(HTMLGen.LI).text("Responses").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("Each API Entity listed shows what structure will be accepted by service (ContentType) " + + "or responded with by service (Accept). Therefore, use these in making your call. Critical for PUT/POST.").end() + .leaf(HTMLGen.LI).text("Each API call may respond with JSON or XML. Choose the ContentType/Accept that has " + + "+json after the type for JSON or +xml after the Type for XML").end() + .leaf(HTMLGen.LI).text("XSDs for Versions").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).leaf(HTMLGen.A,"href=" + fsUrl + "/aaf_2_0.xsd").text("API 2.0").end().end() + .end() + .leaf(HTMLGen.LI).text("AAF can support multiple Versions of the API. Choose the ContentType/Accept that has " + + "the appropriate version=?.?").end() + .leaf(HTMLGen.LI).text("All Errors coming from AAF return AT&T Standard Error Message as a String: " + ERROR_LINK + + " (does not apply to errors from Container)").end() + .end() + .leaf(HTMLGen.LI).text("Character Restrictions").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("Character Restrictions must depend on the Enforcement Point used").end() + .leaf(HTMLGen.LI).text("Most AAF usage will be AAF Enforcement Point Characters for Instance and Action are:") + .br().br().leaf(I).text("a-zA-Z0-9,.()_-=%").end() + .br().br().text("For Instance, you may declare a multi-dimensional key with : (colon) separator, example:").end() + .br().leaf(I).text(":myCluster:myKeyspace").end() + .br().br().text("The * (asterix) may be used as a wild-card by itself or within the multi-dimensional key, example:") + .br().leaf(I).text(":myCluster:*").end() + .br().br().text("The % (percent) character can be used as an Escape Character. Applications can use % followed by 2 hexadecimal " + + "digits to cover odd keys. It is their code, however, which must translate.") + .br().br().text("The = (equals) is allowed so that Applications can pass Base64 encodations of binary keys").end() + .leaf(HTMLGen.LI).text("Ask for a Consultation on how these are typically used, or, if your tool is the only Enforcement Point, if set may be expanded").end() + .end() + .end(); + /* + + The Content is defined in the AAF XSD - TODO Add aaf.xsd”; + Character Restrictions + + URLs impose restrictions on characters which have specific meanings. This means you cannot have these characters in the Field Content you send + “#” is a “Fragment URL”, or anchor. Content after this Character is not sent. AAF cannot do anything about this… don’t use it. + “?=&”. These are used to delineate Parameters. + “/“ is used to separate fields + */ + } + + }; + /** + * Implement the Table Content for Permissions by User + * + * @author Jonathan + * + */ + private static class Model extends TableData { + public static final String[] HEADERS = new String[] {"Entity","Method","Path Info","Description"}; + private static final TextCell BLANK = new TextCell(""); + + @Override + public String[] headers() { + return HEADERS; + } + + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final ArrayList ns = new ArrayList<>(); + final ArrayList perms = new ArrayList<>(); + final ArrayList roles = new ArrayList<>(); + final ArrayList user = new ArrayList<>(); + final ArrayList aafOnly = new ArrayList<>(); + final ArrayList rv = new ArrayList<>(); + + + final TimeTaken tt = trans.start("AAF APIs",Env.REMOTE); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @SuppressWarnings("unchecked") + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fa = client.read("/api",gui.getDF(Api.class)); + if (fa.get(5000)) { + tt.done(); + TimeTaken tt2 = trans.start("Load Data", Env.SUB); + try { + if (fa.value!=null)for (Route r : fa.value.getRoute()) { + String path = r.getPath(); + // Build info + StringBuilder desc = new StringBuilder(); + + desc.append("

"); + desc.append(r.getDesc()); + + if (!r.getComments().isEmpty()) { + for (String ct : r.getComments()) { + desc.append("

"); + desc.append(ct); + } + } + + if (!r.getParam().isEmpty()) { + desc.append("


Parameters

"); + + for (String params : r.getParam()) { + String param[] = params.split("\\s*\\|\\s*"); + desc.append("

"); + desc.append(param[0]); + desc.append(" : "); + desc.append(param[1]); + if ("true".equalsIgnoreCase(param[2])) { + desc.append(" (Required)"); + } + } + } + + + if (r.getExpected()!=0) { + desc.append("

Expected HTTP Code

"); + desc.append(r.getExpected()); + } + + if (!r.getExplicitErr().isEmpty()) { + desc.append("

Explicit HTTP Error Codes

"); + boolean first = true; + for (int ee : r.getExplicitErr()) { + if (first) { + first = false; + } else { + desc.append(", "); + } + desc.append(ee); + } + } + + desc.append("

"); + desc.append("GET".equals(r.getMeth())?"Accept:":"ContentType:"); + Collections.sort(r.getContentType()); + if (r.getPath().startsWith("/authn/basicAuth")) { + desc.append("

text/plain"); + } + for (String ct : r.getContentType()) { + if (ct.contains("version=2")) { + desc.append("

"); + desc.append(ct); + desc.append(""); + } + } + desc.append("

"); + + + AbsCell[] sa = new AbsCell[] { + null, + new TextCell(r.getMeth(),"class=right"), + new TextCell(r.getPath()), + new TextCell(desc.toString()), + }; + + if (path.startsWith("/authz/perm")) { + sa[0] = perms.isEmpty()?new TextCell("PERMISSION"):BLANK; + perms.add(sa); + } else if (path.startsWith("/authz/role") || path.startsWith("/authz/userRole")) { + sa[0] = roles.isEmpty()?new TextCell("ROLE"):BLANK; + roles.add(sa); + } else if (path.startsWith("/authz/ns")) { + sa[0] = ns.isEmpty()?new TextCell("NAMESPACE"):BLANK; + ns.add(sa); + } else if (path.startsWith("/authn/basicAuth") + || path.startsWith("/authn/validate") + || path.startsWith("/authz/user")) { + sa[0] = user.isEmpty()?new TextCell("USER"):BLANK; + user.add(sa); + } else { + sa[0] = aafOnly.isEmpty()?new TextCell("AAF ONLY"):BLANK; + aafOnly.add(sa); + } + } + //TODO if (trans.fish(p)) + prepare(rv, perms,roles,ns,user); + } finally { + tt2.done(); + } + } else { + gui.writeError(trans, fa, null, 0); + } + return null; + } + }); + } catch (Exception e) { + trans.error().log(e.getMessage()); + } finally { + tt.done(); + } + + return new Cells(rv,null); + } + + @SuppressWarnings("unchecked") + private void prepare(ArrayList rv, ArrayList ... all) { + AbsCell lead; + AbsCell[] row; + for (ArrayList al : all) { + if (al.size()>1) { + row = al.get(0); + lead = row[0]; + row[0]=BLANK; + al.get(0).clone()[0]=BLANK; + Collections.sort(al, (ca1, ca2) -> { + int meth = ((TextCell)ca1[2]).name.compareTo( + ((TextCell)ca2[2]).name); + if (meth == 0) { + return (HttpMethods.valueOf(((TextCell)ca1[1]).name).compareTo( + HttpMethods.valueOf(((TextCell)ca2[1]).name))); + } else { + return meth; + } + }); + // set new first row + al.get(0)[0]=lead; + + rv.addAll(al); + } + } + } + } }