Skip to content

Commit 53f8f8e

Browse files
committed
Initial commit (#155).
1 parent 2267922 commit 53f8f8e

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package org.gitlab4j.api.utils;
2+
3+
import java.io.IOException;
4+
import java.io.OutputStream;
5+
import java.io.PrintWriter;
6+
7+
import javax.ws.rs.WebApplicationException;
8+
import javax.ws.rs.core.StreamingOutput;
9+
10+
/**
11+
* This StreamingOutput implementation is utilized to send a OAuth2 token request
12+
* in a secure manner. The password is never copied to a String, instead it is
13+
* contained in a SecretString that is cleared when an instance of this class is finalized.
14+
*/
15+
public class Oauth2LoginStreamingOutput implements StreamingOutput, AutoCloseable {
16+
17+
private final String username;
18+
private final SecretString password;
19+
20+
public Oauth2LoginStreamingOutput(String username, CharSequence password) {
21+
this.username = username;
22+
this.password = new SecretString(password);
23+
}
24+
25+
public Oauth2LoginStreamingOutput(String username, char[] password) {
26+
this.username = username;
27+
this.password = new SecretString(password);
28+
}
29+
30+
@Override
31+
public void write(OutputStream output) throws IOException, WebApplicationException {
32+
33+
PrintWriter writer = new PrintWriter(output);
34+
writer.append("{ ");
35+
writer.append("\"grant_type\": \"password\", ");
36+
writer.append("\"username\": \"" + username + "\", ");
37+
writer.append("\"password\": ");
38+
39+
// Output the quoted password
40+
writer.append('"');
41+
for (int i = 0, length = password.length(); i < length; i++) {
42+
char c = password.charAt(i);
43+
writer.append(c);
44+
}
45+
writer.append('"');
46+
47+
writer.append(" }");
48+
writer.flush();
49+
writer.close();
50+
}
51+
52+
/**
53+
* Clears the contained password's data.
54+
*/
55+
public void clearPassword() {
56+
password.clear();
57+
}
58+
59+
@Override
60+
public void close() {
61+
password.clear();
62+
}
63+
64+
@Override
65+
public void finalize() throws Throwable {
66+
clearPassword();
67+
super.finalize();
68+
}
69+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.gitlab4j.api.utils;
2+
3+
import java.util.Arrays;
4+
5+
/**
6+
* This class implements a CharSequence that can be cleared of it's contained characters.
7+
* This class is utilized to pass around secrets (passwords) instead of a String instance.
8+
*/
9+
public class SecretString implements CharSequence, AutoCloseable {
10+
11+
private final char[] chars;
12+
13+
public SecretString(CharSequence charSequence) {
14+
15+
int length = charSequence.length();
16+
chars = new char[length];
17+
for (int i = 0; i < length; i++) {
18+
chars[i] = charSequence.charAt(i);
19+
}
20+
}
21+
22+
public SecretString(char[] chars) {
23+
this(chars, 0, chars.length);
24+
}
25+
26+
public SecretString(char[] chars, int start, int end) {
27+
this.chars = new char[end - start];
28+
System.arraycopy(chars, start, this.chars, 0, this.chars.length);
29+
}
30+
31+
@Override
32+
public char charAt(int index) {
33+
return chars[index];
34+
}
35+
36+
@Override
37+
public void close() {
38+
clear();
39+
}
40+
41+
@Override
42+
public int length() {
43+
return chars.length;
44+
}
45+
46+
@Override
47+
public CharSequence subSequence(int start, int end) {
48+
return new SecretString(this.chars, start, end);
49+
}
50+
51+
/**
52+
* Clear the contents of this SecretString instance by setting each character to 0.
53+
* This is automatically done in the finalize() method.
54+
*/
55+
public void clear() {
56+
Arrays.fill(chars, '\0');
57+
}
58+
59+
@Override
60+
public void finalize() throws Throwable {
61+
clear();
62+
super.finalize();
63+
}
64+
}

0 commit comments

Comments
 (0)