Skip to content

Commit 8fd83a8

Browse files
author
sgonzalezMSFT
committed
Add ClientAssertion API to ClientCredentialFactory
1 parent ecbc892 commit 8fd83a8

File tree

12 files changed

+137
-63
lines changed

12 files changed

+137
-63
lines changed

src/integrationtest/java/com.microsoft.aad.msal4j/AcquireTokenSilentIT.java

Lines changed: 86 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
package com.microsoft.aad.msal4j;
55

6+
import labapi.AppIdentityProvider;
67
import labapi.FederationProvider;
78
import labapi.LabResponse;
89
import labapi.LabUserProvider;
@@ -13,6 +14,10 @@
1314

1415
import java.util.Collections;
1516
import java.util.Set;
17+
import java.util.concurrent.ExecutionException;
18+
19+
import static com.microsoft.aad.msal4j.TestConstants.GRAPH_DEFAULT_SCOPE;
20+
import static com.microsoft.aad.msal4j.TestConstants.KEYVAULT_DEFAULT_SCOPE;
1621

1722
public class AcquireTokenSilentIT {
1823
private LabUserProvider labUserProvider;
@@ -151,43 +156,80 @@ public void acquireTokenSilent_MultipleAccountsInCache_UseCorrectAccount() throw
151156
Assert.assertEquals(result.account().username(), labResponse.getUser().getUpn());
152157
}
153158

