Skip to content

Commit ba3c006

Browse files
authored
Support Prefixes in AzureKeyCredentialPolicy (Azure#35010)
Support Prefixes in AzureKeyCredentialPolicy
1 parent 50ce75d commit ba3c006

File tree

2 files changed

+84
-16
lines changed

2 files changed

+84
-16
lines changed

sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AzureKeyCredentialPolicy.java

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
import com.azure.core.credential.AzureKeyCredential;
77
import com.azure.core.http.HttpHeaderName;
8+
import com.azure.core.http.HttpHeaders;
89
import com.azure.core.http.HttpPipelineCallContext;
910
import com.azure.core.http.HttpPipelineNextPolicy;
1011
import com.azure.core.http.HttpPipelineNextSyncPolicy;
1112
import com.azure.core.http.HttpResponse;
13+
import com.azure.core.util.FluxUtil;
1214
import com.azure.core.util.logging.ClientLogger;
1315
import reactor.core.publisher.Mono;
1416

@@ -25,18 +27,7 @@ public final class AzureKeyCredentialPolicy implements HttpPipelinePolicy {
2527
private static final ClientLogger LOGGER = new ClientLogger(AzureKeyCredentialPolicy.class);
2628
private final HttpHeaderName name;
2729
private final AzureKeyCredential credential;
28-
29-
private final HttpPipelineSyncPolicy inner = new HttpPipelineSyncPolicy() {
30-
@Override
31-
protected void beforeSendingRequest(HttpPipelineCallContext context) {
32-
if ("http".equals(context.getHttpRequest().getUrl().getProtocol())) {
33-
throw LOGGER.logExceptionAsError(
34-
new IllegalStateException("Key credentials require HTTPS to prevent leaking the key."));
35-
}
36-
37-
context.getHttpRequest().setHeader(name, credential.getKey());
38-
}
39-
};
30+
private final String prefix;
4031

4132
/**
4233
* Creates a policy that uses the passed {@link AzureKeyCredential} to set the specified header name.
@@ -47,23 +38,64 @@ protected void beforeSendingRequest(HttpPipelineCallContext context) {
4738
* @throws IllegalArgumentException If {@code name} is empty.
4839
*/
4940
public AzureKeyCredentialPolicy(String name, AzureKeyCredential credential) {
50-
Objects.requireNonNull(credential, "'credential' cannot be null.");
41+
this(name, credential, null);
42+
}
43+
44+
/**
45+
* Creates a policy that uses the passed {@link AzureKeyCredential} to set the specified header name.
46+
* <p>
47+
* The {@code prefix} will be applied before the {@link AzureKeyCredential#getKey()} when setting the header. A
48+
* space will be inserted between {@code prefix} and credential.
49+
*
50+
* @param name The name of the key header that will be set to {@link AzureKeyCredential#getKey()}.
51+
* @param credential The {@link AzureKeyCredential} containing the authorization key to use.
52+
* @param prefix The prefix to apply before the credential, for example "SharedAccessKey credential".
53+
* @throws NullPointerException If {@code name} or {@code credential} is {@code null}.
54+
* @throws IllegalArgumentException If {@code name} is empty.
55+
*/
56+
public AzureKeyCredentialPolicy(String name, AzureKeyCredential credential, String prefix) {
57+
this(validateName(name), Objects.requireNonNull(credential, "'credential' cannot be null."), prefix);
58+
}
59+
60+
private static HttpHeaderName validateName(String name) {
5161
Objects.requireNonNull(name, "'name' cannot be null.");
5262
if (name.isEmpty()) {
5363
throw LOGGER.logExceptionAsError(new IllegalArgumentException("'name' cannot be empty."));
5464
}
5565

56-
this.name = HttpHeaderName.fromString(name);
66+
return HttpHeaderName.fromString(name);
67+
}
68+
69+
AzureKeyCredentialPolicy(HttpHeaderName name, AzureKeyCredential credential, String prefix) {
70+
this.name = name;
5771
this.credential = credential;
72+
this.prefix = prefix != null ? prefix.trim() : null;
5873
}
5974

6075
@Override
6176
public Mono<HttpResponse> process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
62-
return inner.process(context, next);
77+
if ("http".equals(context.getHttpRequest().getUrl().getProtocol())) {
78+
return FluxUtil.monoError(LOGGER,
79+
new IllegalStateException("Key credentials require HTTPS to prevent leaking the key."));
80+
}
81+
82+
setCredential(context.getHttpRequest().getHeaders());
83+
return next.process();
6384
}
6485

6586
@Override
6687
public HttpResponse processSync(HttpPipelineCallContext context, HttpPipelineNextSyncPolicy next) {
67-
return inner.processSync(context, next);
88+
if ("http".equals(context.getHttpRequest().getUrl().getProtocol())) {
89+
throw LOGGER.logExceptionAsError(
90+
new IllegalStateException("Key credentials require HTTPS to prevent leaking the key."));
91+
}
92+
93+
setCredential(context.getHttpRequest().getHeaders());
94+
return next.processSync();
95+
}
96+
97+
void setCredential(HttpHeaders headers) {
98+
String credential = this.credential.getKey();
99+
headers.set(name, (prefix == null) ? credential : prefix + " " + credential);
68100
}
69101
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.core.http.policy;
5+
6+
import com.azure.core.credential.AzureKeyCredential;
7+
import com.azure.core.http.HttpHeaderName;
8+
import com.azure.core.http.HttpHeaders;
9+
import org.junit.jupiter.params.ParameterizedTest;
10+
import org.junit.jupiter.params.provider.Arguments;
11+
import org.junit.jupiter.params.provider.MethodSource;
12+
13+
import java.util.stream.Stream;
14+
15+
import static org.junit.jupiter.api.Assertions.assertEquals;
16+
17+
public class AzureKeyCredentialPolicyTests {
18+
@ParameterizedTest
19+
@MethodSource("setCredentialSupplier")
20+
public void setCredential(AzureKeyCredentialPolicy policy, String expectedHeader) {
21+
HttpHeaders headers = new HttpHeaders();
22+
policy.setCredential(headers);
23+
assertEquals(expectedHeader, headers.getValue(HttpHeaderName.AUTHORIZATION));
24+
}
25+
26+
private static Stream<Arguments> setCredentialSupplier() {
27+
AzureKeyCredential credential = new AzureKeyCredential("asecret");
28+
return Stream.of(
29+
Arguments.of(new AzureKeyCredentialPolicy(HttpHeaderName.AUTHORIZATION, credential, null), "asecret"),
30+
Arguments.of(new AzureKeyCredentialPolicy(HttpHeaderName.AUTHORIZATION, credential, "SharedKeyCredential"),
31+
"SharedKeyCredential asecret"),
32+
Arguments.of(new AzureKeyCredentialPolicy(HttpHeaderName.AUTHORIZATION, credential, "SharedKeyCredential "),
33+
"SharedKeyCredential asecret")
34+
);
35+
}
36+
}

0 commit comments

Comments
 (0)