com.cx.restclient.httpClient.CxHttpClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cx-client-common Show documentation
Show all versions of cx-client-common Show documentation
Web client for interaction with Checkmarx SAST, SCA and OSA products
package com.cx.restclient.httpClient;
import com.cx.restclient.common.ErrorMessage;
import com.cx.restclient.dto.LoginSettings;
import com.cx.restclient.dto.ProxyConfig;
import com.cx.restclient.dto.TokenLoginResponse;
import com.cx.restclient.exception.CxClientException;
import com.cx.restclient.exception.CxHTTPClientException;
import com.cx.restclient.exception.CxTokenExpiredException;
import com.cx.restclient.osa.dto.ClientType;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.params.AuthPolicy;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.NoConnectionReuseStrategy;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.auth.DigestSchemeFactory;
import org.apache.http.impl.auth.win.WindowsCredentialsProvider;
import org.apache.http.impl.auth.win.WindowsNTLMSchemeFactory;
import org.apache.http.impl.auth.win.WindowsNegotiateSchemeFactory;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.slf4j.Logger;
import javax.annotation.Nullable;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.Closeable;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.*;
import static com.cx.restclient.common.CxPARAM.*;
import static com.cx.restclient.httpClient.utils.ContentType.CONTENT_TYPE_APPLICATION_JSON;
import static com.cx.restclient.httpClient.utils.HttpClientHelper.*;
/**
* Created by Galn on 05/02/2018.
*/
public class CxHttpClient implements Closeable {
private static final String HTTPS = "https";
private static final String LOGIN_FAILED_MSG = "Fail to login with windows authentication: ";
private static final String DEFAULT_GRANT_TYPE = "password";
private static final String LOCATION_HEADER = "Location";
private static final String AUTH_MESSAGE = "authenticate";
private static final String CLIENT_SECRET_PROP = "client_secret";
public static final String REFRESH_TOKEN_PROP = "refresh_token";
private static final String PASSWORD_PROP = "password";
public static final String CLIENT_ID_PROP = "client_id";
private static final String KEY_USER = "user";
private static final String KEY_DOMAIN = "domain";
private HttpClient apacheClient;
private Logger log;
private TokenLoginResponse token;
private String rootUri;
private final String refreshToken;
private String cxOrigin;
private Boolean useSSo;
private Boolean useNTLM;
private LoginSettings lastLoginSettings;
private String teamPath;
private CookieStore cookieStore = new BasicCookieStore();
private HttpClientBuilder cb = HttpClients.custom();
private final Map customHeaders = new HashMap<>();
public CxHttpClient(String rootUri, String origin, boolean disableSSLValidation, boolean isSSO, String refreshToken,
boolean isProxy, @Nullable ProxyConfig proxyConfig, Logger log, Boolean useNTLM) throws CxClientException {
this.log = log;
this.rootUri = rootUri;
this.refreshToken = refreshToken;
this.cxOrigin = origin;
this.useSSo = isSSO;
this.useNTLM = useNTLM;
//create httpclient
cb.setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build());
setSSLTls("TLSv1.2", log);
SSLContextBuilder builder = new SSLContextBuilder();
SSLConnectionSocketFactory sslConnectionSocketFactory = null;
Registry registry;
PoolingHttpClientConnectionManager cm = null;
if (disableSSLValidation) {
try {
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
sslConnectionSocketFactory = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE);
registry = RegistryBuilder.create()
.register("http", new PlainConnectionSocketFactory())
.register(HTTPS, sslConnectionSocketFactory)
.build();
cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(100);
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
log.error(e.getMessage());
}
cb.setSSLSocketFactory(sslConnectionSocketFactory);
cb.setConnectionManager(cm);
} else {
cb.setConnectionManager(getHttpConnectionManager(false));
}
cb.setConnectionManagerShared(true);
if (isProxy) {
if (!setCustomProxy(cb, proxyConfig, log)) {
cb.useSystemProperties();
}
}
if (Boolean.TRUE.equals(useSSo)) {
cb.setDefaultCredentialsProvider(new WindowsCredentialsProvider(new SystemDefaultCredentialsProvider()));
cb.setDefaultCookieStore(cookieStore);
} else {
cb.setConnectionReuseStrategy(new NoConnectionReuseStrategy());
}
cb.setDefaultAuthSchemeRegistry(getAuthSchemeProviderRegistry());
if (useNTLM)
{
setNTLMProxy(proxyConfig, cb, log);
}
else apacheClient = cb.build();
}
@Deprecated
public CxHttpClient(String rootUri, String origin, boolean disableSSLValidation, boolean isSSO, String refreshToken,
@Nullable ProxyConfig proxyConfig, Logger log) throws CxClientException {
this.log = log;
this.rootUri = rootUri;
this.refreshToken = refreshToken;
this.cxOrigin = origin;
this.useSSo = isSSO;
//create httpclient
cb.setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build());
setSSLTls("TLSv1.2", log);
SSLContextBuilder builder = new SSLContextBuilder();
SSLConnectionSocketFactory sslConnectionSocketFactory = null;
Registry registry;
PoolingHttpClientConnectionManager cm = null;
if (disableSSLValidation) {
try {
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
sslConnectionSocketFactory = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE);
registry = RegistryBuilder.create()
.register("http", new PlainConnectionSocketFactory())
.register(HTTPS, sslConnectionSocketFactory)
.build();
cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(100);
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
log.error(e.getMessage());
}
cb.setSSLSocketFactory(sslConnectionSocketFactory);
cb.setConnectionManager(cm);
} else {
cb.setConnectionManager(getHttpConnectionManager(false));
}
cb.setConnectionManagerShared(true);
setCustomProxy(cb, proxyConfig, log);
if (Boolean.TRUE.equals(useSSo)) {
cb.setDefaultCredentialsProvider(new WindowsCredentialsProvider(new SystemDefaultCredentialsProvider()));
cb.setDefaultCookieStore(cookieStore);
} else {
cb.setConnectionReuseStrategy(new NoConnectionReuseStrategy());
}
cb.setDefaultAuthSchemeRegistry(getAuthSchemeProviderRegistry());
cb.useSystemProperties();
apacheClient = cb.build();
}
private void setNTLMProxy(ProxyConfig proxyConfig, HttpClientBuilder cb, Logger log) {
if (proxyConfig == null ||
StringUtils.isEmpty(proxyConfig.getHost()) ||
proxyConfig.getPort() == 0) {
log.info("Proxy configuration not provided.");
apacheClient = cb.build();
return;
}
log.info("Setting NTLM proxy for Checkmarx http client");
HttpHost proxy = new HttpHost(proxyConfig.getHost(), proxyConfig.getPort(), "http");
HashMap userDomainMap = splitDomainAndTheUserName(proxyConfig.getUsername());
String user = userDomainMap.get(KEY_USER);
String domain = userDomainMap.get(KEY_DOMAIN);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
final NTCredentials credentials = new NTCredentials(user, proxyConfig.getPassword(), null, domain);
credsProvider.setCredentials(AuthScope.ANY, credentials);
apacheClient = HttpClientBuilder.create()
.setDefaultCredentialsProvider(credsProvider)
.setProxy(proxy)
.setProxyAuthenticationStrategy(ProxyAuthenticationStrategy.INSTANCE)
.setDefaultRequestConfig(RequestConfig.custom()
.setAuthenticationEnabled(true)
.setProxyPreferredAuthSchemes(Arrays.asList(AuthPolicy.NTLM))
.build()
)
.build();
}
private static HashMap splitDomainAndTheUserName(String userName)
{
String domain="";
String user="";
// If the username has a backslash, then the domain is the first part and the username is the second part
if (userName.contains("\\")) {
String[] parts = userName.split("[\\\\]");
if (parts.length == 2) {
domain = parts[0];
user = parts[1];
}
} else if (userName.contains("/")) {
// If the username has a slash, then the domain is the first part and the username is the second part
String[] parts = userName.split("[/]");
if (parts.length == 2) {
domain = parts[0];
user = parts[1];
}
} else if (userName.contains("@")) {
// If the username has an asterisk, then the domain is the second part and the username is the first part
String[] parts = userName.split("[@]");
if (parts.length == 2) {
user = parts[0];
domain = parts[1];
}
}
HashMap userDomain = new HashMap();
userDomain.put(KEY_USER,user);
userDomain.put(KEY_DOMAIN, domain);
return userDomain;
}
private static boolean setCustomProxy(HttpClientBuilder cb, ProxyConfig proxyConfig, Logger logi) {
if (proxyConfig == null ||
StringUtils.isEmpty(proxyConfig.getHost()) ||
proxyConfig.getPort() == 0) {
return false;
}
String scheme = proxyConfig.isUseHttps() ? HTTPS : "http";
HttpHost proxy = new HttpHost(proxyConfig.getHost(), proxyConfig.getPort(), scheme);
if (StringUtils.isNotEmpty(proxyConfig.getUsername()) &&
StringUtils.isNotEmpty(proxyConfig.getPassword())) {
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(proxyConfig.getUsername(), proxyConfig.getPassword());
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(proxy), credentials);
cb.setDefaultCredentialsProvider(credsProvider);
}
logi.info("Setting proxy for Checkmarx http client");
cb.setProxy(proxy);
cb.setRoutePlanner(new DefaultProxyRoutePlanner(proxy));
cb.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
return true;
}
private static SSLConnectionSocketFactory getTrustAllSSLSocketFactory() {
TrustStrategy acceptingTrustStrategy = new TrustAllStrategy();
SSLContext sslContext;
try {
sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
throw new CxClientException("Fail to set trust all certificate, 'SSLConnectionSocketFactory'", e);
}
return new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
}
private static PoolingHttpClientConnectionManager getHttpConnectionManager(boolean disableSSLValidation) {
ConnectionSocketFactory factory;
if (disableSSLValidation) {
factory = getTrustAllSSLSocketFactory();
} else {
factory = new SSLConnectionSocketFactory(SSLContexts.createDefault());
}
Registry socketFactoryRegistry = RegistryBuilder.create()
.register(HTTPS, factory)
.register("http", new PlainConnectionSocketFactory())
.build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connManager.setMaxTotal(50);
connManager.setDefaultMaxPerRoute(5);
return connManager;
}
private static Registry getAuthSchemeProviderRegistry() {
return RegistryBuilder.create()
.register(AuthSchemes.DIGEST, new DigestSchemeFactory())
.register(AuthSchemes.BASIC, new BasicSchemeFactory())
.register(AuthSchemes.NTLM, new WindowsNTLMSchemeFactory(null))
.register(AuthSchemes.SPNEGO, new WindowsNegotiateSchemeFactory(null))
.build();
}
public void login(LoginSettings settings) throws IOException {
lastLoginSettings = settings;
if (!settings.getSessionCookies().isEmpty()) {
setSessionCookies(settings.getSessionCookies());
return;
}
if (settings.getRefreshToken() != null) {
token = getAccessTokenFromRefreshToken(settings);
} else if (Boolean.TRUE.equals(useSSo)) {
if (settings.getVersion().equals("lower than 9.0")) {
ssoLegacyLogin();
} else {
token = ssoLogin();
// Don't delete this print. VS Code plugin relies on CxCLI output to work properly.
// Also we don't want the token to appear in regular logs.
System.out.printf("Access Token: %s%n", token.getAccess_token()); // NOSONAR: we need standard output here.
}
} else {
token = generateToken(settings);
}
}
public ArrayList ssoLegacyLogin() {
HttpUriRequest request;
HttpResponse loginResponse = null;
try {
request = RequestBuilder.post()
.setUri(rootUri + "auth/ssologin")
.setConfig(RequestConfig.DEFAULT)
.setEntity(new StringEntity("", StandardCharsets.UTF_8))
.build();
loginResponse = apacheClient.execute(request);
} catch (IOException e) {
String message = LOGIN_FAILED_MSG + e.getMessage();
log.error(message);
throw new CxClientException(message);
} finally {
HttpClientUtils.closeQuietly(loginResponse);
}
setSessionCookies(cookieStore.getCookies());
//return cookies clone - for IDE's usage
return new ArrayList<>(cookieStore.getCookies());
}
private void setSessionCookies(List cookies) {
String cxCookie = null;
String csrfToken = null;
for (Cookie cookie : cookies) {
if (cookie.getName().equals(CSRF_TOKEN_HEADER)) {
csrfToken = cookie.getValue();
}
if (cookie.getName().equals("cxCookie")) {
cxCookie = cookie.getValue();
}
}
List headers = new ArrayList<>();
headers.add(new BasicHeader(CSRF_TOKEN_HEADER, csrfToken));
headers.add(new BasicHeader("cookie", String.format("CXCSRFToken=%s; cxCookie=%s", csrfToken, cxCookie)));
// Don't delete these prints, they are being used on VS Code plugin
System.out.println(CSRF_TOKEN_HEADER + ": " + csrfToken);
System.out.printf("cookie: CXCSRFToken=%s; cxCookie=%s%n", csrfToken, cxCookie);
apacheClient = cb.setDefaultHeaders(headers).build();
}
private TokenLoginResponse ssoLogin() {
HttpUriRequest request;
HttpResponse response;
final String BASE_URL = "/auth/identity/";
RequestConfig requestConfig = RequestConfig.custom()
.setRedirectsEnabled(false)
.setAuthenticationEnabled(true)
.setCookieSpec(CookieSpecs.STANDARD)
.build();
try {
//Request1
request = RequestBuilder.post()
.setUri(rootUri + SSO_AUTHENTICATION)
.setConfig(requestConfig)
.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString())
.setEntity(generateSSOEntity())
.build();
response = apacheClient.execute(request);
//Request2
String cookies = retrieveCookies();
String redirectURL = response.getHeaders(LOCATION_HEADER)[0].getValue();
request = RequestBuilder.get()
.setUri(rootUri + BASE_URL + redirectURL)
.setConfig(requestConfig)
.setHeader("Cookie", cookies)
.setHeader("Upgrade-Insecure-Requests", "1")
.build();
response = apacheClient.execute(request);
//Request3
cookies = retrieveCookies();
redirectURL = response.getHeaders(LOCATION_HEADER)[0].getValue();
redirectURL = rootUri + redirectURL.replace("/CxRestAPI/", "");
request = RequestBuilder.get()
.setUri(redirectURL)
.setConfig(requestConfig)
.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString())
.setHeader("Cookie", cookies)
.build();
response = apacheClient.execute(request);
return extractToken(response);
} catch (IOException e) {
throw new CxClientException(LOGIN_FAILED_MSG + e.getMessage());
}
}
private TokenLoginResponse extractToken(HttpResponse response) {
String redirectURL = response.getHeaders(LOCATION_HEADER)[0].getValue();
if (!redirectURL.contains("access_token")) {
throw new CxClientException("Failed retrieving access token from server");
}
return new Gson().fromJson(urlToJson(redirectURL), TokenLoginResponse.class);
}
private String urlToJson(String url) {
url = url.replace("=", "\":\"");
url = url.replace("&", "\",\"");
return "{\"" + url + "\"}";
}
private String retrieveCookies() {
List cookieList = cookieStore.getCookies();
final StringBuilder builder = new StringBuilder();
cookieList.forEach(cookie ->
builder.append(cookie.getName()).append("=").append(cookie.getValue()).append(";"));
return builder.toString();
}
public TokenLoginResponse generateToken(LoginSettings settings) throws IOException {
UrlEncodedFormEntity requestEntity = getAuthRequest(settings);
HttpPost post = new HttpPost(settings.getAccessControlBaseUrl());
try {
return request(post, ContentType.APPLICATION_FORM_URLENCODED.toString(), requestEntity,
TokenLoginResponse.class, HttpStatus.SC_OK, AUTH_MESSAGE, false, false);
} catch (CxClientException e) {
if (!e.getMessage().contains("invalid_scope")) {
throw new CxClientException(String.format("Failed to generate access token, failure error was: %s", e.getMessage()), e);
}
ClientType.RESOURCE_OWNER.setScopes("sast_rest_api");
settings.setClientTypeForPasswordAuth(ClientType.RESOURCE_OWNER);
requestEntity = getAuthRequest(settings);
return request(post, ContentType.APPLICATION_FORM_URLENCODED.toString(), requestEntity,
TokenLoginResponse.class, HttpStatus.SC_OK, AUTH_MESSAGE, false, false);
}
}
private TokenLoginResponse getAccessTokenFromRefreshToken(LoginSettings settings) throws IOException {
UrlEncodedFormEntity requestEntity = getTokenRefreshingRequest(settings);
HttpPost post = new HttpPost(settings.getAccessControlBaseUrl());
try {
return request(post, ContentType.APPLICATION_FORM_URLENCODED.toString(), requestEntity,
TokenLoginResponse.class, HttpStatus.SC_OK, AUTH_MESSAGE, false, false);
} catch (CxClientException e) {
throw new CxClientException(String.format("Failed to generate access token from refresh token. The error was: %s", e.getMessage()), e);
}
}
public void revokeToken(String token) throws IOException {
UrlEncodedFormEntity requestEntity = getRevocationRequest(ClientType.CLI, token);
HttpPost post = new HttpPost(rootUri + REVOCATION);
try {
request(post, ContentType.APPLICATION_FORM_URLENCODED.toString(), requestEntity,
String.class, HttpStatus.SC_OK, "revocation", false, false);
} catch (CxClientException e) {
throw new CxClientException(String.format("Token revocation failure error was: %s", e.getMessage()), e);
}
}
private static UrlEncodedFormEntity getRevocationRequest(ClientType clientType, String token) {
List parameters = new ArrayList<>();
parameters.add(new BasicNameValuePair("token_type_hint", REFRESH_TOKEN_PROP));
parameters.add(new BasicNameValuePair("token", token));
parameters.add(new BasicNameValuePair(CLIENT_ID_PROP, clientType.getClientId()));
parameters.add(new BasicNameValuePair(CLIENT_SECRET_PROP, clientType.getClientSecret()));
return new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8);
}
private static UrlEncodedFormEntity getAuthRequest(LoginSettings settings) {
ClientType clientType = settings.getClientTypeForPasswordAuth();
String grantType = StringUtils.defaultString(clientType.getGrantType(), DEFAULT_GRANT_TYPE);
List parameters = new ArrayList<>();
parameters.add(new BasicNameValuePair("username", settings.getUsername()));
parameters.add(new BasicNameValuePair(PASSWORD_PROP, settings.getPassword()));
parameters.add(new BasicNameValuePair("grant_type", grantType));
parameters.add(new BasicNameValuePair("scope", clientType.getScopes()));
parameters.add(new BasicNameValuePair(CLIENT_ID_PROP, clientType.getClientId()));
parameters.add(new BasicNameValuePair(CLIENT_SECRET_PROP, clientType.getClientSecret()));
if (!StringUtils.isEmpty(settings.getTenant())) {
String authContext = String.format("Tenant:%s", settings.getTenant());
parameters.add(new BasicNameValuePair("acr_values", authContext));
}
return new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8);
}
private static UrlEncodedFormEntity getTokenRefreshingRequest(LoginSettings settings) throws UnsupportedEncodingException {
ClientType clientType = settings.getClientTypeForRefreshToken();
List parameters = new ArrayList<>();
parameters.add(new BasicNameValuePair("grant_type", REFRESH_TOKEN_PROP));
parameters.add(new BasicNameValuePair(CLIENT_ID_PROP, clientType.getClientId()));
parameters.add(new BasicNameValuePair(CLIENT_SECRET_PROP, clientType.getClientSecret()));
parameters.add(new BasicNameValuePair(REFRESH_TOKEN_PROP, settings.getRefreshToken()));
return new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8.name());
}
//GET REQUEST
public T getRequest(String relPath, String contentType, Class responseType, int expectStatus, String failedMsg, boolean isCollection) throws IOException {
return getRequest(rootUri, relPath, CONTENT_TYPE_APPLICATION_JSON, contentType, responseType, expectStatus, failedMsg, isCollection);
}
public T getRequest(String rootURL, String relPath, String acceptHeader, String contentType, Class responseType, int expectStatus, String failedMsg, boolean isCollection) throws IOException {
HttpGet get = new HttpGet(rootURL + relPath);
get.addHeader(HttpHeaders.ACCEPT, acceptHeader);
return request(get, contentType, null, responseType, expectStatus, "get " + failedMsg, isCollection, true);
}
//POST REQUEST
public T postRequest(String relPath, String contentType, HttpEntity entity, Class responseType, int expectStatus, String failedMsg) throws IOException {
HttpPost post = new HttpPost(rootUri + relPath);
return request(post, contentType, entity, responseType, expectStatus, failedMsg, false, true);
}
//PUT REQUEST
public T putRequest(String relPath, String contentType, HttpEntity entity, Class responseType, int expectStatus, String failedMsg) throws IOException {
HttpPut put = new HttpPut(rootUri + relPath);
return request(put, contentType, entity, responseType, expectStatus, failedMsg, false, true);
}
//PATCH REQUEST
public void patchRequest(String relPath, String contentType, HttpEntity entity, int expectStatus, String failedMsg) throws IOException {
HttpPatch patch = new HttpPatch(rootUri + relPath);
request(patch, contentType, entity, null, expectStatus, failedMsg, false, true);
}
public void setTeamPathHeader(String teamPath) {
this.teamPath = teamPath;
}
public void addCustomHeader(String name, String value) {
log.debug(String.format("Adding a custom header: %s: %s", name, value));
customHeaders.put(name, value);
}
private T request(HttpRequestBase httpMethod, String contentType, HttpEntity entity, Class responseType, int expectStatus, String failedMsg, boolean isCollection, boolean retry) throws IOException {
if (contentType != null) {
httpMethod.addHeader("Content-type", contentType);
}
if (entity != null && httpMethod instanceof HttpEntityEnclosingRequestBase) { //Entity for Post methods
((HttpEntityEnclosingRequestBase) httpMethod).setEntity(entity);
}
HttpResponse response = null;
int statusCode = 0;
try {
httpMethod.addHeader(ORIGIN_HEADER, cxOrigin);
httpMethod.addHeader(TEAM_PATH, this.teamPath);
if (token != null) {
httpMethod.addHeader(HttpHeaders.AUTHORIZATION, token.getToken_type() + " " + token.getAccess_token());
}
for (Map.Entry entry : customHeaders.entrySet()) {
httpMethod.addHeader(entry.getKey(), entry.getValue());
}
response = apacheClient.execute(httpMethod);
statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_UNAUTHORIZED) { // Token has probably expired
throw new CxTokenExpiredException(extractResponseBody(response));
}
validateResponse(response, expectStatus, "Failed to " + failedMsg);
//extract response as object and return the link
return convertToObject(response, responseType, isCollection);
} catch (UnknownHostException e) {
throw new CxHTTPClientException(ErrorMessage.CHECKMARX_SERVER_CONNECTION_FAILED.getErrorMessage());
} catch (CxTokenExpiredException ex) {
if (retry) {
logTokenError(httpMethod, statusCode, ex);
if (lastLoginSettings != null) {
login(lastLoginSettings);
return request(httpMethod, contentType, entity, responseType, expectStatus, failedMsg, isCollection, false);
}
}
throw ex;
} finally {
httpMethod.releaseConnection();
HttpClientUtils.closeQuietly(response);
}
}
public void close() {
HttpClientUtils.closeQuietly(apacheClient);
}
private void setSSLTls(String protocol, Logger log) {
try {
final SSLContext sslContext = SSLContext.getInstance(protocol);
sslContext.init(null, null, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
log.warn(String.format("Failed to set SSL TLS : %s", e.getMessage()));
}
}
//TODO handle missing scope issue with management_and_orchestration_api
private StringEntity generateSSOEntity() {
final String clientId = "cxsast_client";
final String redirectUri = "%2Fcxwebclient%2FauthCallback.html%3F";
final String responseType = "id_token%20token";
final String nonce = "9313f0902ba64e50bc564f5137f35a52";
final String isPrompt = "true";
final String scopes = "sast_api openid sast-permissions access-control-permissions access_control_api management_and_orchestration_api".replace(" ", "%20");
final String providerId = "2"; //windows provider id
String redirectUrl = MessageFormat.format("/CxRestAPI/auth/identity/connect/authorize/callback" +
"?client_id={0}" +
"&redirect_uri={1}" + redirectUri +
"&response_type={2}" +
"&scope={3}" +
"&nonce={4}" +
"&prompt={5}"
, clientId, rootUri, responseType, scopes, nonce, isPrompt);
try {
List urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("redirectUrl", redirectUrl));
urlParameters.add(new BasicNameValuePair("providerid", providerId));
return new UrlEncodedFormEntity(urlParameters, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new CxClientException(e.getMessage());
}
}
public void setToken(TokenLoginResponse token) {
this.token = token;
}
private void logTokenError(HttpRequestBase httpMethod, int statusCode, CxTokenExpiredException ex) {
String message = String.format("Received status code %d for URL: %s with the message: %s",
statusCode,
httpMethod.getURI(),
ex.getMessage());
log.warn(message);
log.info("Possible reason: access token has expired. Trying to request a new token...");
}
}