Skip to content

Commit b173c5b

Browse files
authored
Family refresh token support (#37)
1 parent d3ef054 commit b173c5b

34 files changed

+390
-146
lines changed

src/main/java/com/microsoft/aad/msal4j/Account.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class Account {
4545
@SerializedName("environment")
4646
protected String environment;
4747

48+
@EqualsAndHashCode.Exclude
4849
@SerializedName("realm")
4950
protected String realm;
5051

src/main/java/com/microsoft/aad/msal4j/AccountsSupplier.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,38 +23,41 @@
2323

2424
package com.microsoft.aad.msal4j;
2525

26-
import java.util.Collection;
26+
import java.net.URL;
27+
import java.util.Set;
2728
import java.util.concurrent.CompletionException;
2829
import java.util.function.Supplier;
2930

30-
class AccountsSupplier implements Supplier<Collection<Account>> {
31+
class AccountsSupplier implements Supplier<Set<Account>> {
3132

32-
ClientDataHttpHeaders headers;
3333
ClientApplicationBase clientApplication;
34+
MsalRequest msalRequest;
3435

35-
AccountsSupplier(ClientApplicationBase clientApplication) {
36+
AccountsSupplier(ClientApplicationBase clientApplication, MsalRequest msalRequest) {
3637

3738
this.clientApplication = clientApplication;
38-
this.headers = new ClientDataHttpHeaders(clientApplication.correlationId());
39+
this.msalRequest = msalRequest;
3940
}
4041

4142
@Override
42-
public Collection<Account> get() {
43-
Collection<Account> accounts;
43+
public Set<Account> get() {
4444
try {
4545
InstanceDiscoveryMetadataEntry instanceDiscoveryData =
46-
AadInstanceDiscovery.cache.get(clientApplication.authenticationAuthority.host());
46+
AadInstanceDiscovery.GetMetadataEntry
47+
(new URL(clientApplication.authority()),
48+
clientApplication.validateAuthority(),
49+
msalRequest,
50+
clientApplication.getServiceBundle());
4751

48-
accounts = clientApplication.tokenCache.getAccounts
52+
return clientApplication.tokenCache.getAccounts
4953
(clientApplication.clientId(), instanceDiscoveryData.getAliasesSet());
5054

5155
} catch (Exception ex) {
5256
clientApplication.log.error(
5357
LogHelper.createMessage("Execution of " + this.getClass() + " failed.",
54-
this.headers.getHeaderCorrelationIdValue()), ex);
58+
msalRequest.headers().getHeaderCorrelationIdValue()), ex);
5559

5660
throw new CompletionException(ex);
5761
}
58-
return accounts;
5962
}
6063
}

src/main/java/com/microsoft/aad/msal4j/AcquireTokenSilentSupplier.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323

2424
package com.microsoft.aad.msal4j;
2525

26+
import java.util.Optional;
27+
import java.util.Set;
28+
2629
class AcquireTokenSilentSupplier extends AuthenticationResultSupplier {
2730

2831
private SilentRequest silentRequest;
@@ -35,7 +38,6 @@ class AcquireTokenSilentSupplier extends AuthenticationResultSupplier {
3538

3639
@Override
3740
AuthenticationResult execute() throws Exception {
38-
3941
Authority requestAuthority = silentRequest.requestAuthority();
4042
if(requestAuthority.authorityType != AuthorityType.B2C){
4143
requestAuthority =
@@ -52,10 +54,7 @@ AuthenticationResult execute() throws Exception {
5254
return res;
5355
}
5456

55-
if (StringHelper.isBlank(res.refreshToken())) {
56-
return null;
57-
} else {
58-
57+
if (!StringHelper.isBlank(res.refreshToken())) {
5958
RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest(
6059
RefreshTokenParameters.builder(silentRequest.parameters().scopes(), res.refreshToken()).build(),
6160
silentRequest.application(),
@@ -65,6 +64,8 @@ AuthenticationResult execute() throws Exception {
6564
new AcquireTokenByAuthorizationGrantSupplier(clientApplication, refreshTokenRequest, requestAuthority);
6665

6766
return acquireTokenByAuthorisationGrantSupplier.execute();
67+
} else {
68+
return null;
6869
}
6970
}
7071
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.microsoft.aad.msal4j;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import lombok.Getter;
5+
import lombok.Setter;
6+
import lombok.experimental.Accessors;
7+
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
@Accessors(fluent = true)
12+
@Getter
13+
@Setter
14+
public class AppMetadataCacheEntity {
15+
16+
public static final String APP_METADATA_CACHE_ENTITY_ID = "appmetadata";
17+
18+
@SerializedName("client_id")
19+
private String clientId;
20+
21+
@SerializedName("environment")
22+
private String environment;
23+
24+
@SerializedName("family_id")
25+
private String familyId;
26+
27+
String getKey(){
28+
List<String> keyParts = new ArrayList<>();
29+
30+
keyParts.add(APP_METADATA_CACHE_ENTITY_ID);
31+
keyParts.add(environment);
32+
keyParts.add(clientId);
33+
34+
return String.join(Constants.CACHE_KEY_SEPARATOR, keyParts).toLowerCase();
35+
}
36+
}

src/main/java/com/microsoft/aad/msal4j/AuthenticationResult.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public final class AuthenticationResult implements Serializable {
5252

5353
private final String refreshToken;
5454

55+
private final String familyId;
56+
5557
private final String idToken;
5658

5759
@Getter(value = AccessLevel.PACKAGE, lazy = true)

src/main/java/com/microsoft/aad/msal4j/AuthenticationResultSupplier.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.net.URL;
3232
import java.security.MessageDigest;
3333
import java.security.NoSuchAlgorithmException;
34+
import java.util.Set;
3435
import java.util.concurrent.CompletionException;
3536
import java.util.function.Supplier;
3637

src/main/java/com/microsoft/aad/msal4j/ClientApplicationBase.java

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,7 @@
3232
import java.net.MalformedURLException;
3333
import java.net.Proxy;
3434
import java.net.URL;
35-
import java.util.HashMap;
36-
import java.util.List;
37-
import java.util.Collection;
38-
import java.util.UUID;
35+
import java.util.*;
3936
import java.util.concurrent.CompletableFuture;
4037
import java.util.concurrent.ExecutorService;
4138
import java.util.concurrent.Future;
@@ -151,7 +148,7 @@ public CompletableFuture<AuthenticationResult> acquireToken(AuthorizationCodePar
151148
AuthorizationCodeRequest authorizationCodeRequest = new AuthorizationCodeRequest(
152149
parameters,
153150
this,
154-
createRequestContext(AcquireTokenPublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE));
151+
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE));
155152

156153
return this.executeRequest(authorizationCodeRequest);
157154
}
@@ -174,7 +171,7 @@ public CompletableFuture<AuthenticationResult> acquireToken(RefreshTokenParamete
174171
RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest(
175172
parameters,
176173
this,
177-
createRequestContext(AcquireTokenPublicApi.ACQUIRE_TOKEN_BY_REFRESH_TOKEN));
174+
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_REFRESH_TOKEN));
178175

179176
return executeRequest(refreshTokenRequest);
180177
}
@@ -192,46 +189,6 @@ CompletableFuture<AuthenticationResult> executeRequest(
192189
return future;
193190
}
194191

195-
/**
196-
* Returns accounts for which there is an cached SSO (RT token)
197-
*/
198-
public CompletableFuture<AuthenticationResult> acquireTokenSilently(SilentParameters parameters)
199-
throws MalformedURLException {
200-
201-
validateNotNull("parameters", parameters);
202-
203-
SilentRequest silentRequest = new SilentRequest(
204-
parameters,
205-
this,
206-
createRequestContext(AcquireTokenPublicApi.ACQUIRE_TOKEN_SILENTLY));
207-
208-
return executeRequest(silentRequest);
209-
}
210-
211-
/**
212-
* Returns accounts for which there is an cached SSO (RT token)
213-
*/
214-
public CompletableFuture<Collection<Account>> getAccounts() {
215-
AccountsSupplier supplier = new AccountsSupplier(this);
216-
217-
CompletableFuture<Collection<Account>> future =
218-
serviceBundle.getExecutorService() != null ? CompletableFuture.supplyAsync(supplier, serviceBundle.getExecutorService())
219-
: CompletableFuture.supplyAsync(supplier);
220-
return future;
221-
}
222-
223-
/**
224-
* Remove all credentials from cache related to the account
225-
*/
226-
public CompletableFuture removeAccount(Account account) {
227-
RemoveAccountRunnable runnable = new RemoveAccountRunnable(this, account);
228-
229-
CompletableFuture<Void> future =
230-
serviceBundle.getExecutorService() != null ? CompletableFuture.runAsync(runnable, serviceBundle.getExecutorService())
231-
: CompletableFuture.runAsync(runnable);
232-
return future;
233-
}
234-
235192
AuthenticationResult acquireTokenCommon(MsalRequest msalRequest, Authority requestAuthority)
236193
throws Exception {
237194

@@ -278,7 +235,7 @@ private AuthenticationResultSupplier getAuthenticationResultSupplier(MsalRequest
278235
return supplier;
279236
}
280237

281-
RequestContext createRequestContext(AcquireTokenPublicApi publicApi) {
238+
RequestContext createRequestContext(PublicApi publicApi) {
282239
return new RequestContext(
283240
clientId,
284241
correlationId(),
@@ -289,6 +246,50 @@ ServiceBundle getServiceBundle() {
289246
return serviceBundle;
290247
}
291248

249+
/**
250+
* Returns accounts for which there is an cached SSO (RT token)
251+
*/
252+
public CompletableFuture<AuthenticationResult> acquireTokenSilently(SilentParameters parameters)
253+
throws MalformedURLException {
254+
255+
validateNotNull("parameters", parameters);
256+
257+
SilentRequest silentRequest = new SilentRequest(
258+
parameters,
259+
this,
260+
createRequestContext(PublicApi.ACQUIRE_TOKEN_SILENTLY));
261+
262+
return executeRequest(silentRequest);
263+
}
264+
265+
/**
266+
* Returns accounts for which there is an cached SSO (RT token)
267+
*/
268+
public CompletableFuture<Set<Account>> getAccounts() {
269+
MsalRequest msalRequest =
270+
new MsalRequest(this, null,
271+
createRequestContext(PublicApi.GET_ACCOUNTS)){};
272+
273+
AccountsSupplier supplier = new AccountsSupplier(this, msalRequest);
274+
275+
CompletableFuture<Set<Account>> future =
276+
serviceBundle.getExecutorService() != null ? CompletableFuture.supplyAsync(supplier, serviceBundle.getExecutorService())
277+
: CompletableFuture.supplyAsync(supplier);
278+
return future;
279+
}
280+
281+
/**
282+
* Remove all credentials from cache related to account
283+
*/
284+
public CompletableFuture removeAccount(Account account) {
285+
RemoveAccountRunnable runnable = new RemoveAccountRunnable(this, account);
286+
287+
CompletableFuture<Void> future =
288+
serviceBundle.getExecutorService() != null ? CompletableFuture.runAsync(runnable, serviceBundle.getExecutorService())
289+
: CompletableFuture.runAsync(runnable);
290+
return future;
291+
}
292+
292293
protected static String canonicalizeUrl(String authority) {
293294
authority = authority.toLowerCase();
294295

src/main/java/com/microsoft/aad/msal4j/ConfidentialClientApplication.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import java.util.HashMap;
3636
import java.util.List;
3737
import java.util.Map;
38-
import java.util.Set;
3938
import java.util.concurrent.CompletableFuture;
4039

4140
import static com.microsoft.aad.msal4j.ParameterValidationUtils.validateNotNull;
@@ -59,7 +58,7 @@ public CompletableFuture<AuthenticationResult> acquireToken(ClientCredentialPara
5958
new ClientCredentialRequest(
6059
parameters,
6160
this,
62-
createRequestContext(AcquireTokenPublicApi.ACQUIRE_TOKEN_FOR_CLIENT));
61+
createRequestContext(PublicApi.ACQUIRE_TOKEN_FOR_CLIENT));
6362

6463
return this.executeRequest(clientCredentialRequest);
6564
}
@@ -83,7 +82,7 @@ public CompletableFuture<AuthenticationResult> acquireToken(OnBehalfOfParameters
8382
OnBehalfOfRequest oboRequest = new OnBehalfOfRequest(
8483
parameters,
8584
this,
86-
createRequestContext(AcquireTokenPublicApi.ACQUIRE_TOKEN_ON_BEHALF_OF));
85+
createRequestContext(PublicApi.ACQUIRE_TOKEN_ON_BEHALF_OF));
8786

8887
return this.executeRequest(oboRequest);
8988
}

src/main/java/com/microsoft/aad/msal4j/AcquireTokenPublicApi.java renamed to src/main/java/com/microsoft/aad/msal4j/PublicApi.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
package com.microsoft.aad.msal4j;
2525

26-
enum AcquireTokenPublicApi {
26+
enum PublicApi {
2727
// TODO finalize api ids
2828
ACQUIRE_TOKEN_BY_REFRESH_TOKEN(82),
2929
ACQUIRE_TOKEN_BY_USERNAME_PASSWORD(300),
@@ -32,11 +32,12 @@ enum AcquireTokenPublicApi {
3232
ACQUIRE_TOKEN_BY_DEVICE_CODE_FLOW(620),
3333
ACQUIRE_TOKEN_FOR_CLIENT(729),
3434
ACQUIRE_TOKEN_BY_AUTHORIZATION_CODE(831),
35-
ACQUIRE_TOKEN_SILENTLY(800);
35+
ACQUIRE_TOKEN_SILENTLY(800),
36+
GET_ACCOUNTS(801);
3637

3738
private final int apiId;
3839

39-
AcquireTokenPublicApi(int apiId){
40+
PublicApi(int apiId){
4041
this.apiId = apiId;
4142
}
4243

src/main/java/com/microsoft/aad/msal4j/PublicClientApplication.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,8 @@
2727
import com.nimbusds.oauth2.sdk.id.ClientID;
2828
import org.slf4j.LoggerFactory;
2929

30-
import java.util.Set;
3130
import java.util.concurrent.CompletableFuture;
3231
import java.util.concurrent.atomic.AtomicReference;
33-
import java.util.function.Consumer;
3432

3533
import static com.microsoft.aad.msal4j.ParameterValidationUtils.validateNotBlank;
3634
import static com.microsoft.aad.msal4j.ParameterValidationUtils.validateNotNull;
@@ -55,7 +53,7 @@ public CompletableFuture<AuthenticationResult> acquireToken(UserNamePasswordPara
5553
UserNamePasswordRequest userNamePasswordRequest =
5654
new UserNamePasswordRequest(parameters,
5755
this,
58-
createRequestContext(AcquireTokenPublicApi.ACQUIRE_TOKEN_BY_USERNAME_PASSWORD));
56+
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_USERNAME_PASSWORD));
5957

6058
return this.executeRequest(userNamePasswordRequest);
6159
}
@@ -78,7 +76,7 @@ public CompletableFuture<AuthenticationResult> acquireToken(IntegratedWindowsAut
7876
parameters,
7977
this,
8078
createRequestContext(
81-
AcquireTokenPublicApi.ACQUIRE_TOKEN_BY_INTEGRATED_WINDOWS_AUTH));
79+
PublicApi.ACQUIRE_TOKEN_BY_INTEGRATED_WINDOWS_AUTH));
8280

8381
return this.executeRequest(integratedWindowsAuthenticationRequest);
8482
}
@@ -120,7 +118,7 @@ public CompletableFuture<AuthenticationResult> acquireToken(DeviceCodeFlowParame
120118
parameters,
121119
futureReference,
122120
this,
123-
createRequestContext(AcquireTokenPublicApi.ACQUIRE_TOKEN_BY_DEVICE_CODE_FLOW));
121+
createRequestContext(PublicApi.ACQUIRE_TOKEN_BY_DEVICE_CODE_FLOW));
124122

125123
CompletableFuture<AuthenticationResult> future = executeRequest(deviceCodeRequest);
126124
futureReference.set(future);

0 commit comments

Comments
 (0)