Create ResponseBuilder class
[dmaap/dbcapi.git] / src / main / java / org / onap / dmaap / dbcapi / service / ApiService.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.onap.dmaap
4  * ================================================================================
5  * Copyright (C) 2017 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 package org.onap.dmaap.dbcapi.service;
22
23 import static com.att.eelf.configuration.Configuration.MDC_BEGIN_TIMESTAMP;
24 import static com.att.eelf.configuration.Configuration.MDC_ELAPSED_TIME;
25 import static com.att.eelf.configuration.Configuration.MDC_END_TIMESTAMP;
26 import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
27 import static com.att.eelf.configuration.Configuration.MDC_PARTNER_NAME;
28 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
29
30 import java.text.SimpleDateFormat;
31 import java.util.Date;
32 import java.util.TimeZone;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
35
36 import javax.ws.rs.core.Response.Status;
37 import javax.xml.bind.DatatypeConverter;
38
39 import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
40 import org.onap.dmaap.dbcapi.authentication.ApiPolicy;
41 import org.onap.dmaap.dbcapi.authentication.AuthenticationErrorException;
42 import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
43 import org.onap.dmaap.dbcapi.model.ApiError;
44 import org.onap.dmaap.dbcapi.model.Dmaap;
45 import org.onap.dmaap.dbcapi.resources.RequiredFieldException;
46 import org.onap.dmaap.dbcapi.util.DmaapConfig;
47 import org.onap.dmaap.dbcapi.util.RandomString;
48 import org.slf4j.MDC;
49
50 public class ApiService extends BaseLoggingClass {
51         private class StopWatch {
52                 private long clock = 0;
53                 private long elapsed = 0;
54                 
55
56                 
57                 public StopWatch() {
58                         clock = 0;
59                         elapsed = 0;
60                 }
61                 
62                 public void reset() {
63                         clock = System.currentTimeMillis();
64                         elapsed = 0;
65                 }
66                 public void stop() {
67                         Long stopTime = System.currentTimeMillis();
68                         elapsed +=  stopTime - clock;
69                         clock = 0;
70                         MDC.put( MDC_END_TIMESTAMP, isoFormatter.format(new Date(stopTime)));
71                         MDC.put( MDC_ELAPSED_TIME, String.valueOf(elapsed));
72                 }
73                 public void start() {
74                         if ( clock != 0 ) {
75                                 //not stopped
76                                 return;
77                         }
78                         clock = System.currentTimeMillis();     
79                         MDC.put( MDC_BEGIN_TIMESTAMP, isoFormatter.format(new Date(clock)));
80                 }
81                 private long getElapsed() {
82                         return elapsed;
83                 }
84         }
85
86          private String apiNamespace;
87
88          private String uri;
89          private String uriPath;
90          private String method;
91          private String authorization;
92          private String requestId;
93         private ApiError err;
94         private StopWatch stopwatch;
95         private ApiPolicy apiPolicy;
96         
97         public static final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
98     public final static TimeZone utc = TimeZone.getTimeZone("UTC");
99     public final static SimpleDateFormat isoFormatter = new SimpleDateFormat(ISO_FORMAT);
100         
101     static {
102         isoFormatter.setTimeZone(utc);
103     }   
104         public ApiService() {
105
106                 stopwatch = new StopWatch();
107                 stopwatch.start();
108                 err = new ApiError();
109                 requestId = (new RandomString(10)).nextString();
110                 
111                 if (apiNamespace == null) {
112                         DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
113                         apiNamespace = p.getProperty("ApiNamespace", "org.openecomp.dmaapBC.api");
114                         logger.info( "config param usePE has been deprecated.  Use ApiPermission.Class property instead.");
115                 }
116                 apiPolicy = new ApiPolicy();
117
118                 logger.info(  "apiNamespace=" + apiNamespace);  
119         }
120
121         public ApiService setAuth( String auth ) {
122                 this.authorization = auth;
123                 logger.info( "setAuth:  authorization={} ",  authorization);
124                 return this;
125         }
126         private void setServiceName(){
127                 String svcRequest = new String( this.method + " " + this.uriPath );
128         MDC.put(MDC_SERVICE_NAME, svcRequest );
129         }
130         public ApiService setHttpMethod( String httpMethod ) {
131                 this.method = httpMethod;
132                 logger.info( "setHttpMethod: method={} ", method);
133                 setServiceName();
134                 return this;
135         }
136         public ApiService setUriPath( String uriPath ) {
137                 this.uriPath = uriPath;
138                 this.uri = setUriFromPath( uriPath );
139                 logger.info( "setUriPath: uriPath={} uri={}", uriPath, uri);
140                 setServiceName();
141                 return this;
142         }
143         private String setUriFromPath( String uriPath ) {
144                 int ch = uriPath.indexOf("/");
145                 if ( ch > 0 ) {
146                         return( (String) uriPath.subSequence(0, ch ) );
147                 } else {
148                         return uriPath;
149                 }
150         }       
151         
152         public ApiError getErr() {
153                 return err;
154         }
155
156
157         public void setErr(ApiError err) {
158                 this.err = err;
159         }
160
161
162         // test for presence of a required field
163         public void required( String name, Object val, String expr ) throws RequiredFieldException {
164                 err.setCode(0);
165                 if ( val == null  ) {
166                         err.setCode(Status.BAD_REQUEST.getStatusCode());
167                         err.setMessage("missing required field");
168                         err.setFields( name );  
169                         throw new RequiredFieldException();
170                 }
171                 if ( expr != null && ! expr.isEmpty() ) {
172                         Pattern pattern = Pattern.compile(expr);
173                         Matcher matcher = pattern.matcher((CharSequence) val);
174                         if ( ! matcher.find() ) {
175                                 err.setCode(Status.BAD_REQUEST.getStatusCode());
176                                 err.setMessage( "value '" + val + "' violates regexp check '" + expr + "'");
177                                 err.setFields( name );
178                                 throw new RequiredFieldException();
179                         }
180                 }
181         }
182         
183         // utility to serialize ApiErr object
184         public String toString() {
185                 return String.format( "code=%d msg=%s fields=%s", err.getCode(), err.getMessage(), err.getFields() );
186         }
187
188
189         public void setCode(int statusCode) {
190                 err.setCode(statusCode);
191         }
192
193
194         public void setMessage(String string) {
195                 err.setMessage(string);
196         }
197
198
199         public void setFields(String string) {
200                 err.setFields(string);
201         }
202         
203         public void checkAuthorization( String auth, String uriPath, String httpMethod ) throws AuthenticationErrorException, Exception {
204                 authorization = auth;
205                 setUriFromPath( uriPath );
206                 method = httpMethod;
207                 
208                 checkAuthorization();
209         }
210
211         
212         public void checkAuthorization() throws AuthenticationErrorException, Exception {
213
214                 MDC.put(MDC_KEY_REQUEST_ID, requestId); 
215         
216                 logger.info("request: uri={} method={} auth={}", uri, method, authorization );
217
218                 if ( uri == null || uri.isEmpty()) {
219                         String errmsg = "No URI value provided ";
220                         err.setMessage(errmsg);
221                         logger.info( errmsg );
222                         throw new AuthenticationErrorException( );                      
223                 }
224                 if ( method == null || method.isEmpty()) {
225                         String errmsg = "No method value provided ";
226                         err.setMessage(errmsg);
227                         logger.info( errmsg );
228                         throw new AuthenticationErrorException( );                      
229                 }
230                 DmaapService dmaapService = new DmaapService();
231                 Dmaap dmaap = dmaapService.getDmaap();
232                 String env =            dmaap.getDmaapName();
233                 
234                 // special case during bootstrap of app when DMaaP environment may not be set.
235                 // this allows us to authorize certain APIs used for initialization during this window.
236                 if ( env == null || env.isEmpty() ) {
237                         env = "boot";
238                 }
239                 if ( ! apiPolicy.getUseAuthClass() ) return;  // skip authorization if not enabled
240                 if ( authorization == null || authorization.isEmpty()) {
241                         String errmsg = "No basic authorization value provided ";
242                         err.setMessage(errmsg);
243                         logger.info( errmsg );
244                         throw new AuthenticationErrorException( );
245                 }
246                 String credentials = authorization.substring("Basic".length()).trim();
247         byte[] decoded = DatatypeConverter.parseBase64Binary(credentials);
248         String decodedString = new String(decoded);
249         String[] actualCredentials = decodedString.split(":");
250         String ID = actualCredentials[0];
251         String Password = actualCredentials[1];
252         MDC.put(MDC_PARTNER_NAME, ID);
253                 try {
254                         
255                         DmaapPerm p = new DmaapPerm( apiNamespace + "." + uri, env, method );
256                         apiPolicy.check( ID, Password, p);
257                 } catch ( AuthenticationErrorException ae ) {
258                         String errmsg =  "User " + ID + " failed authentication/authorization for " + apiNamespace + "." + uriPath + " " + env + " " + method;
259                         logger.info( errmsg );
260                         err.setMessage(errmsg);
261                         throw ae;
262
263                 } 
264                 
265
266         }
267         public String getRequestId() {
268                 return requestId;
269         }
270         public ApiService setRequestId(String requestId) {
271                 if ( requestId == null || requestId.isEmpty()) {        
272                         this.requestId = (new RandomString(10)).nextString();
273                         logger.warn( "X-ECOMP-RequestID not set in HTTP Header.  Setting RequestId value to: " + this.requestId );
274                 } else {
275                         this.requestId = requestId;
276                 }
277                 MDC.put(MDC_KEY_REQUEST_ID, this.requestId); 
278                 return this;
279         }
280 }