re base code
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / filters / BasicAuthenticationFilter.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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.openecomp.sdc.be.filters;
22
23 import com.google.gson.Gson;
24 import com.google.gson.GsonBuilder;
25 import fj.data.Either;
26 import org.apache.commons.codec.binary.Base64;
27 import org.openecomp.sdc.be.components.impl.ConsumerBusinessLogic;
28 import org.openecomp.sdc.be.dao.api.ActionStatus;
29 import org.openecomp.sdc.be.impl.ComponentsUtils;
30 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
31 import org.openecomp.sdc.be.model.ConsumerDefinition;
32 import org.openecomp.sdc.common.api.Constants;
33 import org.openecomp.sdc.common.log.enums.LogLevel;
34 import org.openecomp.sdc.common.log.enums.Severity;
35 import org.openecomp.sdc.common.log.wrappers.Logger;
36 import org.openecomp.sdc.common.log.wrappers.LoggerSdcAudit;
37 import org.openecomp.sdc.exception.ResponseFormat;
38 import org.openecomp.sdc.security.Passwords;
39 import org.springframework.web.context.WebApplicationContext;
40
41 import javax.annotation.Priority;
42 import javax.servlet.ServletContext;
43 import javax.servlet.http.HttpServletRequest;
44 import javax.ws.rs.container.ContainerRequestContext;
45 import javax.ws.rs.container.ContainerRequestFilter;
46 import javax.ws.rs.core.Context;
47 import javax.ws.rs.core.Response;
48 import javax.ws.rs.core.Response.ResponseBuilder;
49 import javax.ws.rs.core.Response.Status;
50 import java.io.IOException;
51 import java.io.UnsupportedEncodingException;
52 import java.util.StringTokenizer;
53
54 @Priority(10)
55 public class BasicAuthenticationFilter implements ContainerRequestFilter {
56
57         private static LoggerSdcAudit audit = new LoggerSdcAudit(BasicAuthenticationFilter.class);
58     private static final Logger log = Logger.getLogger(BasicAuthenticationFilter.class);
59     private static final String COMPONENT_UTILS_FAILED = "Authentication Filter Failed to get component utils.";
60     private static final String CONSUMER_BL_FAILED = "Authentication Filter Failed to get consumerBL.";
61
62     @Context
63     private HttpServletRequest sr;
64
65     protected Gson gson = new GsonBuilder().setPrettyPrinting().create();
66
67     private String realm = "ASDC";
68
69
70     @Override
71     public void filter(ContainerRequestContext requestContext) throws IOException {
72
73                 audit.startLog(requestContext);
74
75         String authHeader = requestContext.getHeaderString(Constants.AUTHORIZATION_HEADER);
76         if (authHeader != null) {
77             StringTokenizer st = new StringTokenizer(authHeader);
78             String failedToRetrieveAuthErrorMsg = "Authentication Filter Failed Couldn't retrieve authentication, no basic authentication.";
79             if (st.hasMoreTokens()) {
80                 String basic = st.nextToken();
81
82                 if ("Basic".equalsIgnoreCase(basic)) {
83                     try {
84                         String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8");
85                         log.debug("Credentials: {}", credentials);
86                         checkUserCredentials(requestContext, credentials);
87                     } catch (UnsupportedEncodingException e) {
88                         log.error("Authentication Filter Failed Couldn't retrieve authentication", e);
89                         authInvalidHeaderError(requestContext);
90                     }
91                 } else {
92                                         log.error(failedToRetrieveAuthErrorMsg);
93                     authInvalidHeaderError(requestContext);
94                 }
95             } else {
96                                 log.error(failedToRetrieveAuthErrorMsg);
97                 authInvalidHeaderError(requestContext);
98             }
99
100         } else {
101                         log.error("Authentication Filter Failed no authorization header");
102             authRequiredError(requestContext);
103         }
104     }
105
106         private void checkUserCredentials(ContainerRequestContext requestContext, String credentials) {
107         int p = credentials.indexOf(':');
108         if (p != -1) {
109             String userName = credentials.substring(0, p).trim();
110             String password = credentials.substring(p + 1).trim();
111
112             ConsumerBusinessLogic consumerBL = getConsumerBusinessLogic();
113             if (consumerBL == null) {
114                                 abortWith(requestContext, CONSUMER_BL_FAILED, Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build());
115             } else {
116                 Either<ConsumerDefinition, ResponseFormat> result = consumerBL.getConsumer(userName);
117                 validatePassword(requestContext, userName, password, result);
118             }
119         } else {
120                         log.error("Authentication Filter Failed Couldn't retrieve authentication, no basic authentication.");
121             authInvalidHeaderError(requestContext);
122
123         }
124     }
125
126     private void validatePassword(ContainerRequestContext requestContext, String userName, String password, Either<ConsumerDefinition, ResponseFormat> result) {
127         if (result.isRight()) {
128             Integer status = result.right().value().getStatus();
129             if (status == Status.NOT_FOUND.getStatusCode()) {
130                 log.error("Authentication Filter Failed Couldn't find user");
131                 authUserNotFoundError(requestContext, userName);
132             } else {
133                                 abortWith(requestContext, CONSUMER_BL_FAILED, Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build());
134             }
135         } else {
136             ConsumerDefinition consumerCredentials = result.left().value();
137             if (!Passwords.isExpectedPassword(password, consumerCredentials.getConsumerSalt(), consumerCredentials.getConsumerPassword())) {
138                                 log.error("Authentication Filter Failed invalid password");
139                                 authInvalidPasswordError(requestContext, userName);
140             } else {
141                                 authSuccessful(requestContext, userName);
142             }
143         }
144     }
145
146         private void authSuccessful(ContainerRequestContext requestContext, String userName) {
147         ComponentsUtils componentUtils = getComponentsUtils();
148         if (componentUtils == null) {
149                         abortWith(requestContext, COMPONENT_UTILS_FAILED, Response.status(Status.INTERNAL_SERVER_ERROR).build());
150         }
151         componentUtils.auditAuthEvent(requestContext.getUriInfo().getPath(), userName, AuthStatus.AUTH_SUCCESS.toString(), realm);
152     }
153
154         private void authInvalidPasswordError(ContainerRequestContext requestContext, String userName) {
155         ComponentsUtils componentUtils = getComponentsUtils();
156         if (componentUtils == null) {
157                         abortWith(requestContext, COMPONENT_UTILS_FAILED, Response.status(Status.INTERNAL_SERVER_ERROR).build());
158         }
159         componentUtils.auditAuthEvent(requestContext.getUriInfo().getPath(), userName, AuthStatus.AUTH_FAILED_INVALID_PASSWORD.toString(), realm);
160         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.AUTH_FAILED);
161                 abortWith(requestContext, responseFormat.getFormattedMessage(), buildErrorResponse(responseFormat, false));
162     }
163
164     private void authUserNotFoundError(ContainerRequestContext requestContext, String userName) {
165         ComponentsUtils componentUtils = getComponentsUtils();
166         if (componentUtils == null) {
167                         abortWith(requestContext, COMPONENT_UTILS_FAILED, Response.status(Status.INTERNAL_SERVER_ERROR).build());
168         }
169         getComponentsUtils().auditAuthEvent(requestContext.getUriInfo().getPath(), userName, AuthStatus.AUTH_FAILED_USER_NOT_FOUND.toString(), realm);
170         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.AUTH_FAILED);
171                 abortWith(requestContext, responseFormat.getFormattedMessage(), buildErrorResponse(responseFormat, false));
172     }
173
174     private void authInvalidHeaderError(ContainerRequestContext requestContext) {
175         ComponentsUtils componentUtils = getComponentsUtils();
176         if (componentUtils == null) {
177                         abortWith(requestContext, COMPONENT_UTILS_FAILED, Response.status(Status.INTERNAL_SERVER_ERROR).build());
178         }
179         getComponentsUtils().auditAuthEvent(requestContext.getUriInfo().getPath(), "", AuthStatus.AUTH_FAILED_INVALID_AUTHENTICATION_HEADER.toString(), realm);
180         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.AUTH_FAILED_INVALIDE_HEADER);
181                 abortWith(requestContext, responseFormat.getFormattedMessage(), buildErrorResponse(responseFormat, false));
182     }
183
184     private void authRequiredError(ContainerRequestContext requestContext) {
185         ComponentsUtils componentUtils = getComponentsUtils();
186         if (componentUtils == null) {
187                         abortWith(requestContext, COMPONENT_UTILS_FAILED, Response.status(Status.INTERNAL_SERVER_ERROR).build());
188         }
189         getComponentsUtils().auditAuthEvent(requestContext.getUriInfo().getPath(), "", AuthStatus.AUTH_REQUIRED.toString(), realm);
190         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.AUTH_REQUIRED);
191                 abortWith(requestContext, responseFormat.getFormattedMessage(), buildErrorResponse(responseFormat, true));
192     }
193
194     private ComponentsUtils getComponentsUtils() {
195         ServletContext context = sr.getSession().getServletContext();
196         WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
197         WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
198         return webApplicationContext.getBean(ComponentsUtils.class);
199     }
200
201     private ConsumerBusinessLogic getConsumerBusinessLogic() {
202         ServletContext context = sr.getSession().getServletContext();
203         WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
204         WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
205         return webApplicationContext.getBean(ConsumerBusinessLogic.class);
206     }
207
208     public enum AuthStatus {
209         AUTH_REQUIRED, AUTH_FAILED_USER_NOT_FOUND, AUTH_FAILED_INVALID_PASSWORD, AUTH_FAILED_INVALID_AUTHENTICATION_HEADER, AUTH_SUCCESS
210     }
211
212     protected Response buildErrorResponse(ResponseFormat requestErrorWrapper, boolean addWwwAuthenticationHeader) {
213         ResponseBuilder responseBuilder = Response.status(requestErrorWrapper.getStatus());
214         if (addWwwAuthenticationHeader) {
215             responseBuilder = responseBuilder.header("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
216         }
217                 return responseBuilder.entity(gson.toJson(requestErrorWrapper.getRequestError())).build();
218     }
219
220         private void abortWith(ContainerRequestContext requestContext, String message, Response response) {
221
222                 audit.log(sr.getRemoteAddr(),
223                                 requestContext,
224                                 response.getStatusInfo(),
225                                 LogLevel.ERROR,
226                                 Severity.WARNING,
227                                 message);
228
229                 log.error(message);
230                 audit.clearMyData();
231                 requestContext.abortWith(response);
232         }
233 }