AT&T 2.0.19 Code drop, stage 3
[aaf/authz.git] / auth / auth-gui / src / main / java / org / onap / aaf / auth / gui / pages / ApiDocs.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.auth.gui.pages;
23
24 import java.io.IOException;
25 import java.net.ConnectException;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.Comparator;
29
30 import org.onap.aaf.auth.env.AuthzTrans;
31 import org.onap.aaf.auth.gui.AAF_GUI;
32 import org.onap.aaf.auth.gui.BreadCrumbs;
33 import org.onap.aaf.auth.gui.NamedCode;
34 import org.onap.aaf.auth.gui.Page;
35 import org.onap.aaf.auth.gui.Table;
36 import org.onap.aaf.auth.gui.Table.Cells;
37 import org.onap.aaf.auth.gui.table.AbsCell;
38 import org.onap.aaf.auth.gui.table.TableData;
39 import org.onap.aaf.auth.gui.table.TextCell;
40 import org.onap.aaf.auth.rserv.HttpMethods;
41 import org.onap.aaf.cadi.CadiException;
42 import org.onap.aaf.cadi.Symm;
43 import org.onap.aaf.cadi.client.Future;
44 import org.onap.aaf.cadi.client.Rcli;
45 import org.onap.aaf.cadi.client.Retryable;
46 import org.onap.aaf.misc.env.APIException;
47 import org.onap.aaf.misc.env.Env;
48 import org.onap.aaf.misc.env.TimeTaken;
49 import org.onap.aaf.misc.xgen.Cache;
50 import org.onap.aaf.misc.xgen.html.HTMLGen;
51
52 import aaf.v2_0.Api;
53 import aaf.v2_0.Api.Route;
54
55 public class ApiDocs extends Page {
56         // Package on purpose
57         private static final String HREF = "/gui/api";
58         private static final String NAME = "AAF RESTful API";
59         private static final String fields[] = {};
60         private static final String ERROR_LINK = "<a href=\"./example/"
61                         + "YXBwbGljYXRpb24vRXJyb3IranNvbg=="
62 //                      + Symm.base64noSplit().encode("application/Error+json") 
63                         + "\">JSON</a> "
64                         + "<a href=\"./example/"
65                         + "YXBwbGljYXRpb24vRXJyb3IreG1s"
66 //                      + Symm.base64noSplit().encode("application/Error+xml") 
67                         + "\">XML</a> ";
68
69         
70         public ApiDocs(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException {
71                 super(gui.env,NAME,HREF, fields,
72                         new BreadCrumbs(breadcrumbs),
73                         new Preamble(gui),
74                         new Table<AAF_GUI,AuthzTrans>("AAF API Reference",gui.env.newTransNoAvg(),new Model(), "class=std")
75                         );
76         }
77         
78         private static class Preamble extends NamedCode {
79
80                 private static final String I = "i";
81                 private final String fs_url;
82
83                 public Preamble(AAF_GUI gui) {
84                         super(false, "preamble");
85                         fs_url = gui.access.getProperty("fs_url", "");
86                 }
87
88                 @Override
89                 public void code(Cache<HTMLGen> cache, HTMLGen xgen) throws APIException, IOException {
90                         xgen.leaf(HTMLGen.H1).text("AAF 2.0 RESTful interface").end()
91                                 .hr();
92                         xgen.leaf(HTMLGen.H2).text("Accessing RESTful").end();
93                         xgen.incr(HTMLGen.UL)
94                                         .leaf(HTMLGen.LI).text("AAF RESTful service is secured by the following:").end()
95                                         .incr(HTMLGen.UL)
96                                                 .leaf(HTMLGen.LI).text("The Client must utilize HTTP/S. Non Secure HTTP is not acceptable").end()
97                                                 .leaf(HTMLGen.LI).text("The Client MUST supply an Identity validated by one of the following mechanisms").end()
98                                                 .incr(HTMLGen.UL)
99                                                         .leaf(HTMLGen.LI).text("Valid Global Login Cookie (CSP)").end()
100                                                         .leaf(HTMLGen.LI).text("BASIC AUTH protocol using CSO Registered MechID, provisioned in AAF").end()
101                                                         .leaf(HTMLGen.LI).text("BASIC AUTH protocol using ATTUID@csp.att.com, Global Login Password").end()
102                                                         .leaf(HTMLGen.LI).text("(Available 3rd Qtr 2015) Valid tGuard Login Cookie").end()
103                                                         .leaf(HTMLGen.LI).text("(Near Future) Application level Certificate").end()
104                                                 .end()
105                                         .end()
106                                         .leaf(HTMLGen.LI).text("Responses").end()
107                                         .incr(HTMLGen.UL)
108                                                 .leaf(HTMLGen.LI).text("Each API Entity listed shows what structure will be accepted by service (ContentType) "
109                                                                 + "or responded with by service (Accept). Therefore, use these in making your call. Critical for PUT/POST.").end()
110                                                 .leaf(HTMLGen.LI).text("Each API call may respond with JSON or XML.  Choose the ContentType/Accept that has "
111                                                                 + "+json after the type for JSON or +xml after the Type for XML").end()
112                                                 .leaf(HTMLGen.LI).text("XSDs for Versions").end()
113                                                 .incr(HTMLGen.UL)
114                                                         .leaf(HTMLGen.LI).leaf(HTMLGen.A,"href=" + fs_url + "/aaf_2_0.xsd").text("API 2.0").end().end()
115                                                 .end()
116                                                 .leaf(HTMLGen.LI).text("AAF can support multiple Versions of the API.  Choose the ContentType/Accept that has "
117                                                                 + "the appropriate version=?.?").end()
118                                                 .leaf(HTMLGen.LI).text("All Errors coming from AAF return AT&T Standard Error Message as a String: " + ERROR_LINK 
119                                                                 + " (does not apply to errors from Container)").end()
120                                         .end()
121                                         .leaf(HTMLGen.LI).text("Character Restrictions").end()
122                                         .incr(HTMLGen.UL)
123                                                 .leaf(HTMLGen.LI).text("Character Restrictions must depend on the Enforcement Point used").end()
124                                                 .leaf(HTMLGen.LI).text("Most AAF usage will be AAF Enforcement Point Characters for Instance and Action are:")
125                                                         .br().br().leaf(I).text("a-zA-Z0-9,.()_-=%").end()
126                                                         .br().br().text("For Instance, you may declare a multi-dimensional key with : (colon) separator, example:").end()
127                                                         .br().leaf(I).text(":myCluster:myKeyspace").end()
128                                                         .br().br().text("The * (asterix) may be used as a wild-card by itself or within the multi-dimensional key, example:")
129                                                         .br().leaf(I).text(":myCluster:*").end()
130                                                         .br().br().text("The % (percent) character can be used as an Escape Character. Applications can use % followed by 2 hexadecimal "
131                                                                         + "digits to cover odd keys.  It is their code, however, which must translate.")
132                                                         .br().br().text("The = (equals) is allowed so that Applications can pass Base64 encodations of binary keys").end()
133                                                 .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()
134                                         .end()
135                                 .end();
136                         /*
137                         
138                         The Content is defined in the AAF XSD - TODO Add aaf.xsd”;
139                         Character Restrictions
140
141                         URLs impose restrictions on characters which have specific meanings. This means you cannot have these characters in the Field Content you send
142                         “#” is a “Fragment URL”, or anchor. Content after this Character is not sent. AAF cannot do anything about this… don’t use it.
143                         “?=&”. These are used to delineate Parameters.
144                         “/“ is used to separate fields
145                         */
146                 }
147                 
148         };
149         /**
150          * Implement the Table Content for Permissions by User
151          * 
152          * @author Jonathan
153          *
154          */
155         private static class Model extends TableData<AAF_GUI,AuthzTrans> {
156                 public static final String[] HEADERS = new String[] {"Entity","Method","Path Info","Description"};
157                 private static final TextCell BLANK = new TextCell("");
158         
159                 @Override
160                 public String[] headers() {
161                         return HEADERS;
162                 }
163                 
164                 
165                 @Override
166                 public Cells get(final AuthzTrans trans, final AAF_GUI gui) {
167                         final ArrayList<AbsCell[]> ns = new ArrayList<AbsCell[]>();
168                         final ArrayList<AbsCell[]> perms = new ArrayList<AbsCell[]>();
169                         final ArrayList<AbsCell[]> roles = new ArrayList<AbsCell[]>();
170                         final ArrayList<AbsCell[]> user = new ArrayList<AbsCell[]>();
171                         final ArrayList<AbsCell[]> aafOnly = new ArrayList<AbsCell[]>();
172                         final ArrayList<AbsCell[]> rv = new ArrayList<AbsCell[]>();
173                         
174         
175                         final TimeTaken tt = trans.start("AAF APIs",Env.REMOTE);
176                         try {
177                                 gui.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {
178                                         @SuppressWarnings("unchecked")
179                                         @Override
180                                         public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
181                                                 Future<Api> fa = client.read("/api",gui.getDF(Api.class));
182                                                 if(fa.get(5000)) {
183                                                         tt.done();
184                                                         TimeTaken tt2 = trans.start("Load Data", Env.SUB);
185                                                         try {
186                                                                 if(fa.value!=null)for(Route r : fa.value.getRoute()) {
187                                                                         String path = r.getPath();
188                                                                         // Build info
189                                                                         StringBuilder desc = new StringBuilder();
190                         
191                                                                         desc.append("<p class=double>");
192                                                                         desc.append(r.getDesc());
193                                                                         
194                                                                         if(r.getComments().size()>0) {
195                                                                                 for(String ct : r.getComments()) {
196                                                                                         desc.append("</p><p class=api_comment>");
197                                                                                         desc.append(ct);
198                                                                                 }
199                                                                         }
200                         
201                                                                         if(r.getParam().size()>0) {
202                                                                                 desc.append("<hr><p class=api_label>Parameters</p>");
203                                                                                 
204                                                                                 for(String params : r.getParam()) {
205                                                                                         String param[] = params.split("\\s*\\|\\s*");
206                                                                                         desc.append("</p><p class=api_contentType>");
207                                                                                         desc.append(param[0]);
208                                                                                         desc.append(" : ");
209                                                                                         desc.append(param[1]);
210                                                                                         if("true".equalsIgnoreCase(param[2])) {
211                                                                                                 desc.append(" (Required)");
212                                                                                         }
213                                                                                 }
214                                                                         }
215                         
216                         
217                                                                         if(r.getExpected()!=0) {
218                                                                                 desc.append("</p><p class=api_label>Expected HTTP Code</p><p class=api_comment>");
219                                                                                 desc.append(r.getExpected());
220                                                                         } 
221                         
222                                                                         if(r.getExplicitErr().size()!=0) {
223                                                                                 desc.append("</p><p class=api_label>Explicit HTTP Error Codes</p><p class=api_comment>");
224                                                                                 boolean first = true;
225                                                                                 for(int ee : r.getExplicitErr()) {
226                                                                                         if(first) {
227                                                                                                 first = false;
228                                                                                         } else {
229                                                                                                 desc.append(", ");
230                                                                                         }
231                                                                                         desc.append(ee);
232                                                                                 }
233                                                                         }
234                         
235                                                                         desc.append("</p><p class=api_label>");
236                                                                         desc.append("GET".equals(r.getMeth())?"Accept:":"ContentType:");
237                                                                         Collections.sort(r.getContentType());
238                                                                         if(r.getPath().startsWith("/authn/basicAuth")) {
239                                                                                 desc.append("</p><p class=api_contentType>text/plain");
240                                                                         }
241                                                                         for(String ct : r.getContentType()) {
242                                                                                 if(ct.contains("version=2")) {
243                                                                                         desc.append("</p><p class=api_contentType><a href=\"./example/");
244                                                                                         try {
245                                                                                                 desc.append(Symm.base64noSplit.encode(ct));
246                                                                                         } catch (IOException e) {
247                                                                                                 throw new CadiException(e);
248                                                                                         }
249                                                                                         desc.append("\"/>");
250                                                                                         desc.append(ct);
251                                                                                         desc.append("</a>");
252                                                                                 }
253                                                                         }
254                                                                         desc.append("</p>");
255                                                                         
256                                                                         
257                                                                         AbsCell[] sa = new AbsCell[] {
258                                                                                 null,
259                                                                                 new TextCell(r.getMeth(),"class=right"),
260                                                                                 new TextCell(r.getPath()),
261                                                                                 new TextCell(desc.toString()),
262                                                                         };
263                         
264                                                                         if(path.startsWith("/authz/perm")) {
265                                                                                 sa[0] = perms.size()==0?new TextCell("PERMISSION"):BLANK;
266                                                                                 perms.add(sa);
267                                                                         } else if(path.startsWith("/authz/role") || path.startsWith("/authz/userRole")) {
268                                                                                 sa[0] = roles.size()==0?new TextCell("ROLE"):BLANK;
269                                                                                 roles.add(sa);
270                                                                         } else if(path.startsWith("/authz/ns")) {
271                                                                                 sa[0] = ns.size()==0?new TextCell("NAMESPACE"):BLANK;
272                                                                                 ns.add(sa);
273                                                                         } else if(path.startsWith("/authn/basicAuth") 
274                                                                                 || path.startsWith("/authn/validate")
275                                                                                 || path.startsWith("/authz/user")) {
276                                                                                 sa[0] = user.size()==0?new TextCell("USER"):BLANK;
277                                                                                 user.add(sa);
278                                                                         } else {
279                                                                                 sa[0] = aafOnly.size()==0?new TextCell("AAF ONLY"):BLANK;
280                                                                                 aafOnly.add(sa);
281                                                                         }
282                                                                 }
283                                                                 //TODO if(trans.fish(p))
284                                                                 prepare(rv, perms,roles,ns,user);
285                                                         } finally {
286                                                                 tt2.done();
287                                                         }
288                                                 } else {
289                                                         gui.writeError(trans, fa, null, 0);
290                                                 }
291                                                 return null;
292                                         }
293                                 });
294                         } catch (Exception e) {
295                                 trans.error().log(e.getMessage());
296                         } finally {
297                                 tt.done();
298                         }
299                         
300                         return new Cells(rv,null);
301                 }
302
303                 @SuppressWarnings("unchecked")
304                 private void prepare(ArrayList<AbsCell[]> rv, ArrayList<AbsCell[]> ... all) {
305                         AbsCell lead;
306                         AbsCell[] row;
307                         for(ArrayList<AbsCell[]> al : all) {
308                                 if(al.size()>1) {
309                                         row = al.get(0);
310                                         lead = row[0];
311                                         row[0]=BLANK;
312                                         al.get(0).clone()[0]=BLANK;
313                                         Collections.sort(al, new Comparator<AbsCell[]>() {
314                                                 @Override
315                                                 public int compare(AbsCell[] ca1, AbsCell[] ca2) {
316                                                         int meth = ((TextCell)ca1[2]).name.compareTo(
317                                                                            ((TextCell)ca2[2]).name);
318                                                         if(meth == 0) {
319                                                                 return (HttpMethods.valueOf(((TextCell)ca1[1]).name).compareTo(
320                                                                                 HttpMethods.valueOf(((TextCell)ca2[1]).name)));
321                                                         } else { 
322                                                                 return meth;
323                                                         }
324                                                 }
325                                         });
326                                         // set new first row
327                                         al.get(0)[0]=lead;
328
329                                         rv.addAll(al);
330                                 }
331                         }
332                 }
333         }
334 }