DMAAP-83 Initial code import
[dmaap/dbcapi.git] / src / main / java / org / onap / dmaap / dbcapi / service / ApiService.java
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java b/src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java
new file mode 100644 (file)
index 0000000..aab989d
--- /dev/null
@@ -0,0 +1,339 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 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.dmaap.dbcapi.service;
+
+import static com.att.eelf.configuration.Configuration.MDC_BEGIN_TIMESTAMP;
+import static com.att.eelf.configuration.Configuration.MDC_ELAPSED_TIME;
+import static com.att.eelf.configuration.Configuration.MDC_END_TIMESTAMP;
+import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
+import static com.att.eelf.configuration.Configuration.MDC_PARTNER_NAME;
+import static com.att.eelf.configuration.Configuration.MDC_RESPONSE_CODE;
+import static com.att.eelf.configuration.Configuration.MDC_RESPONSE_DESC;
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
+import static com.att.eelf.configuration.Configuration.MDC_STATUS_CODE;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.bind.DatatypeConverter;
+
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+import org.onap.dmaap.dbcapi.aaf.authentication.ApiPolicy;
+import org.onap.dmaap.dbcapi.aaf.authentication.AuthenticationErrorException;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.Dmaap;
+import org.onap.dmaap.dbcapi.resources.RequiredFieldException;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+import org.onap.dmaap.dbcapi.util.RandomString;
+import org.slf4j.MDC;
+
+public class ApiService extends BaseLoggingClass {
+       private class StopWatch {
+               private long clock = 0;
+               private long elapsed = 0;
+               
+
+               
+               public StopWatch() {
+                       clock = 0;
+                       elapsed = 0;
+               }
+               
+               public void reset() {
+                       clock = System.currentTimeMillis();
+                       elapsed = 0;
+               }
+               public void stop() {
+                       Long stopTime = System.currentTimeMillis();
+                       elapsed +=  stopTime - clock;
+                       clock = 0;
+                       MDC.put( MDC_END_TIMESTAMP, isoFormatter.format(new Date(stopTime)));
+                       MDC.put( MDC_ELAPSED_TIME, String.valueOf(elapsed));
+               }
+               public void start() {
+                       if ( clock != 0 ) {
+                               //not stopped
+                               return;
+                       }
+                       clock = System.currentTimeMillis();     
+                       MDC.put( MDC_BEGIN_TIMESTAMP, isoFormatter.format(new Date(clock)));
+               }
+               private long getElapsed() {
+                       return elapsed;
+               }
+       }
+
+        private String apiNamespace;
+        private boolean usePE;
+        private String uri;
+        private String uriPath;
+        private String method;
+        private String authorization;
+        private String requestId;
+       private ApiError err;
+       private StopWatch stopwatch;
+       private ApiPolicy apiPolicy;
+       
+       public static final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+    public final static TimeZone utc = TimeZone.getTimeZone("UTC");
+    public final static SimpleDateFormat isoFormatter = new SimpleDateFormat(ISO_FORMAT);
+       
+    static {
+       isoFormatter.setTimeZone(utc);
+    }  
+       public ApiService() {
+
+               stopwatch = new StopWatch();
+               stopwatch.start();
+               err = new ApiError();
+               requestId = (new RandomString(10)).nextString();
+               
+               if (apiNamespace == null) {
+                       DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+                       usePE = "true".equalsIgnoreCase(p.getProperty("UsePE", "false"));
+                       apiNamespace = p.getProperty("ApiNamespace", "org.openecomp.dmaapBC.api");
+               }
+               apiPolicy = new ApiPolicy();
+               logger.info( "usePE=" + usePE + " apiNamespace=" + apiNamespace);       
+       }
+
+       public ApiService setAuth( String auth ) {
+               this.authorization = auth;
+               logger.info( "setAuth:  authorization={} ",  authorization);
+               return this;
+       }
+       private void setServiceName(){
+               String svcRequest = new String( this.method + " " + this.uriPath );
+        MDC.put(MDC_SERVICE_NAME, svcRequest );
+       }
+       public ApiService setHttpMethod( String httpMethod ) {
+               this.method = httpMethod;
+               logger.info( "setHttpMethod: method={} ", method);
+               setServiceName();
+               return this;
+       }
+       public ApiService setUriPath( String uriPath ) {
+               this.uriPath = uriPath;
+               this.uri = setUriFromPath( uriPath );
+               logger.info( "setUriPath: uriPath={} uri={}", uriPath, uri);
+               setServiceName();
+               return this;
+       }
+       private String setUriFromPath( String uriPath ) {
+               int ch = uriPath.indexOf("/");
+               if ( ch > 0 ) {
+                       return( (String) uriPath.subSequence(0, ch ) );
+               } else {
+                       return uriPath;
+               }
+       }       
+       
+       public ApiError getErr() {
+               return err;
+       }
+
+
+       public void setErr(ApiError err) {
+               this.err = err;
+       }
+
+
+       // test for presence of a required field
+       public void required( String name, Object val, String expr ) throws RequiredFieldException {
+               if ( val == null  ) {
+                       err.setCode(Status.BAD_REQUEST.getStatusCode());
+                       err.setMessage("missing required field");
+                       err.setFields( name );  
+                       throw new RequiredFieldException();
+               }
+               if ( expr != null && ! expr.isEmpty() ) {
+                       Pattern pattern = Pattern.compile(expr);
+                       Matcher matcher = pattern.matcher((CharSequence) val);
+                       if ( ! matcher.find() ) {
+                               err.setCode(Status.BAD_REQUEST.getStatusCode());
+                               err.setMessage( "value '" + val + "' violates regexp check '" + expr + "'");
+                               err.setFields( name );
+                               throw new RequiredFieldException();
+                       }
+               }
+       }
+       
+       // utility to serialize ApiErr object
+       public String toString() {
+               return String.format( "code=%d msg=%s fields=%s", err.getCode(), err.getMessage(), err.getFields() );
+       }
+
+
+       public void setCode(int statusCode) {
+               err.setCode(statusCode);        
+       }
+
+
+       public void setMessage(String string) {
+               err.setMessage(string);
+       }
+
+
+       public void setFields(String string) {
+               err.setFields(string);
+       }
+
+       private Response  buildResponse( Object obj ) {
+               stopwatch.stop();
+               MDC.put( MDC_RESPONSE_CODE, String.valueOf(err.getCode()) );
+               
+               auditLogger.auditEvent( "" );
+               return Response.status( err.getCode())
+                               .entity(obj)
+                               .build();
+       }
+       private Response  buildSuccessResponse(Object d) {
+               MDC.put( MDC_STATUS_CODE,  "COMPLETE");
+               MDC.put( MDC_RESPONSE_DESC, "");
+               return buildResponse( d );
+       }
+       private Response  buildErrResponse() {
+       
+               MDC.put( MDC_STATUS_CODE,  "ERROR");
+               MDC.put( MDC_RESPONSE_DESC, err.getMessage());
+               
+               return buildResponse(getErr());
+       }
+       public Response success( Object d ) {
+               err.setCode(Status.OK.getStatusCode());
+               return buildSuccessResponse(d);
+                               
+       }
+       public Response success( int code, Object d ) {
+               err.setCode(code);
+               return buildSuccessResponse(d);
+       }
+
+       public Response unauthorized( String msg ) {
+               err.setCode(Status.UNAUTHORIZED.getStatusCode());
+               err.setFields( "Authorization");
+               err.setMessage( msg );
+               return buildErrResponse();
+       }
+       public Response unauthorized() {
+               err.setCode(Status.UNAUTHORIZED.getStatusCode());
+               err.setFields( "Authorization");
+               err.setMessage( "User credentials in HTTP Header field Authorization are not authorized for the requested action");
+               return buildErrResponse();
+       }
+       public Response unavailable() {
+               err.setCode(Status.SERVICE_UNAVAILABLE.getStatusCode());
+               err.setMessage( "Request is unavailable due to unexpected condition");
+               return buildErrResponse();
+       }
+       public Response notFound() {
+               err.setCode(Status.NOT_FOUND.getStatusCode());
+               err.setMessage( "Requested object not found");
+               return buildErrResponse();
+       }
+       public Response error() {
+               return buildErrResponse();
+       }
+       
+       public void checkAuthorization( String auth, String uriPath, String httpMethod ) throws AuthenticationErrorException, Exception {
+               authorization = auth;
+               setUriFromPath( uriPath );
+               method = httpMethod;
+               
+               checkAuthorization();
+       }
+
+       
+       public void checkAuthorization() throws AuthenticationErrorException, Exception {
+
+               MDC.put(MDC_KEY_REQUEST_ID, requestId); 
+       
+               logger.info("request: uri={} method={} auth={}", uri, method, authorization );
+
+               if ( uri == null || uri.isEmpty()) {
+                       String errmsg = "No URI value provided ";
+                       err.setMessage(errmsg);
+                       logger.info( errmsg );
+                       throw new AuthenticationErrorException( );                      
+               }
+               if ( method == null || method.isEmpty()) {
+                       String errmsg = "No method value provided ";
+                       err.setMessage(errmsg);
+                       logger.info( errmsg );
+                       throw new AuthenticationErrorException( );                      
+               }
+               DmaapService dmaapService = new DmaapService();
+               Dmaap dmaap = dmaapService.getDmaap();
+               String env =            dmaap.getDmaapName();
+               
+               // special case during bootstrap of app when DMaaP environment may not be set.
+               // this allows us to authorize certain APIs used for initialization during this window.
+               if ( env == null || env.isEmpty() ) {
+                       env = "boot";
+               }
+               if ( ! usePE ) return;  // skip authorization if not enabled
+               if ( authorization == null || authorization.isEmpty()) {
+                       String errmsg = "No basic authorization value provided ";
+                       err.setMessage(errmsg);
+                       logger.info( errmsg );
+                       throw new AuthenticationErrorException( );
+               }
+               String credentials = authorization.substring("Basic".length()).trim();
+        byte[] decoded = DatatypeConverter.parseBase64Binary(credentials);
+        String decodedString = new String(decoded);
+        String[] actualCredentials = decodedString.split(":");
+        String ID = actualCredentials[0];
+        String Password = actualCredentials[1];
+        MDC.put(MDC_PARTNER_NAME, ID);
+               try {
+                       
+                       DmaapPerm p = new DmaapPerm( apiNamespace + "." + uri, env, method );
+                       apiPolicy.check( ID, Password, p);
+               } catch ( AuthenticationErrorException ae ) {
+                       String errmsg =  "User " + ID + " failed authentication/authorization for " + apiNamespace + "." + uriPath + " " + env + " " + method;
+                       logger.info( errmsg );
+                       err.setMessage(errmsg);
+                       throw ae;
+
+               } 
+               
+
+       }
+       public String getRequestId() {
+               return requestId;
+       }
+       public ApiService setRequestId(String requestId) {
+               if ( requestId == null || requestId.isEmpty()) {        
+                       this.requestId = (new RandomString(10)).nextString();
+                       logger.warn( "X-ECOMP-RequestID not set in HTTP Header.  Setting RequestId value to: " + this.requestId );
+               } else {
+                       this.requestId = requestId;
+               }
+               MDC.put(MDC_KEY_REQUEST_ID, this.requestId); 
+               return this;
+       }
+}