2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2018 European Software Marketing Ltd.
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.aaf.cadi.sidecar.rproxy;
22 import com.google.gson.Gson;
23 import com.google.gson.reflect.TypeToken;
24 import com.google.gson.stream.JsonReader;
26 import java.io.FileInputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.InputStreamReader;
31 import java.net.URISyntaxException;
32 import java.security.Principal;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.List;
36 import javax.annotation.Resource;
37 import javax.servlet.Filter;
38 import javax.servlet.FilterChain;
39 import javax.servlet.FilterConfig;
40 import javax.servlet.ServletException;
41 import javax.servlet.ServletRequest;
42 import javax.servlet.ServletResponse;
43 import javax.servlet.http.HttpServletRequest;
44 import javax.servlet.http.HttpServletResponse;
45 import org.eclipse.jetty.http.HttpStatus;
46 import org.onap.aaf.cadi.CadiWrap;
47 import org.onap.aaf.cadi.Permission;
48 import org.onap.aaf.cadi.sidecar.rproxy.config.ReverseProxyURIAuthorizationProperties;
49 import org.onap.aaf.cadi.sidecar.rproxy.utils.ReverseProxyAuthorization;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52 import org.springframework.boot.context.properties.EnableConfigurationProperties;
53 import org.springframework.core.annotation.Order;
54 import org.springframework.stereotype.Component;
58 @EnableConfigurationProperties(ReverseProxyURIAuthorizationProperties.class)
59 public class ReverseProxyAuthorizationFilter implements Filter {
61 private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyAuthorizationFilter.class);
63 private List<ReverseProxyAuthorization> reverseProxyAuthorizations = new ArrayList<>();
66 private ReverseProxyURIAuthorizationProperties reverseProxyURIAuthorizationProperties;
69 public void init(FilterConfig filterConfig) throws ServletException {
71 // Read in the URI Authorisation configuration file
72 String authFilePath = reverseProxyURIAuthorizationProperties.getConfigurationFile();
73 if (authFilePath != null) {
74 try (InputStream inputStream =
75 new FileInputStream(new File(reverseProxyURIAuthorizationProperties.getConfigurationFile()));
76 JsonReader jsonReader = new JsonReader(new InputStreamReader(inputStream))) {
77 List<ReverseProxyAuthorization> untrimmedList = new Gson().fromJson(jsonReader,
78 new TypeToken<ArrayList<ReverseProxyAuthorization>>() {}.getType());
79 untrimmedList.removeAll(Collections.singleton(null));
80 reverseProxyAuthorizations = untrimmedList;
81 } catch (IOException e) {
82 throw new ServletException("Authorizations config file not found.", e);
88 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
89 throws IOException, ServletException {
91 CadiWrap cadiWrap = (CadiWrap) servletRequest;
92 Principal principal = cadiWrap.getUserPrincipal();
93 List<Permission> grantedPermissions = new ArrayList<>();
94 cadiWrap.getLur().fishAll(principal, grantedPermissions);
96 if (LOGGER.isDebugEnabled()) {
97 logNeededPermissions();
102 requestPath = new URI(((HttpServletRequest) servletRequest).getRequestURI()).getPath();
103 } catch (URISyntaxException e) {
104 throw new ServletException("Request URI not valid", e);
107 if (authorizeRequest(grantedPermissions, requestPath)) {
108 LOGGER.info("Authorized");
109 filterChain.doFilter(servletRequest, servletResponse);
111 LOGGER.info("Unauthorized");
112 ((HttpServletResponse) servletResponse).setStatus(HttpStatus.FORBIDDEN_403);
113 ((HttpServletResponse) servletResponse).setContentType("application/json");
114 ((HttpServletResponse) servletResponse).sendError(HttpStatus.FORBIDDEN_403,
115 "Sorry, the request is not allowed");
120 * Check if the granted permissions for the request path matches the configured needed permissions.
122 * @param grantedPermissions The granted permissions for the request path
123 * @param requestPath The request path
124 * @return true if permissions match
126 private boolean authorizeRequest(List<Permission> grantedPermissions, String requestPath) {
127 boolean authorized = false;
128 for (ReverseProxyAuthorization reverseProxyAuthorization : reverseProxyAuthorizations) {
129 if (requestPath.matches(reverseProxyAuthorization.getUri())) {
130 LOGGER.debug("The URI:{} matches:{}", requestPath, reverseProxyAuthorization.getUri());
131 if (checkPermissionsMatch(grantedPermissions, reverseProxyAuthorization)) {
136 LOGGER.debug("The URI:{} doesn't match any in the configuration:{}", requestPath,
137 reverseProxyAuthorization.getUri());
144 * Check all needed permissions match the granted permissions.
146 * @param grantedPermissions the granted permissions
147 * @param reverseProxyAuthorization the bean that contains the needed permissions
148 * @return true if all needed permissions match
150 private boolean checkPermissionsMatch(List<Permission> grantedPermissions,
151 ReverseProxyAuthorization reverseProxyAuthorization) {
153 boolean matchedAllPermissions = true;
154 for (String neededPermission : reverseProxyAuthorization.getPermissions()) {
156 // Check needed permission is granted
157 boolean matchedNeededPermission = false;
158 for (Permission grantedPermission : grantedPermissions) {
159 if (checkGrantedPermission(neededPermission, grantedPermission.getKey())) {
160 LOGGER.debug("Permission match found - needed permission:{}, granted permission:{}",
161 neededPermission, grantedPermission.getKey());
162 matchedNeededPermission = true;
166 if (!matchedNeededPermission) {
167 matchedAllPermissions = false;
171 return matchedAllPermissions;
175 * Check whether an AAF style permission matches a needed permission. Wildcards (*) are supported.
177 * @param neededPermission, the needed permission
178 * @param grantedPermission, the granted permission
180 * @return true if the needed permission matches a granted permission
182 private boolean checkGrantedPermission(String neededPermission, String grantedPermission) {
183 boolean permissionMatch = false;
184 if (grantedPermission.matches(neededPermission)) {
185 permissionMatch = true;
186 } else if (grantedPermission.contains("*")) {
187 String[] splitNeededPermission = neededPermission.split("\\\\\\|");
188 String[] splitGrantedPermission = grantedPermission.split("\\|");
189 if ((splitGrantedPermission[0].matches(splitNeededPermission[0]))
190 && (splitGrantedPermission[1].equals("*")
191 || splitGrantedPermission[1].matches(splitNeededPermission[1]))
192 && (splitGrantedPermission[2].equals("*")
193 || splitGrantedPermission[2].matches(splitNeededPermission[2]))) {
194 permissionMatch = true;
197 return permissionMatch;
201 * Log the needed permissions for each URL configured.
203 private void logNeededPermissions() {
204 for (ReverseProxyAuthorization reverseProxyAuthorization : reverseProxyAuthorizations) {
205 LOGGER.debug("URI For authorization: {}", reverseProxyAuthorization.getUri());
206 for (String permission : reverseProxyAuthorization.getPermissions()) {
207 LOGGER.debug("\t Needed permission:{}", permission);
213 public void destroy() {