Merge "[AAI] Fix doc config files"
[aai/aai-common.git] / aai-aaf-auth / src / main / java / org / onap / aai / aaf / filters / TwoWaySslAuthorization.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2019 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.onap.aai.aaf.filters;
22
23 import java.io.IOException;
24 import java.security.cert.X509Certificate;
25 import java.util.*;
26
27 import javax.security.auth.x500.X500Principal;
28 import javax.servlet.FilterChain;
29 import javax.servlet.ServletException;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32
33 import org.onap.aai.aaf.auth.AAIAuthCore;
34 import org.onap.aai.aaf.auth.CertUtil;
35 import org.onap.aai.aaf.auth.ResponseFormatter;
36 import org.onap.aai.exceptions.AAIException;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import org.springframework.beans.factory.annotation.Autowired;
40 import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
41 import org.springframework.context.annotation.Profile;
42 import org.springframework.core.env.Environment;
43 import org.springframework.stereotype.Component;
44
45 @Component
46 @Profile("two-way-ssl")
47 public class TwoWaySslAuthorization extends OrderedRequestContextFilter {
48
49     private static final Logger LOGGER = LoggerFactory.getLogger(TwoWaySslAuthorization.class);
50
51     public static final String HTTP_METHOD_OVERRIDE = "X-HTTP-Method-Override";
52
53     public static final String MERGE_PATCH = "MERGE_PATCH";
54
55     @Autowired
56     private Environment environment;
57
58     @Autowired
59     private AAIAuthCore aaiAuthCore;
60
61     @Autowired
62     private CadiProps cadiProps;
63
64     public TwoWaySslAuthorization() {
65         this.setOrder(FilterPriority.TWO_WAY_SSL_AUTH.getPriority());
66     }
67
68     @Override
69     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
70             throws IOException, ServletException {
71
72         String uri = request.getRequestURI();
73         String httpMethod = getHttpMethod(request);
74
75         Optional<String> authUser = getUser(request);
76
77         if (authUser.isPresent()) {
78             Properties cadiProperties = cadiProps.getCadiProperties();
79
80             String issuer = CertUtil.getCertIssuer(request);
81             if (issuer == null || issuer.isEmpty()) {
82                 AAIException aaie = new AAIException("AAI_9107");
83                 ResponseFormatter.errorResponse(aaie, request, response);
84                 return;
85             }
86             issuer = issuer.replaceAll("\\s+", "").toUpperCase();
87
88             List<String> cadiConfiguredIssuers = CertUtil.getCadiCertIssuers(cadiProperties);
89             boolean isAafAuthProfileActive = this.isAafAuthProfileActive();
90             if ((!isAafAuthProfileActive) || (!cadiConfiguredIssuers.contains(issuer))) {
91                 try {
92                     this.authorize(uri, httpMethod, authUser.get(), this.getHaProxyUser(request), issuer);
93                 } catch (AAIException e) {
94                     ResponseFormatter.errorResponse(e, request, response);
95                     return;
96                 }
97             }
98         } else {
99             AAIException aaie = new AAIException("AAI_9107");
100             ResponseFormatter.errorResponse(aaie, request, response);
101             return;
102         }
103         filterChain.doFilter(request, response);
104     }
105
106     private String getHttpMethod(HttpServletRequest request) {
107         String httpMethod = request.getMethod();
108         if ("POST".equalsIgnoreCase(httpMethod) && "PATCH".equals(request.getHeader(HTTP_METHOD_OVERRIDE))) {
109             httpMethod = MERGE_PATCH;
110         }
111         if (httpMethod.equalsIgnoreCase(MERGE_PATCH) || "patch".equalsIgnoreCase(httpMethod)) {
112             httpMethod = "PUT";
113         }
114         return httpMethod;
115     }
116
117     private Optional<String> getUser(HttpServletRequest hsr) {
118         String authUser = null;
119         if (hsr.getAttribute("javax.servlet.request.cipher_suite") != null) {
120             X509Certificate[] certChain = (X509Certificate[]) hsr.getAttribute("javax.servlet.request.X509Certificate");
121
122             /*
123              * If the certificate is null or the certificate chain length is zero Then
124              * retrieve the authorization in the request header Authorization Check that it
125              * is not null and that it starts with Basic and then strip the basic portion to
126              * get the base64 credentials Check if this is contained in the AAIBasicAuth
127              * Singleton class If it is, retrieve the username associated with that
128              * credentials and set to authUser Otherwise, get the principal from certificate
129              * and use that authUser
130              */
131
132             if (certChain == null || certChain.length == 0) {
133
134                 String authorization = hsr.getHeader("Authorization");
135
136                 if (authorization != null && authorization.startsWith("Basic ")) {
137                     authUser = authorization.replace("Basic ", "");
138                 }
139
140             } else {
141                 X509Certificate clientCert = certChain[0];
142                 X500Principal subjectDN = clientCert.getSubjectX500Principal();
143                 authUser = subjectDN.toString().toLowerCase();
144             }
145         }
146
147         return Optional.ofNullable(authUser);
148     }
149
150     private String getHaProxyUser(HttpServletRequest hsr) {
151         String haProxyUser;
152         if (Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-CN")) || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-OU"))
153                 || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-O"))
154                 || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-L"))
155                 || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-ST"))
156                 || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-C"))) {
157             haProxyUser = "";
158         } else {
159             haProxyUser = String.format("CN=%s, OU=%s, O=\"%s\", L=%s, ST=%s, C=%s",
160                     Objects.toString(hsr.getHeader("X-AAI-SSL-Client-CN"), ""),
161                     Objects.toString(hsr.getHeader("X-AAI-SSL-Client-OU"), ""),
162                     Objects.toString(hsr.getHeader("X-AAI-SSL-Client-O"), ""),
163                     Objects.toString(hsr.getHeader("X-AAI-SSL-Client-L"), ""),
164                     Objects.toString(hsr.getHeader("X-AAI-SSL-Client-ST"), ""),
165                     Objects.toString(hsr.getHeader("X-AAI-SSL-Client-C"), "")).toLowerCase();
166         }
167         return haProxyUser;
168     }
169
170     private void authorize(String uri, String httpMethod, String authUser, String haProxyUser, String issuer)
171             throws AAIException {
172         if (!aaiAuthCore.authorize(authUser, uri, httpMethod, haProxyUser, issuer)) {
173             throw new AAIException("AAI_9101", "Request on " + httpMethod + " " + uri + " status is not OK");
174         }
175     }
176
177     private boolean isAafAuthProfileActive() {
178         String[] profiles = environment.getActiveProfiles();
179         if (profiles != null) {
180             if (Arrays.stream(profiles).anyMatch(env -> (env.equalsIgnoreCase(AafProfiles.AAF_CERT_AUTHENTICATION)))) {
181                 return true;
182             }
183         }
184         return false;
185     }
186 }