Merge "Added support for using oauth token for Kafka"
[nonrtric/plt/ranpm.git] / datafilecollector / src / main / java / org / oran / datafile / service / HttpUtils.java
1 /*-
2  * ============LICENSE_START======================================================================
3  * Copyright (C) 2018-2023 Nordix Foundation. All rights reserved.
4  * Modifications Copyright (C) 2020-2021 Nokia. All rights reserved
5  * ===============================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  * ============LICENSE_END========================================================================
18  */
19
20 package org.oran.datafile.service;
21
22 import java.util.Base64;
23 import java.util.List;
24
25 import org.apache.hc.core5.http.NameValuePair;
26 import org.apache.http.HttpStatus;
27 import org.oran.datafile.commons.FileServerData;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 public final class HttpUtils implements HttpStatus {
32
33     private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);
34     public static final int HTTP_DEFAULT_PORT = 80;
35     public static final int HTTPS_DEFAULT_PORT = 443;
36     public static final String JWT_TOKEN_NAME = "access_token";
37     public static final String AUTH_JWT_WARN = "Both JWT token and Basic auth data present. Omitting basic auth info.";
38     public static final String AUTH_JWT_ERROR =
39         "More than one JWT token present in the queryParameters. Omitting JWT token.";
40
41     private HttpUtils() {
42     }
43
44     public static String nonRetryableResponse(int responseCode) {
45         return "Unexpected response code - " + responseCode;
46     }
47
48     public static String retryableResponse(int responseCode) {
49         return "Unexpected response code - " + responseCode + ". No retry attempts will be done.";
50     }
51
52     public static boolean isSuccessfulResponseCodeWithDataRouter(Integer statusCode) {
53         return statusCode >= 200 && statusCode < 300;
54     }
55
56     public static boolean isBasicAuthDataFilled(final FileServerData fileServerData) {
57         return !fileServerData.userId.isEmpty() && !fileServerData.password.isEmpty();
58     }
59
60     public static String basicAuthContent(String username, String password) {
61         return "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
62     }
63
64     public static String jwtAuthContent(String token) {
65         return "Bearer " + token;
66     }
67
68     /**
69      * Prepare uri to retrieve file from xNF using HTTP connection. If JWT token was
70      * included
71      * in the queryParameters, it is removed. Other entries are rewritten.
72      *
73      * @param fileServerData fileServerData including - server address, port,
74      *        queryParameters and uriRawFragment
75      * @param remoteFile file which has to be downloaded
76      * @return uri String representing the xNF HTTP location
77      */
78     public static String prepareHttpUri(FileServerData fileServerData, String remoteFile) {
79         return prepareUri("http", fileServerData, remoteFile, HTTP_DEFAULT_PORT);
80     }
81
82     /**
83      * Prepare uri to retrieve file from xNF using HTTPS connection. If JWT token
84      * was included
85      * in the queryParameters, it is removed. Other entries are rewritten.
86      *
87      * @param fileServerData fileServerData including - server address, port,
88      *        queryParameters and uriRawFragment
89      * @param remoteFile file which has to be downloaded
90      * @return uri String representing the xNF HTTPS location
91      */
92     public static String prepareHttpsUri(FileServerData fileServerData, String remoteFile) {
93         return prepareUri("https", fileServerData, remoteFile, HTTPS_DEFAULT_PORT);
94     }
95
96     /**
97      * Prepare uri to retrieve file from xNF. If JWT token was included
98      * in the queryParameters, it is removed. Other entries are rewritten.
99      *
100      * @param scheme scheme which is used during the connection
101      * @param fileServerData fileServerData including - server address, port, query
102      *        and fragment
103      * @param remoteFile file which has to be downloaded
104      * @param defaultPort default port which exchange empty entry for given
105      *        connection type
106      * @return uri String representing the xNF location
107      */
108     public static String prepareUri(String scheme, FileServerData fileServerData, String remoteFile, int defaultPort) {
109         int port = fileServerData.port != null ? fileServerData.port : defaultPort;
110         String query = rewriteQueryWithoutToken(fileServerData.queryParameters);
111         String fragment = fileServerData.uriRawFragment;
112         if (!query.isEmpty()) {
113             query = "?" + query;
114         }
115         if (!fragment.isEmpty()) {
116             fragment = "#" + fragment;
117         }
118         return scheme + "://" + fileServerData.serverAddress + ":" + port + remoteFile + query + fragment;
119     }
120
121     /**
122      * Returns JWT token string (if single exist) from the queryParameters.
123      *
124      * @param fileServerData file server data which contain queryParameters where
125      *        JWT token may exist
126      * @return JWT token value if single token entry exist or empty string
127      *         elsewhere.
128      *         If JWT token key has no value, empty string will be returned.
129      */
130     public static String getJWTToken(FileServerData fileServerData) {
131
132         if (fileServerData.queryParameters.isEmpty()) {
133             return "";
134         }
135         boolean jwtTokenKeyPresent = HttpUtils.isQueryWithSingleJWT(fileServerData.queryParameters);
136         if (!jwtTokenKeyPresent) {
137             return "";
138         }
139         String token = HttpUtils.getJWTToken(fileServerData.queryParameters);
140         if (HttpUtils.isBasicAuthDataFilled(fileServerData)) {
141             logger.warn(HttpUtils.AUTH_JWT_WARN);
142         }
143         return token;
144     }
145
146     /**
147      * Checks if the queryParameters contains single JWT token entry. Valid
148      * queryParameters
149      * contains only one token entry.
150      *
151      * @param query queryParameters
152      * @return true if queryParameters contains single token
153      */
154     public static boolean isQueryWithSingleJWT(List<NameValuePair> query) {
155         if (query == null) {
156             return false;
157         }
158         int i = getJWTTokenCount(query);
159         if (i == 0) {
160             return false;
161         }
162         if (i > 1) {
163             logger.error(AUTH_JWT_ERROR);
164             return false;
165         }
166         return true;
167     }
168
169     /**
170      * Returns the number of JWT token entries. Valid queryParameters contains only
171      * one token entry.
172      *
173      * @param queryElements elements of the queryParameters
174      * @return true if queryParameters contains single JWT token entry
175      */
176     public static int getJWTTokenCount(List<NameValuePair> queryElements) {
177         int i = 0;
178         for (NameValuePair element : queryElements) {
179             if (element.getName().equals(JWT_TOKEN_NAME)) {
180                 i++;
181             }
182         }
183         return i;
184     }
185
186     private static String getJWTToken(List<NameValuePair> query) {
187         for (NameValuePair element : query) {
188             if (!element.getName().equals(JWT_TOKEN_NAME)) {
189                 continue;
190             }
191             if (element.getValue() != null) {
192                 return element.getValue();
193             }
194             return "";
195         }
196         return "";
197     }
198
199     /**
200      * Rewrites HTTP queryParameters without JWT token
201      *
202      * @param query list of NameValuePair of elements sent in the queryParameters
203      * @return String representation of queryParameters elements which were provided
204      *         in the input
205      *         Empty string is possible when queryParameters is empty or contains
206      *         only access_token key.
207      */
208     public static String rewriteQueryWithoutToken(List<NameValuePair> query) {
209         if (query.isEmpty()) {
210             return "";
211         }
212         StringBuilder sb = new StringBuilder();
213         for (NameValuePair nvp : query) {
214             if (nvp.getName().equals(JWT_TOKEN_NAME)) {
215                 continue;
216             }
217             sb.append(nvp.getName());
218             if (nvp.getValue() != null) {
219                 sb.append("=");
220                 sb.append(nvp.getValue());
221             }
222             sb.append("&");
223         }
224         if ((sb.length() > 0) && (sb.charAt(sb.length() - 1) == '&')) {
225             sb.deleteCharAt(sb.length() - 1);
226         }
227         return sb.toString();
228     }
229 }