4f69042d6a5bde07b733a16c20af07bd90d870dd
[aai/schema-service.git] /
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
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
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 package org.onap.aai.schemaservice.interceptors.pre;
21
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;
30
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;
40 import java.util.*;
41 import java.util.stream.Collectors;
42
43 @PreMatching
44 @Priority(AAIRequestFilterPriority.AUTHORIZATION)
45 @Profile("two-way-ssl")
46 public class TwoWaySslAuthorization extends AAIContainerFilter implements ContainerRequestFilter {
47
48     private static final String PATCH = "PATCH";
49
50     @Autowired
51     private HttpServletRequest httpServletRequest;
52
53     @Autowired
54     private AAIAuthCore aaiAuthCore;
55
56     @Override
57     public void filter(ContainerRequestContext requestContext) {
58
59         Optional<Response> oResp;
60
61         String uri = requestContext.getUriInfo().getAbsolutePath().getPath();
62         String httpMethod = getHttpMethod(requestContext);
63
64         List<MediaType> acceptHeaderValues = requestContext.getAcceptableMediaTypes();
65
66         Optional<String> authUser = getUser(this.httpServletRequest);
67
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());
73                 return;
74             }
75         } else {
76             AAIException aaie = new AAIException("AAI_9107");
77             requestContext
78                 .abortWith(Response
79                     .status(aaie.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper
80                         .getRESTAPIErrorResponseWithLogging(acceptHeaderValues, aaie, new ArrayList<>()))
81                     .build());
82         }
83
84     }
85
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);
94         } else {
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();
100                 }
101             }
102         }
103         return issuer;
104     }
105
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();
111         }
112         if (httpMethod.equalsIgnoreCase(HttpMethod.MERGE_PATCH.toString()) || PATCH.equalsIgnoreCase(httpMethod)) {
113             httpMethod = HttpMethod.PUT.toString();
114         }
115         return httpMethod;
116     }
117
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");
122
123             /*
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
131              */
132
133             if (certChain == null || certChain.length == 0) {
134
135                 String authorization = hsr.getHeader("Authorization");
136
137                 if (authorization != null && authorization.startsWith("Basic ")) {
138                     authUser = authorization.substring(6);
139                 }
140
141             } else {
142                 X509Certificate clientCert = certChain[0];
143                 X500Principal subjectDN = clientCert.getSubjectX500Principal();
144                 authUser = subjectDN.toString().toLowerCase();
145             }
146         }
147
148         return Optional.ofNullable(authUser);
149     }
150
151     private String getHaProxyUser(HttpServletRequest hsr) {
152         String haProxyUser;
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"))) {
159             haProxyUser = "";
160         } else {
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();
168         }
169         return haProxyUser;
170     }
171
172     private Optional<Response> authorize(String uri, String httpMethod, List<MediaType> acceptHeaderValues,
173                                          String authUser, String haProxyUser, String issuer) {
174         Response response = null;
175         try {
176             if (!aaiAuthCore.authorize(authUser, uri, httpMethod, haProxyUser, issuer)) {
177                 throw new AAIException("AAI_9101", "Request on " + httpMethod + " " + uri + " status is not OK");
178             }
179         } catch (AAIException e) {
180             response = Response.status(e.getErrorObject().getHTTPResponseCode())
181                 .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging(acceptHeaderValues, e, new ArrayList<>()))
182                 .build();
183         }
184         return Optional.ofNullable(response);
185     }
186
187 }