Skip to content

Commit a491250

Browse files
authored
Client Core + Core V2 Auth Changes (Azure#44244)
1 parent d26d0ff commit a491250

File tree

20 files changed

+1025
-287
lines changed

20 files changed

+1025
-287
lines changed

sdk/clientcore/core/spotbugs-exclude.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<Class name="io.clientcore.core.http.pipeline.HttpPipelineBuilder" />
2020
<Class name="io.clientcore.core.http.pipeline.HttpPipelineNextPolicy" />
2121
<Class name="io.clientcore.core.http.pipeline.HttpRetryPolicy" />
22+
<Class name="io.clientcore.core.http.pipeline.OAuthBearerTokenAuthenticationPolicy" />
2223
<Class name="io.clientcore.core.implementation.GenericParameterizedType" />
2324
<Class name="io.clientcore.core.implementation.ReflectionUtilsMethodHandle" />
2425
<Class name="io.clientcore.core.implementation.http.HttpPipelineCallState" />
@@ -46,6 +47,7 @@
4647
<Class name="io.clientcore.core.utils.SharedExecutorService" />
4748
<Class name="io.clientcore.core.utils.Union" />
4849
<Class name="io.clientcore.core.utils.configuration.Configuration" />
50+
<Class name="io.clientcore.core.credentials.oauth.OAuthTokenRequestContext" />
4951
</Or>
5052
</Match>
5153
<Match>
@@ -87,6 +89,7 @@
8789
<Bug pattern="DM_CONVERT_CASE" />
8890
<Or>
8991
<Class name="io.clientcore.core.http.models.HttpHeaderName" />
92+
<Class name="io.clientcore.core.credentials.oauth.AccessTokenType" />
9093
<Class name="io.clientcore.core.utils.AuthUtils" />
9194
<Class name="io.clientcore.core.utils.ServerSentEventUtils" />
9295
</Or>
@@ -278,6 +281,10 @@
278281
<Bug pattern="RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT" />
279282
<Class name="io.clientcore.core.serialization.xml.XmlReaderCodesnippetsTests" />
280283
</Match>
284+
<Match>
285+
<Bug pattern="RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT" />
286+
<Class name="io.clientcore.core.credentials.oauth.OAuthTokenRequestContext" />
287+
</Match>
281288
<Match>
282289
<Bug pattern="SERVLET_QUERY_STRING" />
283290
<Class name="io.clientcore.core.shared.HttpClientTestsServer" />
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package io.clientcore.core.credentials.oauth;
5+
6+
import java.time.OffsetDateTime;
7+
8+
/**
9+
* <p>
10+
* Represents an immutable access token with a token string and an expiration time.
11+
* </p>
12+
*
13+
* <p>
14+
* Access Tokens are obtained through the authentication process, where the user or application presents valid
15+
* credentials (either a secret or a managed identity) to the authentication source.
16+
* The authentication source then verifies the credentials and issues an Access Token, which is a time-limited token
17+
* that grants access to the requested resource.
18+
* </p>
19+
*
20+
* <p>
21+
* Once an Access Token is obtained, it can be included in the Authorization header of HTTP requests to
22+
* authenticate and authorize requests.
23+
* </p>
24+
*
25+
* @see io.clientcore.core.credentials
26+
*/
27+
public class AccessToken {
28+
private final String token;
29+
private final OffsetDateTime expiresAt;
30+
private final OffsetDateTime refreshAt;
31+
private final AccessTokenType tokenType;
32+
33+
/**
34+
* Creates an access token instance.
35+
* Defaults to {@link AccessTokenType#BEARER} for {@code tokenType}.
36+
*
37+
* @param token the token string.
38+
* @param expiresAt the expiration time.
39+
*/
40+
public AccessToken(String token, OffsetDateTime expiresAt) {
41+
this(token, expiresAt, null, AccessTokenType.BEARER);
42+
}
43+
44+
/**
45+
* Creates an access token instance.
46+
* Defaults to {@link AccessTokenType#BEARER} for {@code tokenType}.
47+
*
48+
* @param token the token string.
49+
* @param expiresAt the expiration time.
50+
* @param refreshAt the next token refresh time.
51+
*/
52+
public AccessToken(String token, OffsetDateTime expiresAt, OffsetDateTime refreshAt) {
53+
this(token, expiresAt, refreshAt, AccessTokenType.BEARER);
54+
}
55+
56+
/**
57+
* Creates an access token instance.
58+
*
59+
* @param token the token string.
60+
* @param expiresAt the expiration time.
61+
* @param refreshAt the next token refresh time.
62+
* @param tokenType the type of token.
63+
*/
64+
public AccessToken(String token, OffsetDateTime expiresAt, OffsetDateTime refreshAt, AccessTokenType tokenType) {
65+
this.token = token;
66+
this.expiresAt = expiresAt;
67+
this.refreshAt = refreshAt;
68+
this.tokenType = tokenType;
69+
}
70+
71+
/**
72+
* Gets the token.
73+
*
74+
* @return The token.
75+
*/
76+
public String getToken() {
77+
return token;
78+
}
79+
80+
/**
81+
* Gets the time when the token expires, in UTC.
82+
*
83+
* @return The time when the token expires, in UTC.
84+
*/
85+
public OffsetDateTime getExpiresAt() {
86+
return expiresAt;
87+
}
88+
89+
/**
90+
* Gets the time when the token should refresh next, in UTC.
91+
* @return The time when the token should refresh next, in UTC.
92+
*/
93+
public OffsetDateTime getRefreshAt() {
94+
return refreshAt;
95+
}
96+
97+
/**
98+
* Whether the token has expired.
99+
*
100+
* @return Whether the token has expired.
101+
*/
102+
public boolean isExpired() {
103+
return OffsetDateTime.now().isAfter(expiresAt);
104+
}
105+
106+
/**
107+
* Gets the token type.
108+
*
109+
* @return The {@link AccessTokenType} representing the Token Type.
110+
*/
111+
public AccessTokenType getTokenType() {
112+
return tokenType;
113+
}
114+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package io.clientcore.core.credentials.oauth;
5+
6+
import io.clientcore.core.utils.ExpandableEnum;
7+
8+
import java.util.Collection;
9+
import java.util.Map;
10+
import java.util.Objects;
11+
import java.util.concurrent.ConcurrentHashMap;
12+
13+
/**
14+
* Represents Access Token types.
15+
*/
16+
public final class AccessTokenType implements ExpandableEnum<String> {
17+
private static final Map<String, AccessTokenType> VALUES = new ConcurrentHashMap<>();
18+
private final String caseSensitive;
19+
private final String caseInsensitive;
20+
21+
private AccessTokenType(String name) {
22+
this.caseSensitive = name;
23+
this.caseInsensitive = name.toLowerCase();
24+
}
25+
26+
@Override
27+
public String getValue() {
28+
return caseSensitive;
29+
}
30+
31+
/**
32+
* Gets the {@link AccessTokenType} based on the name passed into {@link #fromString(String)}.
33+
*
34+
* @return The token type based on the construction of this {@link AccessTokenType}.
35+
*/
36+
public String getCaseSensitiveName() {
37+
return toString();
38+
}
39+
40+
/**
41+
* Gets the {@link AccessTokenType} lower cased.
42+
*
43+
* @return The {@link AccessTokenType} lower cased.
44+
*/
45+
public String getCaseInsensitiveName() {
46+
return caseInsensitive;
47+
}
48+
49+
/**
50+
* Creates or finds a {@link AccessTokenType} for the passed {@code name}.
51+
*
52+
* <p>{@code null} will be returned if {@code name} is {@code null}.</p>
53+
*
54+
* @param name A name to look for.
55+
*
56+
* @return The corresponding {@link AccessTokenType} of the provided name, or {@code null} if {@code name} was
57+
* {@code null}.
58+
*/
59+
public static AccessTokenType fromString(String name) {
60+
if (name == null) {
61+
return null;
62+
}
63+
64+
AccessTokenType accessTokenType = VALUES.get(name);
65+
66+
if (accessTokenType != null) {
67+
return accessTokenType;
68+
}
69+
70+
return VALUES.computeIfAbsent(name, AccessTokenType::new);
71+
}
72+
73+
/**
74+
* Gets all known {@link AccessTokenType} values.
75+
*
76+
* @return The known {@link AccessTokenType} values.
77+
*/
78+
public static Collection<AccessTokenType> values() {
79+
return VALUES.values();
80+
}
81+
82+
@Override
83+
public String toString() {
84+
return caseSensitive;
85+
}
86+
87+
@Override
88+
public int hashCode() {
89+
return caseInsensitive.hashCode();
90+
}
91+
92+
@Override
93+
public boolean equals(Object obj) {
94+
if (this == obj) {
95+
return true;
96+
}
97+
98+
if (!(obj instanceof AccessTokenType)) {
99+
return false;
100+
}
101+
102+
AccessTokenType other = (AccessTokenType) obj;
103+
104+
return Objects.equals(caseInsensitive, other.caseInsensitive);
105+
}
106+
107+
/**
108+
* The Bearer token type.
109+
*/
110+
public static final AccessTokenType BEARER = fromString("Bearer");
111+
112+
/**
113+
* The Pop token type.
114+
*/
115+
public static final AccessTokenType POP = fromString("Pop");
116+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package io.clientcore.core.credentials.oauth;
5+
6+
/**
7+
* <p>
8+
* OAuth Token Credential interface serves as a fundamental component for managing and providing access tokens.
9+
* </p>
10+
*
11+
* <p>
12+
* The {@link OAuthTokenCredential} interface, offers an API to retrieve an access token that can be used for
13+
* bearer token authentication. The scopes parameter specified as part of {@link OAuthTokenRequestContext} represents
14+
* the resources or permissions required for the token.
15+
* </p>
16+
*
17+
* <p>
18+
* By utilizing the OAuth Token Provider interface, you can abstract the authentication logic away from your
19+
* application code. This allows for flexibility in choosing authentication mechanisms and simplifies the management
20+
* of access tokens, including token caching and refreshing.
21+
* </p>
22+
*
23+
* @see io.clientcore.core.credentials
24+
*/
25+
@FunctionalInterface
26+
public interface OAuthTokenCredential {
27+
28+
/**
29+
* Get a token for a given resource/audience.
30+
*
31+
* @param request the details of the token request
32+
* @return The Access Token
33+
*/
34+
AccessToken getToken(OAuthTokenRequestContext request);
35+
}

0 commit comments

Comments
 (0)