blob: 24a3eec7b174238181056d1dd459b30f5bc802e3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.knox.gateway.topology.discovery.ambari;
import net.minidev.json.JSONObject;
import net.minidev.json.JSONValue;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.knox.gateway.config.ConfigurationException;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.services.security.AliasServiceException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
class RESTInvoker {
private static final String DEFAULT_USER_ALIAS = "ambari.discovery.user";
private static final String DEFAULT_PWD_ALIAS = "ambari.discovery.password";
private static final AmbariServiceDiscoveryMessages log = MessagesFactory.get(AmbariServiceDiscoveryMessages.class);
private static final int DEFAULT_TIMEOUT = 10000;
private AliasService aliasService;
private CloseableHttpClient httpClient;
RESTInvoker(AliasService aliasService) {
this(null, aliasService);
}
RESTInvoker(GatewayConfig config, AliasService aliasService) {
this.aliasService = aliasService;
// Initialize the HTTP client
this.httpClient = HttpClientBuilder.create().setDefaultRequestConfig(getRequestConfig(config)).build();
}
private static RequestConfig getRequestConfig(GatewayConfig config) {
RequestConfig.Builder builder = RequestConfig.custom();
if (config != null) {
builder.setConnectTimeout(config.getHttpClientConnectionTimeout())
.setConnectionRequestTimeout(config.getHttpClientConnectionTimeout())
.setSocketTimeout(config.getHttpClientSocketTimeout());
} else {
builder.setConnectTimeout(DEFAULT_TIMEOUT)
.setConnectionRequestTimeout(DEFAULT_TIMEOUT)
.setSocketTimeout(DEFAULT_TIMEOUT);
}
return builder.build();
}
JSONObject invoke(String url, String username, String passwordAlias) {
JSONObject result = null;
try {
HttpGet request = new HttpGet(url);
// If no configured username, then use default username alias
String password = null;
if (username == null) {
if (aliasService != null) {
try {
char[] defaultUser = aliasService.getPasswordFromAliasForGateway(DEFAULT_USER_ALIAS);
if (defaultUser != null) {
username = new String(defaultUser);
}
} catch (AliasServiceException e) {
log.aliasServiceUserError(DEFAULT_USER_ALIAS, e.getLocalizedMessage());
}
}
// If username is still null
if (username == null) {
log.aliasServiceUserNotFound();
throw new ConfigurationException("No username is configured for Ambari service discovery.");
}
}
if (aliasService != null) {
// If no password alias is configured, then try the default alias
if (passwordAlias == null) {
passwordAlias = DEFAULT_PWD_ALIAS;
}
try {
char[] pwd = aliasService.getPasswordFromAliasForGateway(passwordAlias);
if (pwd != null) {
password = new String(pwd);
}
} catch (AliasServiceException e) {
log.aliasServicePasswordError(passwordAlias, e.getLocalizedMessage());
}
}
// If the password could not be determined
if (password == null) {
log.aliasServicePasswordNotFound();
throw new ConfigurationException("No password is configured for Ambari service discovery.");
}
// Add an auth header if credentials are available
String encodedCreds = Base64.getEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));
request.addHeader(new BasicHeader("Authorization", "Basic " + encodedCreds));
// Ambari CSRF protection
request.addHeader("X-Requested-By", "Knox");
try(CloseableHttpResponse response = httpClient.execute(request)){
if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = (JSONObject) JSONValue.parse((EntityUtils.toString(entity)));
log.debugJSON(result.toJSONString());
} else {
log.noJSON(url);
}
} else {
log.unexpectedRestResponseStatusCode(url, response.getStatusLine().getStatusCode());
}
}
} catch (ConnectTimeoutException e) {
log.restInvocationTimedOut(url, e);
} catch (IOException e) {
log.restInvocationError(url, e);
}
return result;
}
}