Skip to content

Commit 5a44b1d

Browse files
authored
Lazy-loading configuration for MantaClient (#357)
Resolves #311 by reading as many values directly from the config as possible in addition to introducing a new ConfigContext which will manage derived authentication objects: AuthAwareConfigContext. The new class also provides a reload() method for users to indicate that we should regenerate authentication objects. No guarantees are made about the thread-safety of AuthAwareConfigContext.
1 parent 94ed248 commit 5a44b1d

37 files changed

Lines changed: 1485 additions & 478 deletions

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ This project aims to adhere to [Semantic Versioning](http://semver.org/).
1414
`MantaConnectionFactoryConfigurator` containing their custom instance to the
1515
`MantaClient(ConfigContext, MantaConnectionFactoryConfigurator)` constructor. Constructor documentation
1616
explains the benefits and trade offs.
17+
- `MantaClient` now allows for modification of authentication parameters by
18+
[dynamically-reloading configuration state](https://github.com/joyent/java-manta/issues/311). `AuthAwareConfigContext` can
19+
be used to wrap the desired configuration and provides a method to update derived objects atomically.
1720
### Fixed
1821
- Clarify version history of `MantaInputStreamEntity`
1922
- MPU parts which were missing an ETag in their response were

USAGE.md

Lines changed: 92 additions & 73 deletions
Large diffs are not rendered by default.

java-manta-client-unshaded/src/main/java/com/joyent/manta/client/MantaClient.java

Lines changed: 66 additions & 108 deletions
Large diffs are not rendered by default.

java-manta-client-unshaded/src/main/java/com/joyent/manta/client/MantaDirectoryListingIterator.java

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,6 @@ public class MantaDirectoryListingIterator implements Iterator<Map<String, Objec
5656
*/
5757
private final int pagingSize;
5858

59-
/**
60-
* Base Manta URL that all paths are appended to.
61-
*/
62-
private final String url;
63-
6459
/**
6560
* Path to directory in which we will iterate through its contents.
6661
*/
@@ -111,20 +106,32 @@ public class MantaDirectoryListingIterator implements Iterator<Map<String, Objec
111106
/**
112107
* Create a new instance of a directory list iterator.
113108
*
114-
* @param url base Manta URL that all paths are appended to
109+
* @param url ignored
115110
* @param path path to directory in which we will iterate through its contents
116111
* @param httpHelper HTTP request helper class
117112
* @param pagingSize size of result set requested against the Manta API (2-1024).
118113
*/
114+
@Deprecated
119115
public MantaDirectoryListingIterator(final String url,
120116
final String path,
121117
final HttpHelper httpHelper,
122118
final int pagingSize) {
123-
Validate.notNull(url, "URL must not be null");
119+
this(path, httpHelper, pagingSize);
120+
}
121+
122+
/**
123+
* Create a new instance of a directory list iterator.
124+
*
125+
* @param path path to directory in which we will iterate through its contents
126+
* @param httpHelper HTTP request helper class
127+
* @param pagingSize size of result set requested against the Manta API (2-1024).
128+
*/
129+
public MantaDirectoryListingIterator(final String path,
130+
final HttpHelper httpHelper,
131+
final int pagingSize) {
124132
Validate.notBlank(path, "Path must not be blank");
125133
Validate.notNull(httpHelper, "HTTP help must not be null");
126134

127-
this.url = url;
128135
this.path = path;
129136
this.httpHelper = httpHelper;
130137

@@ -146,11 +153,10 @@ public MantaDirectoryListingIterator(final String url,
146153
private synchronized void selectReader() throws IOException {
147154
if (lastMarker == null) {
148155
String query = String.format("?limit=%d", pagingSize);
149-
String uri = url + formatPath(path) + query;
150-
HttpGet get = new HttpGet(uri);
156+
final HttpGet request = httpHelper.getRequestFactory().get(formatPath(path) + query);
151157

152158
IOUtils.closeQuietly(currentResponse);
153-
currentResponse = httpHelper.executeRequest(get, null);
159+
currentResponse = httpHelper.executeRequest(request, null);
154160
HttpEntity entity = currentResponse.getEntity();
155161
String contentType = entity.getContentType().getValue();
156162

@@ -166,13 +172,12 @@ private synchronized void selectReader() throws IOException {
166172
} else {
167173
String query = String.format("?limit=%d&marker=%s",
168174
pagingSize, URLEncoder.encode(lastMarker, "UTF-8"));
169-
String uri = url + formatPath(path) + query;
170-
HttpGet get = new HttpGet(uri);
175+
final HttpGet request = httpHelper.getRequestFactory().get(formatPath(path) + query);
171176

172177
IOUtils.closeQuietly(br);
173178
IOUtils.closeQuietly(currentResponse);
174179

175-
currentResponse = httpHelper.executeRequest(get, null);
180+
currentResponse = httpHelper.executeRequest(request, null);
176181
HttpEntity entity = currentResponse.getEntity();
177182
Reader streamReader = new InputStreamReader(entity.getContent(),
178183
StandardCharsets.UTF_8.name());

java-manta-client-unshaded/src/main/java/com/joyent/manta/client/UriSigner.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import com.joyent.http.signature.KeyFingerprinter;
1111
import com.joyent.http.signature.ThreadLocalSigner;
12+
import com.joyent.manta.config.AuthAwareConfigContext;
1213
import com.joyent.manta.config.ConfigContext;
1314
import org.apache.commons.lang3.StringUtils;
1415
import org.apache.commons.lang3.Validate;
@@ -28,32 +29,31 @@
2829
* @since 3.0.0
2930
*/
3031
public class UriSigner {
31-
/**
32-
* Manta configuration object.
33-
*/
34-
private final ConfigContext config;
3532

3633
/**
37-
* HTTP signature generator instance.
34+
* Authentication Helper which provides objects needed for signing.
3835
*/
39-
private final ThreadLocalSigner signer;
36+
private final AuthAwareConfigContext authConfig;
4037

4138
/**
42-
* Cryptographic key pair used to sign URIs.
43-
*/
44-
private final KeyPair keyPair;
45-
46-
/**
47-
* Creates a new instance.
39+
* DEPRECATED: Creates an instance based on a new authentication context.
4840
*
4941
* @param config Manta configuration context
5042
* @param keyPair cryptographic key pair used to sign URIs
5143
* @param signer Signer configured to work with the the given keyPair
5244
*/
45+
@Deprecated
5346
public UriSigner(final ConfigContext config, final KeyPair keyPair, final ThreadLocalSigner signer) {
54-
this.config = config;
55-
this.keyPair = keyPair;
56-
this.signer = signer;
47+
this(new AuthAwareConfigContext(config));
48+
}
49+
50+
/**
51+
* Creates a new instance. This constructor is package-private because this class is being made package private.
52+
*
53+
* @param authConfig Manta authentication context
54+
*/
55+
UriSigner(final AuthAwareConfigContext authConfig) {
56+
this.authConfig = authConfig;
5757
}
5858

5959
/**
@@ -77,11 +77,14 @@ public URI signURI(final URI uri, final String method, final long expires)
7777
"Query must be null or empty. URI: %s", uri);
7878
}
7979

80+
final ThreadLocalSigner signer = authConfig.getSigner();
81+
8082
final String charset = "UTF-8";
8183
final String algorithm = signer.get().getHttpHeaderAlgorithm().toUpperCase();
82-
final String keyId = String.format("/%s/keys/%s",
83-
config.getMantaUser(),
84-
KeyFingerprinter.md5Fingerprint(keyPair));
84+
final String keyId = String.format(
85+
"/%s/keys/%s",
86+
authConfig.getMantaUser(),
87+
KeyFingerprinter.md5Fingerprint(authConfig.getKeyPair()));
8588

8689
final String keyIdEncoded = URLEncoder.encode(keyId, charset);
8790

@@ -95,10 +98,11 @@ public URI signURI(final URI uri, final String method, final long expires)
9598

9699

97100
StringBuilder request = new StringBuilder();
98-
final byte[] sigBytes = sigText.toString().getBytes(
99-
StandardCharsets.UTF_8);
100-
final byte[] signed = signer.get().sign(config.getMantaUser(),
101-
keyPair, sigBytes);
101+
final byte[] sigBytes = sigText.toString().getBytes(StandardCharsets.UTF_8);
102+
103+
// first parameter isn't actually used for anything, just checked for nullness
104+
final byte[] signed = signer.get().sign("", authConfig.getKeyPair(), sigBytes);
105+
102106
final String encoded = new String(Base64.encode(signed), charset);
103107
final String urlEncoded = URLEncoder.encode(encoded, charset);
104108

0 commit comments

Comments
 (0)