2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 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=========================================================
20 package org.onap.aai.schemaservice.interceptors.pre;
22 import org.onap.aai.auth.AAIAuthCore;
23 import org.onap.aai.exceptions.AAIException;
24 import org.onap.aai.logging.ErrorLogHelper;
25 import org.onap.aai.restcore.HttpMethod;
26 import org.onap.aai.schemaservice.interceptors.AAIContainerFilter;
27 import org.onap.aai.schemaservice.interceptors.AAIHeaderProperties;
28 import org.springframework.beans.factory.annotation.Autowired;
29 import org.springframework.context.annotation.Profile;
31 import javax.annotation.Priority;
32 import javax.security.auth.x500.X500Principal;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.ws.rs.container.ContainerRequestContext;
35 import javax.ws.rs.container.ContainerRequestFilter;
36 import javax.ws.rs.container.PreMatching;
37 import javax.ws.rs.core.MediaType;
38 import javax.ws.rs.core.Response;
39 import java.security.cert.X509Certificate;
41 import java.util.stream.Collectors;
44 @Priority(AAIRequestFilterPriority.AUTHORIZATION)
45 @Profile("two-way-ssl")
46 public class TwoWaySslAuthorization extends AAIContainerFilter implements ContainerRequestFilter {
48 private static final String PATCH = "PATCH";
51 private HttpServletRequest httpServletRequest;
54 private AAIAuthCore aaiAuthCore;
57 public void filter(ContainerRequestContext requestContext) {
59 Optional<Response> oResp;
61 String uri = requestContext.getUriInfo().getAbsolutePath().getPath();
62 String httpMethod = getHttpMethod(requestContext);
64 List<MediaType> acceptHeaderValues = requestContext.getAcceptableMediaTypes();
66 Optional<String> authUser = getUser(this.httpServletRequest);
68 if (authUser.isPresent()) {
69 oResp = this.authorize(uri, httpMethod, acceptHeaderValues, authUser.get(),
70 this.getHaProxyUser(this.httpServletRequest), getCertIssuer(this.httpServletRequest));
71 if (oResp.isPresent()) {
72 requestContext.abortWith(oResp.get());
76 AAIException aaie = new AAIException("AAI_9107");
79 .status(aaie.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper
80 .getRESTAPIErrorResponseWithLogging(acceptHeaderValues, aaie, new ArrayList<>()))
86 private String getCertIssuer(HttpServletRequest hsr) {
87 String issuer = hsr.getHeader("X-AAI-SSL-Issuer");
88 if (issuer != null && !issuer.isEmpty()) {
89 // the haproxy header replaces the ', ' with '/' and reverses on the '/' need to undo that.
90 List<String> broken = Arrays.asList(issuer.split("/"));
91 broken = broken.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
92 Collections.reverse(broken);
93 issuer = String.join(", ", broken);
95 if (hsr.getAttribute("javax.servlet.request.cipher_suite") != null) {
96 X509Certificate[] certChain = (X509Certificate[]) hsr.getAttribute("javax.servlet.request.X509Certificate");
97 if (certChain != null && certChain.length > 0) {
98 X509Certificate clientCert = certChain[0];
99 issuer = clientCert.getIssuerX500Principal().getName();
106 private String getHttpMethod(ContainerRequestContext requestContext) {
107 String httpMethod = requestContext.getMethod();
108 if (javax.ws.rs.HttpMethod.POST.equalsIgnoreCase(httpMethod)
109 && PATCH.equals(requestContext.getHeaderString(AAIHeaderProperties.HTTP_METHOD_OVERRIDE))) {
110 httpMethod = HttpMethod.MERGE_PATCH.toString();
112 if (httpMethod.equalsIgnoreCase(HttpMethod.MERGE_PATCH.toString()) || PATCH.equalsIgnoreCase(httpMethod)) {
113 httpMethod = HttpMethod.PUT.toString();
118 private Optional<String> getUser(HttpServletRequest hsr) {
119 String authUser = null;
120 if (hsr.getAttribute("javax.servlet.request.cipher_suite") != null) {
121 X509Certificate[] certChain = (X509Certificate[]) hsr.getAttribute("javax.servlet.request.X509Certificate");
124 * If the certificate is null or the certificate chain length is zero Then
125 * retrieve the authorization in the request header Authorization Check that it
126 * is not null and that it starts with Basic and then strip the basic portion to
127 * get the base64 credentials Check if this is contained in the AAIBasicAuth
128 * Singleton class If it is, retrieve the username associated with that
129 * credentials and set to authUser Otherwise, get the principal from certificate
130 * and use that authUser
133 if (certChain == null || certChain.length == 0) {
135 String authorization = hsr.getHeader("Authorization");
137 if (authorization != null && authorization.startsWith("Basic ")) {
138 authUser = authorization.substring(6);
142 X509Certificate clientCert = certChain[0];
143 X500Principal subjectDN = clientCert.getSubjectX500Principal();
144 authUser = subjectDN.toString().toLowerCase();
148 return Optional.ofNullable(authUser);
151 private String getHaProxyUser(HttpServletRequest hsr) {
153 if (Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-CN"))
154 || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-OU"))
155 || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-O"))
156 || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-L"))
157 || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-ST"))
158 || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-C"))) {
161 haProxyUser = String.format("CN=%s, OU=%s, O=\"%s\", L=%s, ST=%s, C=%s",
162 Objects.toString(hsr.getHeader("X-AAI-SSL-Client-CN"), ""),
163 Objects.toString(hsr.getHeader("X-AAI-SSL-Client-OU"), ""),
164 Objects.toString(hsr.getHeader("X-AAI-SSL-Client-O"), ""),
165 Objects.toString(hsr.getHeader("X-AAI-SSL-Client-L"), ""),
166 Objects.toString(hsr.getHeader("X-AAI-SSL-Client-ST"), ""),
167 Objects.toString(hsr.getHeader("X-AAI-SSL-Client-C"), "")).toLowerCase();
172 private Optional<Response> authorize(String uri, String httpMethod, List<MediaType> acceptHeaderValues,
173 String authUser, String haProxyUser, String issuer) {
174 Response response = null;
176 if (!aaiAuthCore.authorize(authUser, uri, httpMethod, haProxyUser, issuer)) {
177 throw new AAIException("AAI_9101", "Request on " + httpMethod + " " + uri + " status is not OK");
179 } catch (AAIException e) {
180 response = Response.status(e.getErrorObject().getHTTPResponseCode())
181 .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging(acceptHeaderValues, e, new ArrayList<>()))
184 return Optional.ofNullable(response);