X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Forg%2Fonap%2Fdmaap%2Fdbcapi%2Fservice%2FApiService.java;fp=src%2Fmain%2Fjava%2Forg%2Fonap%2Fdmaap%2Fdbcapi%2Fservice%2FApiService.java;h=aab989d8ffa316c70895c54a330dfe2d300bfb0c;hb=a05efb7b7b3cfc77f5e3fda11e8434834829f56a;hp=0000000000000000000000000000000000000000;hpb=256e95421e478b6fe7a9af77f5681255329cab99;p=dmaap%2Fdbcapi.git 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 index 0000000..aab989d --- /dev/null +++ b/src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java @@ -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; + } +}