2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.dmaap.dbcapi.service;
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;
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;
36 import javax.ws.rs.core.Response.Status;
37 import javax.xml.bind.DatatypeConverter;
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;
50 public class ApiService extends BaseLoggingClass {
51 private class StopWatch {
52 private long clock = 0;
53 private long elapsed = 0;
63 clock = System.currentTimeMillis();
67 Long stopTime = System.currentTimeMillis();
68 elapsed += stopTime - clock;
70 MDC.put( MDC_END_TIMESTAMP, isoFormatter.format(new Date(stopTime)));
71 MDC.put( MDC_ELAPSED_TIME, String.valueOf(elapsed));
78 clock = System.currentTimeMillis();
79 MDC.put( MDC_BEGIN_TIMESTAMP, isoFormatter.format(new Date(clock)));
81 private long getElapsed() {
86 private String apiNamespace;
89 private String uriPath;
90 private String method;
91 private String authorization;
92 private String requestId;
94 private StopWatch stopwatch;
95 private ApiPolicy apiPolicy;
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);
102 isoFormatter.setTimeZone(utc);
104 public ApiService() {
106 stopwatch = new StopWatch();
108 err = new ApiError();
109 requestId = (new RandomString(10)).nextString();
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.");
116 apiPolicy = new ApiPolicy();
118 logger.info( "apiNamespace=" + apiNamespace);
121 public ApiService setAuth( String auth ) {
122 this.authorization = auth;
123 logger.info( "setAuth: authorization={} ", authorization);
126 private void setServiceName(){
127 String svcRequest = new String( this.method + " " + this.uriPath );
128 MDC.put(MDC_SERVICE_NAME, svcRequest );
130 public ApiService setHttpMethod( String httpMethod ) {
131 this.method = httpMethod;
132 logger.info( "setHttpMethod: method={} ", method);
136 public ApiService setUriPath( String uriPath ) {
137 this.uriPath = uriPath;
138 this.uri = setUriFromPath( uriPath );
139 logger.info( "setUriPath: uriPath={} uri={}", uriPath, uri);
143 private String setUriFromPath( String uriPath ) {
144 int ch = uriPath.indexOf("/");
146 return( (String) uriPath.subSequence(0, ch ) );
152 public ApiError getErr() {
157 public void setErr(ApiError err) {
162 // test for presence of a required field
163 public void required( String name, Object val, String expr ) throws RequiredFieldException {
166 err.setCode(Status.BAD_REQUEST.getStatusCode());
167 err.setMessage("missing required field");
168 err.setFields( name );
169 throw new RequiredFieldException();
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();
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() );
189 public void setCode(int statusCode) {
190 err.setCode(statusCode);
194 public void setMessage(String string) {
195 err.setMessage(string);
199 public void setFields(String string) {
200 err.setFields(string);
203 public void checkAuthorization( String auth, String uriPath, String httpMethod ) throws AuthenticationErrorException, Exception {
204 authorization = auth;
205 setUriFromPath( uriPath );
208 checkAuthorization();
212 public void checkAuthorization() throws AuthenticationErrorException, Exception {
214 MDC.put(MDC_KEY_REQUEST_ID, requestId);
216 logger.info("request: uri={} method={} auth={}", uri, method, authorization );
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( );
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( );
230 DmaapService dmaapService = new DmaapService();
231 Dmaap dmaap = dmaapService.getDmaap();
232 String env = dmaap.getDmaapName();
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() ) {
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( );
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);
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);
267 public String getRequestId() {
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 );
275 this.requestId = requestId;
277 MDC.put(MDC_KEY_REQUEST_ID, this.requestId);