Skip to content

Commit

Permalink
using certificate from Key Vault for unit testing (#243)
Browse files Browse the repository at this point in the history
using certificate from Key Vault for unit testing
  • Loading branch information
SomkaPe authored Jun 3, 2020
1 parent 6deb186 commit 21f253e
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 253 deletions.
20 changes: 0 additions & 20 deletions build/credscan-exclude.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,5 @@
{
"tool": "Credential Scanner",
"suppressions": [
{
"file": "test-certificate.pfx",
"_justification": "test self signed certificate to test signing from the library. this certificate is not associated with any tenant"
},
{
"placeholder": "client_secret",
"_justification" : "credential used for testing. not associated with any tenant"
},
{
"placeholder": "ClientPassword",
"_justification" : "credential used for testing. not associated with any tenant"
},
{
"placeholder": "B2C_CONFIDENTIAL_CLIENT_APP_SECRET",
"_justification" : "Not a credential, just the identifier of the secret exposed by test lab API"
},
{
"placeholder": "MSIDLABB2C-MSAapp-AppSecret",
"_justification" : "Not a credential, just the identifier of the secret exposed by test lab API"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.net.MalformedURLException;
import java.net.URI;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
Expand Down Expand Up @@ -181,7 +180,7 @@ private void assertAcquireTokenAAD(User user, Map<String, Set<String>> parameter
private void assertAcquireTokenB2C(User user){

String appId = LabService.getSecret(TestConstants.B2C_CONFIDENTIAL_CLIENT_LAB_APP_ID);
String appSecret = LabService.getSecret(TestConstants.B2C_CONFIDENTIAL_CLIENT_APP_SECRET);
String appSecret = LabService.getSecret(TestConstants.B2C_CONFIDENTIAL_CLIENT_APP_SECRETID);

ConfidentialClientApplication cca;
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.aad.msal4j;

import labapi.KeyVaultSecretsProvider;
import org.apache.commons.lang3.SystemUtils;

import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class CertificateHelper {
static KeyStore createKeyStore() throws KeyStoreException, NoSuchProviderException {
String os = SystemUtils.OS_NAME;
if(os.contains("Mac")){
return KeyStore.getInstance("KeychainStore");
}
else{
return KeyStore.getInstance("Windows-MY", "SunMSCAPI");
}
}

static IClientCertificate getClientCertificate() throws
KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException, UnrecoverableKeyException, NoSuchProviderException {

KeyStore keystore = createKeyStore();

keystore.load(null, null);

PrivateKey key = (PrivateKey) keystore.getKey(KeyVaultSecretsProvider.CERTIFICATE_ALIAS, null);
X509Certificate publicCertificate = (X509Certificate) keystore.getCertificate(
KeyVaultSecretsProvider.CERTIFICATE_ALIAS);

return ClientCredentialFactory.createFromCertificate(key, publicCertificate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,33 @@

import labapi.AppCredentialProvider;
import labapi.AzureEnvironment;
import labapi.KeyVaultSecretsProvider;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;

import static com.microsoft.aad.msal4j.TestConstants.KEYVAULT_DEFAULT_SCOPE;

@Test
public class ClientCredentialsIT {
private IClientCertificate certificate;

@BeforeClass
void init() throws CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, NoSuchProviderException, IOException {
certificate = CertificateHelper.getClientCertificate();
}

@Test
public void acquireTokenClientCredentials_ClientCertificate() throws Exception{
String clientId = "55e7e5af-ca53-482d-9aa3-5cb1cc8eecb5";
IClientCredential credential = getCertificateFromKeyStore();
assertAcquireTokenCommon(clientId, credential);
assertAcquireTokenCommon(clientId, certificate);
}

@Test
Expand All @@ -45,11 +47,10 @@ public void acquireTokenClientCredentials_ClientSecret() throws Exception{
@Test
public void acquireTokenClientCredentials_ClientAssertion() throws Exception{
String clientId = "55e7e5af-ca53-482d-9aa3-5cb1cc8eecb5";
IClientCredential certificateFromKeyStore = getCertificateFromKeyStore();

ClientAssertion clientAssertion = JwtHelper.buildJwt(
clientId,
(ClientCertificate) certificateFromKeyStore,
(ClientCertificate) certificate,
"https://login.microsoftonline.com/common/oauth2/v2.0/token");

IClientCredential credential = ClientCredentialFactory.createFromClientAssertion(
Expand All @@ -72,17 +73,4 @@ private void assertAcquireTokenCommon(String clientId, IClientCredential credent
Assert.assertNotNull(result);
Assert.assertNotNull(result.accessToken());
}

private IClientCredential getCertificateFromKeyStore() throws
NoSuchProviderException, KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException, UnrecoverableKeyException {
KeyStore keystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
keystore.load(null, null);

PrivateKey key = (PrivateKey)keystore.getKey(KeyVaultSecretsProvider.CERTIFICATE_ALIAS, null);
X509Certificate publicCertificate = (X509Certificate)keystore.getCertificate(
KeyVaultSecretsProvider.CERTIFICATE_ALIAS);

return ClientCredentialFactory.createFromCertificate(key, publicCertificate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,48 @@
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.oauth2.sdk.auth.PrivateKeyJWT;
import org.apache.commons.lang3.StringUtils;
import org.easymock.EasyMock;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.*;
import java.util.concurrent.Future;

import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;

@PowerMockIgnore({"javax.net.ssl.*"})
@Test(groups = {"checkin"})
@PrepareForTest({ConfidentialClientApplication.class,
ClientCertificate.class, UserDiscoveryRequest.class, JwtHelper.class})
public class ConfidentialClientApplicationTest extends PowerMockTestCase {
public class ConfidentialClientApplicationUnitT extends PowerMockTestCase {

private ConfidentialClientApplication app = null;
private IClientCertificate clientCertificate;

@BeforeClass
private void init() throws
KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException, UnrecoverableKeyException, NoSuchProviderException {

clientCertificate = CertificateHelper.getClientCertificate();
}

@Test
public void testAcquireTokenAuthCode_ClientCredential() throws Exception {
app = PowerMock.createPartialMock(ConfidentialClientApplication.class,
new String[]{"acquireTokenCommon"},
ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID,
ClientCredentialFactory.createFromSecret(TestConfiguration.AAD_CLIENT_SECRET))
ClientCredentialFactory.createFromSecret(TestConfiguration.AAD_CLIENT_DUMMYSECRET))
.authority(TestConfiguration.AAD_TENANT_ENDPOINT)
);

Expand Down Expand Up @@ -77,23 +82,9 @@ public void testAcquireTokenAuthCode_ClientCredential() throws Exception {

@Test
public void testAcquireTokenAuthCode_KeyCredential() throws Exception {
final KeyStore keystore = KeyStore.getInstance("PKCS12", "SunJSSE");
keystore.load(
new FileInputStream(this.getClass()
.getResource(TestConfiguration.AAD_CERTIFICATE_PATH)
.getFile()),
TestConfiguration.AAD_CERTIFICATE_PASSWORD.toCharArray());
final String alias = keystore.aliases().nextElement();
final PrivateKey key = (PrivateKey) keystore.getKey(alias,
TestConfiguration.AAD_CERTIFICATE_PASSWORD.toCharArray());
final X509Certificate cert = (X509Certificate) keystore
.getCertificate(alias);

IClientCredential clientCredential = ClientCredentialFactory.createFromCertificate(key, cert);

app = PowerMock.createPartialMock(ConfidentialClientApplication.class,
new String[]{"acquireTokenCommon"},
ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, clientCredential)
ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, clientCertificate)
.authority(TestConfiguration.AAD_TENANT_ENDPOINT));

PowerMock.expectPrivate(app, "acquireTokenCommon",
Expand Down Expand Up @@ -121,24 +112,11 @@ public void testAcquireTokenAuthCode_KeyCredential() throws Exception {
PowerMock.resetAll(app);
}

@Test
public void testAcquireToken_KeyCred() throws Exception {
final KeyStore keystore = KeyStore.getInstance("PKCS12", "SunJSSE");
keystore.load(
new FileInputStream(this.getClass()
.getResource(TestConfiguration.AAD_CERTIFICATE_PATH)
.getFile()),
TestConfiguration.AAD_CERTIFICATE_PASSWORD.toCharArray());
final String alias = keystore.aliases().nextElement();
final PrivateKey key = (PrivateKey) keystore.getKey(alias,
TestConfiguration.AAD_CERTIFICATE_PASSWORD.toCharArray());
final X509Certificate cert = (X509Certificate) keystore
.getCertificate(alias);

IClientCredential clientCredential = ClientCredentialFactory.createFromCertificate(key, cert);

app = PowerMock.createPartialMock(ConfidentialClientApplication.class,
new String[]{"acquireTokenCommon"},
ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, clientCredential)
ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, clientCertificate)
.authority(TestConfiguration.AAD_TENANT_ENDPOINT));

PowerMock.expectPrivate(app, "acquireTokenCommon",
Expand Down Expand Up @@ -167,23 +145,13 @@ public void testAcquireToken_KeyCred() throws Exception {

@Test
public void testClientCertificateRebuildsWhenExpired() throws Exception {
final KeyStore keystore = KeyStore.getInstance("PKCS12", "SunJSSE");
keystore.load(
new FileInputStream(this.getClass()
.getResource(TestConfiguration.AAD_CERTIFICATE_PATH)
.getFile()),
TestConfiguration.AAD_CERTIFICATE_PASSWORD.toCharArray());
final String alias = keystore.aliases().nextElement();
final PrivateKey key = (PrivateKey) keystore.getKey(alias,
TestConfiguration.AAD_CERTIFICATE_PASSWORD.toCharArray());
final X509Certificate cert = (X509Certificate) keystore
.getCertificate(alias);

ClientCertificate clientCredential = (ClientCertificate) ClientCredentialFactory.createFromCertificate(key, cert);

PowerMock.mockStaticPartial(JwtHelper.class, new String[]{"buildJwt"});
long jwtExperiationPeriodMilli = 2000;
ClientAssertion shortExperationJwt = buildShortJwt(TestConfiguration.AAD_CLIENT_ID, clientCredential, TestConfiguration.AAD_TENANT_ENDPOINT, jwtExperiationPeriodMilli);
ClientAssertion shortExperationJwt = buildShortJwt(TestConfiguration.AAD_CLIENT_ID,
clientCertificate,
TestConfiguration.AAD_TENANT_ENDPOINT,
jwtExperiationPeriodMilli);

PowerMock.expectPrivate(
JwtHelper.class,
"buildJwt",
Expand All @@ -194,7 +162,7 @@ public void testClientCertificateRebuildsWhenExpired() throws Exception {
.times(2); // By this being called twice we ensure the client assertion is rebuilt once it has expired

PowerMock.replay(JwtHelper.class);
app = ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, clientCredential)
app = ConfidentialClientApplication.builder(TestConfiguration.AAD_CLIENT_ID, clientCertificate)
.authority(TestConfiguration.AAD_TENANT_ENDPOINT).build();
Thread.sleep(jwtExperiationPeriodMilli + 1000); //Have to sleep to ensure that the time period has passed
final PrivateKeyJWT clientAuthentication = (PrivateKeyJWT) app.clientAuthentication();
Expand All @@ -203,7 +171,7 @@ public void testClientCertificateRebuildsWhenExpired() throws Exception {
}

private ClientAssertion buildShortJwt(String clientId,
ClientCertificate credential,
IClientCertificate credential,
String jwtAudience,
long jwtExperiationPeriod) {
final long time = System.currentTimeMillis();
Expand Down
Loading

0 comments on commit 21f253e

Please sign in to comment.