From 53f8f8efd1c3c58a2552f1e9b66376088dab5f4a Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Mon, 12 Mar 2018 15:43:40 -0700 Subject: [PATCH 1/6] Initial commit (#155). --- .../api/utils/Oauth2LoginStreamingOutput.java | 69 +++++++++++++++++++ .../org/gitlab4j/api/utils/SecretString.java | 64 +++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java create mode 100644 src/main/java/org/gitlab4j/api/utils/SecretString.java diff --git a/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java b/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java new file mode 100644 index 000000000..3c85499c1 --- /dev/null +++ b/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java @@ -0,0 +1,69 @@ +package org.gitlab4j.api.utils; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.StreamingOutput; + +/** + * This StreamingOutput implementation is utilized to send a OAuth2 token request + * in a secure manner. The password is never copied to a String, instead it is + * contained in a SecretString that is cleared when an instance of this class is finalized. + */ +public class Oauth2LoginStreamingOutput implements StreamingOutput, AutoCloseable { + + private final String username; + private final SecretString password; + + public Oauth2LoginStreamingOutput(String username, CharSequence password) { + this.username = username; + this.password = new SecretString(password); + } + + public Oauth2LoginStreamingOutput(String username, char[] password) { + this.username = username; + this.password = new SecretString(password); + } + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + + PrintWriter writer = new PrintWriter(output); + writer.append("{ "); + writer.append("\"grant_type\": \"password\", "); + writer.append("\"username\": \"" + username + "\", "); + writer.append("\"password\": "); + + // Output the quoted password + writer.append('"'); + for (int i = 0, length = password.length(); i < length; i++) { + char c = password.charAt(i); + writer.append(c); + } + writer.append('"'); + + writer.append(" }"); + writer.flush(); + writer.close(); + } + + /** + * Clears the contained password's data. + */ + public void clearPassword() { + password.clear(); + } + + @Override + public void close() { + password.clear(); + } + + @Override + public void finalize() throws Throwable { + clearPassword(); + super.finalize(); + } +} \ No newline at end of file diff --git a/src/main/java/org/gitlab4j/api/utils/SecretString.java b/src/main/java/org/gitlab4j/api/utils/SecretString.java new file mode 100644 index 000000000..a4673f42a --- /dev/null +++ b/src/main/java/org/gitlab4j/api/utils/SecretString.java @@ -0,0 +1,64 @@ +package org.gitlab4j.api.utils; + +import java.util.Arrays; + +/** + * This class implements a CharSequence that can be cleared of it's contained characters. + * This class is utilized to pass around secrets (passwords) instead of a String instance. + */ +public class SecretString implements CharSequence, AutoCloseable { + + private final char[] chars; + + public SecretString(CharSequence charSequence) { + + int length = charSequence.length(); + chars = new char[length]; + for (int i = 0; i < length; i++) { + chars[i] = charSequence.charAt(i); + } + } + + public SecretString(char[] chars) { + this(chars, 0, chars.length); + } + + public SecretString(char[] chars, int start, int end) { + this.chars = new char[end - start]; + System.arraycopy(chars, start, this.chars, 0, this.chars.length); + } + + @Override + public char charAt(int index) { + return chars[index]; + } + + @Override + public void close() { + clear(); + } + + @Override + public int length() { + return chars.length; + } + + @Override + public CharSequence subSequence(int start, int end) { + return new SecretString(this.chars, start, end); + } + + /** + * Clear the contents of this SecretString instance by setting each character to 0. + * This is automatically done in the finalize() method. + */ + public void clear() { + Arrays.fill(chars, '\0'); + } + + @Override + public void finalize() throws Throwable { + clear(); + super.finalize(); + } +} \ No newline at end of file From eeb9f62d552190c28f3d6a25ed5d25259e936564 Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Mon, 12 Mar 2018 15:44:09 -0700 Subject: [PATCH 2/6] Mods to support secure passwords (#155). --- .../java/org/gitlab4j/api/AbstractApi.java | 20 ++ src/main/java/org/gitlab4j/api/GitLabApi.java | 176 ++++++++++++++++-- .../org/gitlab4j/api/GitLabApiClient.java | 16 ++ .../org/gitlab4j/api/TestGitLabLogin.java | 25 ++- 4 files changed, 217 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/gitlab4j/api/AbstractApi.java b/src/main/java/org/gitlab4j/api/AbstractApi.java index 477fd8d82..d14834c51 100644 --- a/src/main/java/org/gitlab4j/api/AbstractApi.java +++ b/src/main/java/org/gitlab4j/api/AbstractApi.java @@ -7,6 +7,7 @@ import javax.ws.rs.core.Form; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; import org.gitlab4j.api.GitLabApi.ApiVersion; @@ -141,6 +142,25 @@ protected Response post(Response.Status expectedStatus, Object payload, Object.. } } + /** + * Perform an HTTP POST call with the specified payload object and path objects, returning + * a ClientResponse instance with the data returned from the endpoint. + * + * @param expectedStatus the HTTP status that should be returned from the server + * @param stream the StreamingOutput taht will be used for the POST data + * @param mediaType the content-type for the streamed data + * @param pathArgs variable list of arguments used to build the URI + * @return a ClientResponse instance with the data returned from the endpoint + * @throws GitLabApiException if any exception occurs during execution + */ + protected Response post(Response.Status expectedStatus, StreamingOutput stream, String mediaType, Object... pathArgs) throws GitLabApiException { + try { + return validate(getApiClient().post(stream, mediaType, pathArgs), expectedStatus); + } catch (Exception e) { + throw handle(e); + } + } + /** * Perform an HTTP POST call with the specified form data and path objects, returning * a ClientResponse instance with the data returned from the endpoint. diff --git a/src/main/java/org/gitlab4j/api/GitLabApi.java b/src/main/java/org/gitlab4j/api/GitLabApi.java index 6e75cc89f..aa61a0fd9 100644 --- a/src/main/java/org/gitlab4j/api/GitLabApi.java +++ b/src/main/java/org/gitlab4j/api/GitLabApi.java @@ -5,6 +5,7 @@ import java.util.Optional; import java.util.WeakHashMap; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.gitlab4j.api.Constants.TokenType; @@ -12,6 +13,8 @@ import org.gitlab4j.api.models.Session; import org.gitlab4j.api.models.User; import org.gitlab4j.api.models.Version; +import org.gitlab4j.api.utils.Oauth2LoginStreamingOutput; +import org.gitlab4j.api.utils.SecretString; /** * This class is provides a simplified interface to a GitLab API server, and divides the API up into @@ -95,11 +98,44 @@ public final GitLabApi duplicate() { * @param password password for a given {@code username} * @return new {@code GitLabApi} instance configured for a user-specific token * @throws GitLabApiException GitLabApiException if any exception occurs during execution + * @deprecated As of release 4.8.7, replaced by {@link #oauth2Login(String, String, CharSequence)}, will be removed in 4.9.0 */ + @Deprecated public static GitLabApi oauth2Login(String url, String username, String password) throws GitLabApiException { return (GitLabApi.oauth2Login(ApiVersion.V4, url, username, password, null, null, false)); } + /** + *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, + * and creates a new {@code GitLabApi} instance using returned access token.

+ * + * @param url GitLab URL + * @param username user name for which private token should be obtained + * @param password a CharSequence containing the password for a given {@code username} + * @return new {@code GitLabApi} instance configured for a user-specific token + * @throws GitLabApiException GitLabApiException if any exception occurs during execution + */ + public static GitLabApi oauth2Login(String url, String username, CharSequence password) throws GitLabApiException { + return (GitLabApi.oauth2Login(ApiVersion.V4, url, username, password, null, null, false)); + } + + /** + *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, + * and creates a new {@code GitLabApi} instance using returned access token.

+ * + * @param url GitLab URL + * @param username user name for which private token should be obtained + * @param password a char array holding the password for a given {@code username} + * @return new {@code GitLabApi} instance configured for a user-specific token + * @throws GitLabApiException GitLabApiException if any exception occurs during execution + */ + public static GitLabApi oauth2Login(String url, String username, char[] password) throws GitLabApiException { + + try (SecretString secretPassword = new SecretString(password)) { + return (GitLabApi.oauth2Login(ApiVersion.V4, url, username, secretPassword, null, null, false)); + } + } + /** *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, * and creates a new {@code GitLabApi} instance using returned access token.

@@ -110,11 +146,46 @@ public static GitLabApi oauth2Login(String url, String username, String password * @param ignoreCertificateErrors if true will set up the Jersey system ignore SSL certificate errors * @return new {@code GitLabApi} instance configured for a user-specific token * @throws GitLabApiException GitLabApiException if any exception occurs during execution + * @deprecated As of release 4.8.7, replaced by {@link #oauth2Login(String, String, CharSequence, boolean)}, will be removed in 4.9.0 */ + @Deprecated public static GitLabApi oauth2Login(String url, String username, String password, boolean ignoreCertificateErrors) throws GitLabApiException { return (GitLabApi.oauth2Login(ApiVersion.V4, url, username, password, null, null, ignoreCertificateErrors)); } + /** + *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, + * and creates a new {@code GitLabApi} instance using returned access token.

+ * + * @param url GitLab URL + * @param username user name for which private token should be obtained + * @param password a CharSequence containing the password for a given {@code username} + * @param ignoreCertificateErrors if true will set up the Jersey system ignore SSL certificate errors + * @return new {@code GitLabApi} instance configured for a user-specific token + * @throws GitLabApiException GitLabApiException if any exception occurs during execution + */ + public static GitLabApi oauth2Login(String url, String username, CharSequence password, boolean ignoreCertificateErrors) throws GitLabApiException { + return (GitLabApi.oauth2Login(ApiVersion.V4, url, username, password, null, null, ignoreCertificateErrors)); + } + + /** + *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, + * and creates a new {@code GitLabApi} instance using returned access token.

+ * + * @param url GitLab URL + * @param username user name for which private token should be obtained + * @param password a char array holding the password for a given {@code username} + * @param ignoreCertificateErrors if true will set up the Jersey system ignore SSL certificate errors + * @return new {@code GitLabApi} instance configured for a user-specific token + * @throws GitLabApiException GitLabApiException if any exception occurs during execution + */ + public static GitLabApi oauth2Login(String url, String username, char[] password, boolean ignoreCertificateErrors) throws GitLabApiException { + + try (SecretString secretPassword = new SecretString(password)) { + return (GitLabApi.oauth2Login(ApiVersion.V4, url, username, secretPassword, null, null, ignoreCertificateErrors)); + } + } + /** *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, * and creates a new {@code GitLabApi} instance using returned access token.

@@ -127,13 +198,77 @@ public static GitLabApi oauth2Login(String url, String username, String password * @param ignoreCertificateErrors if true will set up the Jersey system ignore SSL certificate errors * @return new {@code GitLabApi} instance configured for a user-specific token * @throws GitLabApiException GitLabApiException if any exception occurs during execution + * @deprecated As of release 4.8.7, will be removed in 4.9.0 */ - public static GitLabApi oauth2Login(String url, String username, String password, - String secretToken, Map clientConfigProperties, boolean ignoreCertificateErrors) - throws GitLabApiException { + @Deprecated + public static GitLabApi oauth2Login(String url, String username, String password, String secretToken, + Map clientConfigProperties, boolean ignoreCertificateErrors) throws GitLabApiException { + return (GitLabApi.oauth2Login(ApiVersion.V4, url, username, password, secretToken, clientConfigProperties, ignoreCertificateErrors)); + } + + /** + *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, + * and creates a new {@code GitLabApi} instance using returned access token.

+ * + * @param url GitLab URL + * @param username user name for which private token should be obtained + * @param password a CharSequence containing the password for a given {@code username} + * @param secretToken use this token to validate received payloads + * @param clientConfigProperties Map instance with additional properties for the Jersey client connection + * @param ignoreCertificateErrors if true will set up the Jersey system ignore SSL certificate errors + * @return new {@code GitLabApi} instance configured for a user-specific token + * @throws GitLabApiException GitLabApiException if any exception occurs during execution + */ + public static GitLabApi oauth2Login(String url, String username, CharSequence password, String secretToken, + Map clientConfigProperties, boolean ignoreCertificateErrors) throws GitLabApiException { return (GitLabApi.oauth2Login(ApiVersion.V4, url, username, password, secretToken, clientConfigProperties, ignoreCertificateErrors)); } + /** + *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, + * and creates a new {@code GitLabApi} instance using returned access token.

+ * + * @param url GitLab URL + * @param username user name for which private token should be obtained + * @param password a char array holding the password for a given {@code username} + * @param secretToken use this token to validate received payloads + * @param clientConfigProperties Map instance with additional properties for the Jersey client connection + * @param ignoreCertificateErrors if true will set up the Jersey system ignore SSL certificate errors + * @return new {@code GitLabApi} instance configured for a user-specific token + * @throws GitLabApiException GitLabApiException if any exception occurs during execution + */ + public static GitLabApi oauth2Login(String url, String username, char[] password, String secretToken, + Map clientConfigProperties, boolean ignoreCertificateErrors) throws GitLabApiException { + + try (SecretString secretPassword = new SecretString(password)) { + return (GitLabApi.oauth2Login(ApiVersion.V4, url, username, secretPassword, + secretToken, clientConfigProperties, ignoreCertificateErrors)); + } + } + + /** + *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, + * and creates a new {@code GitLabApi} instance using returned access token.

+ * + * @param url GitLab URL + * @param apiVersion the ApiVersion specifying which version of the API to use + * @param username user name for which private token should be obtained + * @param password a char array holding the password for a given {@code username} + * @param secretToken use this token to validate received payloads + * @param clientConfigProperties Map instance with additional properties for the Jersey client connection + * @param ignoreCertificateErrors if true will set up the Jersey system ignore SSL certificate errors + * @return new {@code GitLabApi} instance configured for a user-specific token + * @throws GitLabApiException GitLabApiException if any exception occurs during execution + */ + public static GitLabApi oauth2Login(ApiVersion apiVersion, String url, String username, char[] password, String secretToken, + Map clientConfigProperties, boolean ignoreCertificateErrors) throws GitLabApiException { + + try (SecretString secretPassword = new SecretString(password)) { + return (GitLabApi.oauth2Login(apiVersion, url, username, secretPassword, + secretToken, clientConfigProperties, ignoreCertificateErrors)); + } + } + /** *

Logs into GitLab using OAuth2 with the provided {@code username} and {@code password}, * and creates a new {@code GitLabApi} instance using returned access token.

@@ -148,7 +283,7 @@ public static GitLabApi oauth2Login(String url, String username, String password * @return new {@code GitLabApi} instance configured for a user-specific token * @throws GitLabApiException GitLabApiException if any exception occurs during execution */ - public static GitLabApi oauth2Login(ApiVersion apiVersion, String url, String username, String password, + public static GitLabApi oauth2Login(ApiVersion apiVersion, String url, String username, CharSequence password, String secretToken, Map clientConfigProperties, boolean ignoreCertificateErrors) throws GitLabApiException { @@ -167,19 +302,17 @@ class Oauth2Api extends AbstractApi { } } - GitLabApiForm formData = new GitLabApiForm() - .withParam("grant_type", "password", true) - .withParam("username", username, true) - .withParam("password", password, true); + try (Oauth2LoginStreamingOutput stream = new Oauth2LoginStreamingOutput(username, password)) { - Response response = new Oauth2Api(gitLabApi).post(Response.Status.OK, formData, "oauth", "token"); - OauthTokenResponse oauthToken = response.readEntity(OauthTokenResponse.class); - gitLabApi = new GitLabApi(apiVersion, url, TokenType.ACCESS, oauthToken.getAccessToken(), secretToken, clientConfigProperties); - if (ignoreCertificateErrors) { - gitLabApi.setIgnoreCertificateErrors(true); - } + Response response = new Oauth2Api(gitLabApi).post(Response.Status.OK, stream, MediaType.APPLICATION_JSON, "oauth", "token"); + OauthTokenResponse oauthToken = response.readEntity(OauthTokenResponse.class); + gitLabApi = new GitLabApi(apiVersion, url, TokenType.ACCESS, oauthToken.getAccessToken(), secretToken, clientConfigProperties); + if (ignoreCertificateErrors) { + gitLabApi.setIgnoreCertificateErrors(true); + } - return (gitLabApi); + return (gitLabApi); + } } /** @@ -195,7 +328,9 @@ class Oauth2Api extends AbstractApi { * @param password password for a given {@code username} * @return new {@code GitLabApi} instance configured for a user-specific token * @throws GitLabApiException GitLabApiException if any exception occurs during execution + * @deprecated As of release 4.8.7, will be removed in 4.9.0 */ + @Deprecated public static GitLabApi login(ApiVersion apiVersion, String url, String username, String password) throws GitLabApiException { return (GitLabApi.login(apiVersion, url, username, password, false)); } @@ -212,7 +347,9 @@ public static GitLabApi login(ApiVersion apiVersion, String url, String username * @param password password for a given {@code username} * @return new {@code GitLabApi} instance configured for a user-specific token * @throws GitLabApiException GitLabApiException if any exception occurs during execution + * @deprecated As of release 4.8.7, will be removed in 4.9.0 */ + @Deprecated public static GitLabApi login(String url, String username, String password) throws GitLabApiException { return (GitLabApi.login(ApiVersion.V4, url, username, password, false)); } @@ -231,7 +368,9 @@ public static GitLabApi login(String url, String username, String password) thro * @param ignoreCertificateErrors if true will set up the Jersey system ignore SSL certificate errors * @return new {@code GitLabApi} instance configured for a user-specific token * @throws GitLabApiException GitLabApiException if any exception occurs during execution + * @deprecated As of release 4.8.7, will be removed in 4.9.0 */ + @Deprecated public static GitLabApi login(ApiVersion apiVersion, String url, String username, String password, boolean ignoreCertificateErrors) throws GitLabApiException { GitLabApi gitLabApi = new GitLabApi(apiVersion, url, (String)null); @@ -273,7 +412,9 @@ public static GitLabApi login(ApiVersion apiVersion, String url, String username * @param ignoreCertificateErrors if true will set up the Jersey system ignore SSL certificate errors * @return new {@code GitLabApi} instance configured for a user-specific token * @throws GitLabApiException GitLabApiException if any exception occurs during execution + * @deprecated As of release 4.8.7, will be removed in 4.9.0 */ + @Deprecated public static GitLabApi login(String url, String username, String password, boolean ignoreCertificateErrors) throws GitLabApiException { return (GitLabApi.login(ApiVersion.V4, url, username, password, ignoreCertificateErrors)); } @@ -287,7 +428,7 @@ public static GitLabApi login(String url, String username, String password, bool * @param password password for a given {@code username} * @return new {@code GitLabApi} instance configured for a user-specific token * @throws GitLabApiException GitLabApiException if any exception occurs during execution - * @deprecated As of release 4.2.0, replaced by {@link #login(String, String, String)}, will be removed in 5.0.0 + * @deprecated As of release 4.2.0, replaced by {@link #login(String, String, String)}, will be removed in 4.9.0 */ @Deprecated public static GitLabApi create(String url, String username, String password) throws GitLabApiException { @@ -301,8 +442,9 @@ public static GitLabApi create(String url, String username, String password) thr * NOTE: For GitLab servers 10.2 and above this method will always return null. * * @return the Session instance - * @deprecated This method will be removed in Release 5.0.0 + * @deprecated This method will be removed in Release 4.9.0 */ + @Deprecated public Session getSession() { return session; } diff --git a/src/main/java/org/gitlab4j/api/GitLabApiClient.java b/src/main/java/org/gitlab4j/api/GitLabApiClient.java index 5e4a49350..003dee75f 100755 --- a/src/main/java/org/gitlab4j/api/GitLabApiClient.java +++ b/src/main/java/org/gitlab4j/api/GitLabApiClient.java @@ -25,6 +25,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; import org.gitlab4j.api.Constants.TokenType; import org.gitlab4j.api.GitLabApi.ApiVersion; @@ -434,6 +435,21 @@ protected Response post(Object payload, Object... pathArgs) throws IOException { return (invocation(url, null).post(entity)); } + /** + * Perform an HTTP POST call with the specified StreamingOutput, MediaType, and path objects, returning + * a ClientResponse instance with the data returned from the endpoint. + * + * @param stream the StreamingOutput instance that contains the POST data + * @param mediaType the content-type of the POST data + * @param pathArgs variable list of arguments used to build the URI + * @return a ClientResponse instance with the data returned from the endpoint + * @throws IOException if an error occurs while constructing the URL + */ + protected Response post(StreamingOutput stream, String mediaType, Object... pathArgs) throws IOException { + URL url = getApiUrl(pathArgs); + return (invocation(url, null).post(Entity.entity(stream, mediaType))); + } + /** * Perform an HTTP PUT call with the specified form data and path objects, returning * a ClientResponse instance with the data returned from the endpoint. diff --git a/src/test/java/org/gitlab4j/api/TestGitLabLogin.java b/src/test/java/org/gitlab4j/api/TestGitLabLogin.java index f8ddbe639..a75a1f889 100644 --- a/src/test/java/org/gitlab4j/api/TestGitLabLogin.java +++ b/src/test/java/org/gitlab4j/api/TestGitLabLogin.java @@ -7,6 +7,7 @@ import org.gitlab4j.api.GitLabApi.ApiVersion; import org.gitlab4j.api.models.Version; +import org.gitlab4j.api.utils.SecretString; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -112,8 +113,8 @@ public void testSessionV3() throws GitLabApiException { @Test public void testSessionFallover() throws GitLabApiException { - assumeFalse(hasSession); + @SuppressWarnings("deprecation") GitLabApi gitLabApi = GitLabApi.login(ApiVersion.V4, TEST_HOST_URL, TEST_LOGIN_USERNAME, TEST_LOGIN_PASSWORD); assertNotNull(gitLabApi); Version version = gitLabApi.getVersion(); @@ -121,11 +122,29 @@ public void testSessionFallover() throws GitLabApiException { } @Test - public void testOauth2Login() throws GitLabApiException { - + public void testOauth2LoginWithStringPassword() throws GitLabApiException { + @SuppressWarnings("deprecation") GitLabApi gitLabApi = GitLabApi.oauth2Login(TEST_HOST_URL, TEST_LOGIN_USERNAME, TEST_LOGIN_PASSWORD, null, null, true); assertNotNull(gitLabApi); Version version = gitLabApi.getVersion(); assertNotNull(version); } + + @Test + public void testOauth2LoginWithCharSequencePassword() throws GitLabApiException { + SecretString password = new SecretString(TEST_LOGIN_PASSWORD); + GitLabApi gitLabApi = GitLabApi.oauth2Login(TEST_HOST_URL, TEST_LOGIN_USERNAME, password, null, null, true); + assertNotNull(gitLabApi); + Version version = gitLabApi.getVersion(); + assertNotNull(version); + } + + @Test + public void testOauth2LoginWithCharArrayPassword() throws GitLabApiException { + char[] password = TEST_LOGIN_PASSWORD.toCharArray(); + GitLabApi gitLabApi = GitLabApi.oauth2Login(TEST_HOST_URL, TEST_LOGIN_USERNAME, password, null, null, true); + assertNotNull(gitLabApi); + Version version = gitLabApi.getVersion(); + assertNotNull(version); + } } From 1d0bfbd371b4be122daee7b15c41042892eea0f0 Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Mon, 12 Mar 2018 16:36:11 -0700 Subject: [PATCH 3/6] Removed debug code (#155). --- .../org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java b/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java index 3c85499c1..6d6ecab58 100644 --- a/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java +++ b/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java @@ -39,8 +39,7 @@ public void write(OutputStream output) throws IOException, WebApplicationExcepti // Output the quoted password writer.append('"'); for (int i = 0, length = password.length(); i < length; i++) { - char c = password.charAt(i); - writer.append(c); + writer.append(password.charAt(i)); } writer.append('"'); From 73464cbe8e82cc88ca4d07609c85c8f32fb1645b Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Mon, 12 Mar 2018 17:17:24 -0700 Subject: [PATCH 4/6] Changed close() to use clearPassword() (#155). --- .../java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java b/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java index 6d6ecab58..214b1a262 100644 --- a/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java +++ b/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java @@ -57,7 +57,7 @@ public void clearPassword() { @Override public void close() { - password.clear(); + clearPassword(); } @Override From b381630212f91b2f84a70b981eac66bc142eac09 Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Mon, 12 Mar 2018 17:40:23 -0700 Subject: [PATCH 5/6] Replaced all instances of str.length() == 0 with str.isEmpty() (#155). --- src/test/java/org/gitlab4j/api/TestGitLabLogin.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/gitlab4j/api/TestGitLabLogin.java b/src/test/java/org/gitlab4j/api/TestGitLabLogin.java index a75a1f889..2b40cd070 100644 --- a/src/test/java/org/gitlab4j/api/TestGitLabLogin.java +++ b/src/test/java/org/gitlab4j/api/TestGitLabLogin.java @@ -48,19 +48,19 @@ public static void setup() { problems = ""; - if (TEST_LOGIN_USERNAME == null || TEST_LOGIN_USERNAME.trim().length() == 0) { + if (TEST_LOGIN_USERNAME == null || TEST_LOGIN_USERNAME.trim().isEmpty()) { problems += "TEST_LOGIN_USERNAME cannot be empty\n"; } - if (TEST_LOGIN_PASSWORD == null || TEST_LOGIN_PASSWORD.trim().length() == 0) { + if (TEST_LOGIN_PASSWORD == null || TEST_LOGIN_PASSWORD.trim().isEmpty()) { problems += "TEST_LOGIN_PASSWORD cannot be empty\n"; } - if (TEST_HOST_URL == null || TEST_HOST_URL.trim().length() == 0) { + if (TEST_HOST_URL == null || TEST_HOST_URL.trim().isEmpty()) { problems += "TEST_HOST_URL cannot be empty\n"; } - if (TEST_PRIVATE_TOKEN == null || TEST_PRIVATE_TOKEN.trim().length() == 0) { + if (TEST_PRIVATE_TOKEN == null || TEST_PRIVATE_TOKEN.trim().isEmpty()) { problems += "TEST_PRIVATE_TOKEN cannot be empty\n"; } From 0b157958666b04ffbbad1ceb25a880316a2fc458 Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Mon, 12 Mar 2018 22:29:14 -0700 Subject: [PATCH 6/6] Changed all occurances of append() to write() (#155). --- .../api/utils/Oauth2LoginStreamingOutput.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java b/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java index 214b1a262..b829315b0 100644 --- a/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java +++ b/src/main/java/org/gitlab4j/api/utils/Oauth2LoginStreamingOutput.java @@ -31,19 +31,19 @@ public Oauth2LoginStreamingOutput(String username, char[] password) { public void write(OutputStream output) throws IOException, WebApplicationException { PrintWriter writer = new PrintWriter(output); - writer.append("{ "); - writer.append("\"grant_type\": \"password\", "); - writer.append("\"username\": \"" + username + "\", "); - writer.append("\"password\": "); + writer.write("{ "); + writer.write("\"grant_type\": \"password\", "); + writer.write("\"username\": \"" + username + "\", "); + writer.write("\"password\": "); // Output the quoted password - writer.append('"'); + writer.write('"'); for (int i = 0, length = password.length(); i < length; i++) { - writer.append(password.charAt(i)); + writer.write(password.charAt(i)); } - writer.append('"'); + writer.write('"'); - writer.append(" }"); + writer.write(" }"); writer.flush(); writer.close(); }