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