Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using certificate from Key Vault for unit testing #243

Merged
merged 7 commits into from
Jun 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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