154-
private IPublicClientApplication getPublicClientApplicationWithTokensInCache()
155-
throws Exception {
159+
@Test
160+
public void acquireTokenSilent_usingCommonAuthority_returnCachedAt() throws Exception {
161+
acquireTokenSilent_returnCachedTokens(TestConstants.ORGANIZATIONS_AUTHORITY);
162+
}
163+
164+
@Test
165+
public void acquireTokenSilent_usingTenantSpecificAuthority_returnCachedAt() throws Exception {
156166
LabResponse labResponse = labUserProvider.getDefaultUser(
157167
NationalCloud.AZURE_CLOUD,
158168
false);
159-
String password = labUserProvider.getUserPassword(labResponse.getUser());
169+
String tenantSpecificAuthority = TestConstants.MICROSOFT_AUTHORITY_HOST + labResponse.getUser().getTenantId();
160170

161-
PublicClientApplication pca = new PublicClientApplication.Builder(
162-
labResponse.getAppId()).
163-
authority(TestConstants.ORGANIZATIONS_AUTHORITY).
164-
build();
171+
acquireTokenSilent_returnCachedTokens(tenantSpecificAuthority);
172+
}
165173

166-
pca.acquireToken(UserNamePasswordParameters.
167-
builder(Collections.singleton(TestConstants.GRAPH_DEFAULT_SCOPE),
168-
labResponse.getUser().getUpn(),
169-
password.toCharArray())
174+
175+
@Test
176+
public void acquireTokenSilent_ConfidentialClient_acquireTokenSilent() throws Exception{
177+
178+
IConfidentialClientApplication cca = getConfidentialClientApplications();
179+
180+
IAuthenticationResult result = cca.acquireToken(ClientCredentialParameters
181+
.builder(Collections.singleton(KEYVAULT_DEFAULT_SCOPE))
170182
.build())
171183
.get();
172-
return pca;
184+
185+
Assert.assertNotNull(result);
186+
Assert.assertNotNull(result.accessToken());
187+
188+
String cachedAt = result.accessToken();
189+
190+
result = cca.acquireTokenSilently(SilentParameters
191+
.builder(Collections.singleton(KEYVAULT_DEFAULT_SCOPE))
192+
.build())
193+
.get();
194+
195+
Assert.assertNotNull(result);
196+
Assert.assertEquals(result.accessToken(), cachedAt);
173197
}
174198

175-
@Test
176-
private void acquireTokenSilent_usingCommonAuthority_returnCachedAt() throws Exception {
177-
acquireTokenSilent_returnCachedTokens(TestConstants.ORGANIZATIONS_AUTHORITY);
199+
@Test(expectedExceptions = ExecutionException.class)
200+
public void acquireTokenSilent_ConfidentialClient_acquireTokenSilentDifferentScopeThrowsException()
201+
throws Exception {
202+
203+
IConfidentialClientApplication cca = getConfidentialClientApplications();
204+
205+
IAuthenticationResult result = cca.acquireToken(ClientCredentialParameters
206+
.builder(Collections.singleton(KEYVAULT_DEFAULT_SCOPE))
207+
.build())
208+
.get();
209+
210+
Assert.assertNotNull(result);
211+
Assert.assertNotNull(result.accessToken());
212+
213+
//Acquiring token for different scope, expect exception to be thrown
214+
cca.acquireTokenSilently(SilentParameters
215+
.builder(Collections.singleton(GRAPH_DEFAULT_SCOPE))
216+
.build())
217+
.get();
178218
}
179219

180-
@Test
181-
private void acquireTokenSilent_usingTenantSpecificAuthority_returnCachedAt() throws Exception {
182-
LabResponse labResponse = labUserProvider.getDefaultUser(
183-
NationalCloud.AZURE_CLOUD,
184-
false);
185-
String tenantSpecificAuthority = TestConstants.MICROSOFT_AUTHORITY_HOST + labResponse.getUser().getTenantId();
220+
private IConfidentialClientApplication getConfidentialClientApplications() throws Exception{
221+
AppIdentityProvider appProvider = new AppIdentityProvider();
222+
final String clientId = appProvider.getDefaultLabId();
223+
final String password = appProvider.getDefaultLabPassword();
224+
IClientCredential credential = ClientCredentialFactory.createFromSecret(password);
186225

187-
acquireTokenSilent_returnCachedTokens(tenantSpecificAuthority);
226+
return ConfidentialClientApplication.builder(
227+
clientId, credential).
228+
authority(TestConstants.MICROSOFT_AUTHORITY).
229+
build();
188230
}
189231

190-
void acquireTokenSilent_returnCachedTokens(String authority) throws Exception {
232+
private void acquireTokenSilent_returnCachedTokens(String authority) throws Exception {
191233

192234
LabResponse labResponse = labUserProvider.getDefaultUser(
193235
NationalCloud.AZURE_CLOUD,
@@ -217,4 +259,25 @@ void acquireTokenSilent_returnCachedTokens(String authority) throws Exception {
217259
Assert.assertNotNull(silentAuthResult);
218260
Assert.assertEquals(interactiveAuthResult.accessToken(), silentAuthResult.accessToken());
219261
}
262+
263+
private IPublicClientApplication getPublicClientApplicationWithTokensInCache()
264+
throws Exception {
265+
LabResponse labResponse = labUserProvider.getDefaultUser(
266+
NationalCloud.AZURE_CLOUD,
267+
false);
268+
String password = labUserProvider.getUserPassword(labResponse.getUser());
269+
270+
PublicClientApplication pca = new PublicClientApplication.Builder(
271+
labResponse.getAppId()).
272+
authority(TestConstants.ORGANIZATIONS_AUTHORITY).
273+
build();
274+
275+
pca.acquireToken(
276+
UserNamePasswordParameters.builder(
277+
Collections.singleton(TestConstants.GRAPH_DEFAULT_SCOPE),
278+
labResponse.getUser().getUpn(),
279+
password.toCharArray())
280+
.build()).get();
281+
return pca;
282+
}
220283
}

src/integrationtest/java/com.microsoft.aad.msal4j/AuthorizationCodeIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ private IAuthenticationResult acquireTokenInteractiveB2C(LabResponse labResponse
247247
String authCode) {
248248
IAuthenticationResult result;
249249
try{
250-
IClientCredential credential = ClientCredentialFactory.create("");
250+
IClientCredential credential = ClientCredentialFactory.createFromSecret("");
251251
ConfidentialClientApplication cca = ConfidentialClientApplication.builder(
252252
labResponse.getAppId(),
253253
credential)

src/integrationtest/java/com.microsoft.aad.msal4j/ClientCredentialsIT.java

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
@Test
2525
public class ClientCredentialsIT {
26+
2627
@Test
2728
public void acquireTokenClientCredentials_AsymmetricKeyCredential() throws Exception{
2829
String clientId = "55e7e5af-ca53-482d-9aa3-5cb1cc8eecb5";
@@ -35,7 +36,24 @@ public void acquireTokenClientCredentials_ClientSecret() throws Exception{
3536
AppIdentityProvider appProvider = new AppIdentityProvider();
3637
final String clientId = appProvider.getDefaultLabId();
3738
final String password = appProvider.getDefaultLabPassword();
38-
IClientCredential credential = ClientCredentialFactory.create(password);
39+
IClientCredential credential = ClientCredentialFactory.createFromSecret(password);
40+
41+
assertAcquireTokenCommon(clientId, credential);
42+
}
43+
44+
@Test
45+
public void acquireTokenClientCredentials_ClientAssertion() throws Exception{
46+
String clientId = "55e7e5af-ca53-482d-9aa3-5cb1cc8eecb5";
47+
IClientCredential certificateFromKeyStore = getCertificateFromKeyStore();
48+
49+
ClientAssertion clientAssertion = JwtHelper.buildJwt(
50+
clientId,
51+
(AsymmetricKeyCredential) certificateFromKeyStore,
52+
"https://login.microsoftonline.com/common/oauth2/v2.0/token");
53+
54+
55+
IClientCredential credential = ClientCredentialFactory.createFromClientAssertion(
56+
clientAssertion.assertion());
3957

4058
assertAcquireTokenCommon(clientId, credential);
4159
}
@@ -53,23 +71,6 @@ private void assertAcquireTokenCommon(String clientId, IClientCredential credent
5371

5472
Assert.assertNotNull(result);
5573
Assert.assertNotNull(result.accessToken());
56-
57-
String cachedAt = result.accessToken();
58-
59-
result = cca.acquireTokenSilently(SilentParameters
60-
.builder(Collections.singleton(GRAPH_DEFAULT_SCOPE))
61-
.build())
62-
.get();
63-
64-
Assert.assertNull(result);
65-
66-
result = cca.acquireTokenSilently(SilentParameters
67-
.builder(Collections.singleton(KEYVAULT_DEFAULT_SCOPE))
68-
.build())
69-
.get();
70-
71-
Assert.assertNotNull(result);
72-
Assert.assertEquals(result.accessToken(), cachedAt);
7374
}
7475

7576

@@ -84,6 +85,6 @@ private IClientCredential getCertificateFromKeyStore() throws
8485
X509Certificate publicCertificate = (X509Certificate)keystore.getCertificate(
8586
certificateAlias);
8687

87-
return ClientCredentialFactory.create(key, publicCertificate);
88+
return ClientCredentialFactory.createFromCertificate(key, publicCertificate);
8889
}
8990
}

src/integrationtest/java/com.microsoft.aad.msal4j/OnBehalfOfIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public void acquireTokenWithOBO_Managed() throws Exception {
5050
final String password = appProvider.getOboPassword();
5151

5252
ConfidentialClientApplication cca =
53-
ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.create(password)).
53+
ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromSecret(password)).
5454
authority(msidlab4Authority).
5555
build();
5656

src/integrationtest/java/labapi/KeyVaultSecretsProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,6 @@ private IClientCredential getClientCredentialFromKeyStore() {
7878
} catch (Exception e){
7979
throw new RuntimeException("Error getting certificate from keystore: " + e.getMessage());
8080
}
81-
return ClientCredentialFactory.create(key, publicCertificate);
81+
return ClientCredentialFactory.createFromCertificate(key, publicCertificate);
8282
}
8383
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
@Accessors(fluent = true)
1616
@Getter
1717
@EqualsAndHashCode
18-
public final class ClientAssertion {
18+
final class ClientAssertion implements IClientCredential{
1919

2020
public static final String assertionType = JWTAuthentication.CLIENT_ASSERTION_TYPE;
2121
private final String assertion;
@@ -26,7 +26,7 @@ public final class ClientAssertion {
2626
*
2727
* @param assertion The jwt used as credential.
2828
*/
29-
public ClientAssertion(final String assertion) {
29+
ClientAssertion(final String assertion) {
3030
if (StringHelper.isBlank(assertion)) {
3131
throw new NullPointerException("assertion");
3232
}

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class ClientCredentialFactory {
1919
* @param secret secret of application requesting a token
2020
* @return {@link ClientSecret}
2121
*/
22-
public static IClientCredential create(String secret){
22+
public static IClientCredential createFromSecret(String secret){
2323
return new ClientSecret(secret);
2424
}
2525

@@ -35,8 +35,7 @@ public static IClientCredential create(String secret){
3535
* @throws NoSuchProviderException
3636
* @throws IOException
3737
*/
38-
public static IClientCredential create
39-
(final InputStream pkcs12Certificate, final String password)
38+
public static IClientCredential createFromCertificate(final InputStream pkcs12Certificate, final String password)
4039
throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException,
4140
KeyStoreException, NoSuchProviderException, IOException {
4241
return AsymmetricKeyCredential.create(pkcs12Certificate, password);
@@ -48,8 +47,16 @@ public static IClientCredential create(String secret){
4847
* @param publicCertificate x509 public certificate used for thumbprint
4948
* @return {@link IClientCredential}
5049
*/
51-
public static IClientCredential create
52-
(final PrivateKey key, final X509Certificate publicCertificate) {
50+
public static IClientCredential createFromCertificate(final PrivateKey key, final X509Certificate publicCertificate) {
5351
return AsymmetricKeyCredential.create(key, publicCertificate);
5452
}
53+
54+
/**
55+
*
56+
* @param clientAssertion Jwt token encoded as a base64 URL encoded string
57+
* @return {@link IClientCredential}
58+
*/
59+
public static IClientCredential createFromClientAssertion(String clientAssertion){
60+
return new ClientAssertion(clientAssertion);
61+
}
5562
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ private void initClientAuthentication(IClientCredential clientCredential) {
7474
this.authenticationAuthority.selfSignedJwtAudience());
7575

7676
clientAuthentication = createClientAuthFromClientAssertion(clientAssertion);
77+
} else if (clientCredential instanceof ClientAssertion){
78+
clientAuthentication = createClientAuthFromClientAssertion((ClientAssertion) clientCredential);
7779
} else {
7880
throw new IllegalArgumentException("Unsupported client credential");
7981
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@ static ClientAssertion buildJwt(String clientId, final AsymmetricKeyCredential c
4545

4646
SignedJWT jwt;
4747
try {
48-
JWSHeader.Builder builder = new Builder(JWSAlgorithm.RS256);
49-
List<Base64> certs = new ArrayList<Base64>();
48+
List<Base64> certs = new ArrayList<>();
5049
certs.add(new Base64(credential.publicCertificate()));
50+
51+
JWSHeader.Builder builder = new Builder(JWSAlgorithm.RS256);
5152
builder.x509CertChain(certs);
52-
builder.x509CertThumbprint(new Base64URL(credential
53-
.getPublicCertificateHash()));
53+
builder.x509CertThumbprint(new Base64URL(credential.getPublicCertificateHash()));
54+
5455
jwt = new SignedJWT(builder.build(), claimsSet);
5556
final RSASSASigner signer = new RSASSASigner(credential.key());
5657

src/test/java/com/microsoft/aad/msal4j/AcquireTokenSilentlyTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public void publicAppAcquireTokenSilently_emptyCache_MsalClientException() throw
3535
public void confidentialAppAcquireTokenSilently_emptyCache_MsalClientException() throws Throwable {
3636

3737
ConfidentialClientApplication application = ConfidentialClientApplication
38-
.builder(TestConfiguration.AAD_CLIENT_ID, ClientCredentialFactory.create(TestConfiguration.AAD_CLIENT_SECRET))
38+
.builder(TestConfiguration.AAD_CLIENT_ID, ClientCredentialFactory.createFromSecret(TestConfiguration.AAD_CLIENT_SECRET))
3939
.b2cAuthority(TestConfiguration.B2C_AUTHORITY).build();
4040

4141
SilentParameters parameters = SilentParameters.builder(Collections.singleton("scope")).build();

0 commit comments

Comments
 (0)