Commit 2ffa20d1 authored by Greg Messner's avatar Greg Messner
Browse files

Added support for processing the secret token in X-GitLab-Token.

parent 4e42d84e
package org.gitlab4j.api; package org.gitlab4j.api;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.core.Form; import javax.ws.rs.core.Form;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
...@@ -229,13 +230,17 @@ public abstract class AbstractApi { ...@@ -229,13 +230,17 @@ public abstract class AbstractApi {
* @param response response * @param response response
* @param expected expected respone status * @param expected expected respone status
* @return original response if the response status is expected * @return original response if the response status is expected
* @throws GitLabApiException if HTTP status is not as expected * @throws GitLabApiException if HTTP status is not as expected, or the secret token doesn't match
*/ */
protected Response validate(Response response, Response.Status expected) throws GitLabApiException { protected Response validate(Response response, Response.Status expected) throws GitLabApiException {
if (response.getStatus() != expected.getStatusCode()) { if (response.getStatus() != expected.getStatusCode()) {
throw new GitLabApiException(response); throw new GitLabApiException(response);
} }
if (!getApiClient().validateSecretToken(response)) {
throw new GitLabApiException(new NotAuthorizedException("Invalid secret token in response."));
}
return (response); return (response);
} }
......
...@@ -26,7 +26,7 @@ public class GitLabApi { ...@@ -26,7 +26,7 @@ public class GitLabApi {
* @return new {@code GitLabApi} instance configured for a user-specific token * @return new {@code GitLabApi} instance configured for a user-specific token
* @throws GitLabApiException GitLabApiException if any exception occurs during execution * @throws GitLabApiException GitLabApiException if any exception occurs during execution
*/ */
static public GitLabApi create(String url, String username, String password) throws GitLabApiException { public static GitLabApi create(String url, String username, String password) throws GitLabApiException {
String token = new SessionApi(new GitLabApi(url, null)).login(username, null, password).getPrivateToken(); String token = new SessionApi(new GitLabApi(url, null)).login(username, null, password).getPrivateToken();
return new GitLabApi(url, token); return new GitLabApi(url, token);
} }
...@@ -39,7 +39,19 @@ public class GitLabApi { ...@@ -39,7 +39,19 @@ public class GitLabApi {
* @param privateToken to private token to use for access to the API * @param privateToken to private token to use for access to the API
*/ */
public GitLabApi(String hostUrl, String privateToken) { public GitLabApi(String hostUrl, String privateToken) {
apiClient = new GitLabApiClient(hostUrl, privateToken); this(hostUrl, privateToken, null);
}
/**
* Constructs a GitLabApi instance set up to interact with the GitLab server
* specified by hostUrl.
*
* @param hostUrl the URL of the GitLab server
* @param privateToken to private token to use for access to the API
* @param secretToken use this token to validate received payloads
*/
public GitLabApi(String hostUrl, String privateToken, String secretToken) {
apiClient = new GitLabApiClient(hostUrl, privateToken, secretToken);
commitsApi = new CommitsApi(this); commitsApi = new CommitsApi(this);
groupApi = new GroupApi(this); groupApi = new GroupApi(this);
mergeRequestApi = new MergeRequestApi(this); mergeRequestApi = new MergeRequestApi(this);
......
...@@ -35,28 +35,49 @@ import java.util.Map; ...@@ -35,28 +35,49 @@ import java.util.Map;
public class GitLabApiClient { public class GitLabApiClient {
protected static final String PRIVATE_TOKEN_HEADER = "PRIVATE-TOKEN"; protected static final String PRIVATE_TOKEN_HEADER = "PRIVATE-TOKEN";
protected static final String X_GITLAB_TOKEN_HEADER = "X-Gitlab-Token";
protected static final String API_NAMESPACE = "/api/v3"; protected static final String API_NAMESPACE = "/api/v3";
private ClientConfig clientConfig; private ClientConfig clientConfig;
private Client apiClient; private Client apiClient;
private String hostUrl; private String hostUrl;
private String privateToken; private String privateToken;
private String secretToken;
private static boolean ignoreCertificateErrors; private static boolean ignoreCertificateErrors;
private static SSLSocketFactory defaultSocketFactory; private static SSLSocketFactory defaultSocketFactory;
/** /**
* Construct an instance to communicate with a GitLab API server using the specified * Construct an instance to communicate with a GitLab API server using the specified
* server URL and private token. * server URL, private token, and secret token.
* *
* @param hostUrl the URL to the GitLab API server * @param hostUrl the URL to the GitLab API server
* @param privateToken the private token to authenticate with * @param privateToken the private token to authenticate with
*/ */
public GitLabApiClient(String hostUrl, String privateToken) { public GitLabApiClient(String hostUrl, String privateToken) {
this(hostUrl, privateToken, null);
}
/**
* Construct an instance to communicate with a GitLab API server using the specified
* server URL, private token, and secret token.
*
* @param hostUrl the URL to the GitLab API server
* @param privateToken the private token to authenticate with
* @param secretToken use this token to validate received payloads
*/
public GitLabApiClient(String hostUrl, String privateToken, String secretToken) {
// Remove the trailing "/" from the hostUrl if present // Remove the trailing "/" from the hostUrl if present
this.hostUrl = (hostUrl.endsWith("/") ? hostUrl.replaceAll("/$", "") : hostUrl) + API_NAMESPACE; this.hostUrl = (hostUrl.endsWith("/") ? hostUrl.replaceAll("/$", "") : hostUrl) + API_NAMESPACE;
this.privateToken = privateToken; this.privateToken = privateToken;
if (secretToken != null) {
secretToken = secretToken.trim();
secretToken = (secretToken.length() > 0 ? secretToken : null);
}
this.secretToken = secretToken;
clientConfig = new ClientConfig(); clientConfig = new ClientConfig();
clientConfig.register(JacksonJson.class); clientConfig.register(JacksonJson.class);
} }
...@@ -159,6 +180,25 @@ public class GitLabApiClient { ...@@ -159,6 +180,25 @@ public class GitLabApiClient {
return (new URL(url.toString())); return (new URL(url.toString()));
} }
/**
* Validates the secret token (X-GitLab-Token) header against the expected secret token, returns true if valid,
* otherwise returns false.
*
* @param response the Response instance sent from the GitLab server
* @return true if the response's secret token is valid, otherwise returns false
*/
protected boolean validateSecretToken(Response response) {
if (this.secretToken == null)
return (true);
String secretToken = response.getHeaderString(X_GITLAB_TOKEN_HEADER);
if (secretToken == null)
return (false);
return (this.secretToken.equals(secretToken));
}
/** /**
* Perform an HTTP GET call with the specified query parameters and path objects, returning * Perform an HTTP GET call with the specified query parameters and path objects, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
...@@ -288,13 +328,6 @@ public class GitLabApiClient { ...@@ -288,13 +328,6 @@ public class GitLabApiClient {
return (invocation(url, queryParams).delete()); return (invocation(url, queryParams).delete());
} }
protected class AcceptAllHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String s, SSLSession sslSession) {
return (true);
}
}
protected Invocation.Builder invocation(URL url, MultivaluedMap<String, String> queryParams) { protected Invocation.Builder invocation(URL url, MultivaluedMap<String, String> queryParams) {
if (apiClient == null) { if (apiClient == null) {
...@@ -311,6 +344,13 @@ public class GitLabApiClient { ...@@ -311,6 +344,13 @@ public class GitLabApiClient {
return (target.request().header(PRIVATE_TOKEN_HEADER, privateToken).accept(MediaType.APPLICATION_JSON)); return (target.request().header(PRIVATE_TOKEN_HEADER, privateToken).accept(MediaType.APPLICATION_JSON));
} }
protected class AcceptAllHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String s, SSLSession sslSession) {
return (true);
}
}
private SSLContext getSslContext() { private SSLContext getSslContext() {
try { try {
return SSLContext.getDefault(); return SSLContext.getDefault();
...@@ -318,5 +358,4 @@ public class GitLabApiClient { ...@@ -318,5 +358,4 @@ public class GitLabApiClient {
throw new UnsupportedOperationException(e); throw new UnsupportedOperationException(e);
} }
} }
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment