Skip to content
This repository has been archived by the owner on Dec 4, 2023. It is now read-only.

Commit

Permalink
Dropped private Sun security imports. Now using pregenerated certs. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
tracyboehrer authored Mar 5, 2021
1 parent 24dc4e9 commit e51a84d
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@
import com.microsoft.bot.connector.authentication.OpenIdMetadataKey;
import com.microsoft.bot.connector.authentication.TokenValidationParameters;
import java.io.IOException;
import java.math.BigInteger;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
Expand All @@ -34,54 +36,45 @@
import java.util.concurrent.CompletionException;
import org.junit.Before;
import org.junit.Test;
import sun.security.x509.AlgorithmId;
import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateVersion;
import sun.security.x509.CertificateX509Key;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;

/**
* Test Notes:
*
* The PKCS12 certificates were created using these steps:
* https://kb.globalscape.com/Knowledgebase/11039/Generating-a-PKCS12-Private-Key-and-Public-Certificate
*
* For the expired cert, just specify a negative number of days in step #4.
*
* For both valid and expired certs, these unit tests expect the alias for both to be "bot-connector-pkcs12"
* and the password to be "botframework"
*/
public class JwtTokenExtractorTests {
private X509Certificate validCertificate;
private X509Certificate expiredCertificate;
private KeyPair keyPair;
private CertInfo valid;
private CertInfo expired;

@Before
public void setup() throws GeneralSecurityException, IOException {
ChannelValidation.TOKENVALIDATIONPARAMETERS.validateLifetime = false;
EmulatorValidation.TOKENVALIDATIONPARAMETERS.validateLifetime = false;
GovernmentChannelValidation.TOKENVALIDATIONPARAMETERS.validateLifetime = false;

// create keys
keyPair = createKeyPair();
Date now = new Date();
Date from = new Date(now.getTime() - (10 * 86400000L));

// create expired certificate
Date to = new Date(now.getTime() - (9 * 86400000L));
expiredCertificate = createSelfSignedCertificate(keyPair, from, to);

// create valid certificate
to = new Date(now.getTime() + (9 * 86400000L));
validCertificate = createSelfSignedCertificate(keyPair, from, to);
valid = loadCert("bot-connector.pkcs12");
expired = loadCert("bot-connector-expired.pkcs12");
}

@Test(expected = CompletionException.class)
public void JwtTokenExtractor_WithExpiredCert_ShouldNotAllowCertSigningKey() {
// this should throw a CompletionException (which contains an AuthenticationException)
buildExtractorAndValidateToken(
expiredCertificate, keyPair.getPrivate()
expired.cert, expired.keypair.getPrivate()
).join();
}

@Test
public void JwtTokenExtractor_WithValidCert_ShouldAllowCertSigningKey() {
// this should not throw
buildExtractorAndValidateToken(
validCertificate, keyPair.getPrivate()
valid.cert, valid.keypair.getPrivate()
).join();
}

Expand All @@ -92,7 +85,7 @@ public void JwtTokenExtractor_WithExpiredToken_ShouldNotAllow() {
Date issuedAt = new Date(now.getTime() - 86400000L);

buildExtractorAndValidateToken(
expiredCertificate, keyPair.getPrivate(), issuedAt
expired.cert, expired.keypair.getPrivate(), issuedAt
).join();
}

Expand Down Expand Up @@ -161,45 +154,24 @@ private static TokenValidationParameters createTokenValidationParameters(X509Cer
}};
}

private KeyPair createKeyPair() throws NoSuchAlgorithmException {
// note that this isn't allowing for a "kid" value
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
return generator.generateKeyPair();
private static class CertInfo {
public X509Certificate cert;
public KeyPair keypair;
}

private static X509Certificate createSelfSignedCertificate(
KeyPair pair, Date from, Date to
) throws GeneralSecurityException, IOException {
String dn = "CN=Bot, OU=BotFramework, O=Microsoft, C=US";
String algorithm = "SHA256withRSA";

PrivateKey privateKey = pair.getPrivate();
X509CertInfo info = new X509CertInfo();

CertificateValidity interval = new CertificateValidity(from, to);
BigInteger sn = new BigInteger(64, new SecureRandom());
X500Name owner = new X500Name(dn);

info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
info.set(X509CertInfo.SUBJECT, owner);
info.set(X509CertInfo.ISSUER, owner);
info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
AlgorithmId algo = new AlgorithmId(AlgorithmId.sha256WithRSAEncryption_oid);
info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

// Sign the cert to identify the algorithm that's used.
X509CertImpl cert = new X509CertImpl(info);
cert.sign(privateKey, algorithm);

// Update the algorithm, and resign.
algo = (AlgorithmId)cert.get(X509CertImpl.SIG_ALG);
info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
cert = new X509CertImpl(info);
cert.sign(privateKey, algorithm);
return cert;
private static CertInfo loadCert(String pkcs12File)
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException,
UnrecoverableKeyException {
InputStream fis = ClassLoader.getSystemResourceAsStream(pkcs12File);
KeyStore p12 = KeyStore.getInstance("pkcs12");
p12.load(fis, "botframework".toCharArray());

return new CertInfo() {{
cert = (X509Certificate) p12.getCertificate("bot-connector-pkcs12");
keypair = new KeyPair(cert.getPublicKey(),
(PrivateKey) p12.getKey("bot-connector-pkcs12", "botframework".toCharArray())
);
}};
}

private static String encodeCertificate(Certificate certificate) {
Expand Down
Binary file not shown.
27 changes: 27 additions & 0 deletions libraries/bot-connector/src/test/resources/bot-connector.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAy8VcIYWh4sF2XcZF7u+lSq7YdE8skZhmtDF5w8GoEoPscGyT
wSeWjK7u+y2g5iAZsXQwzhN1VvOHznAlLrswLaORie7ch9veFeTMT60gLL2w8e6h
RUWxNJiQXjeExwk8Fhvcq7Kpl+qM4iEHvDX6iXCjEkNJ4Ghx48j9siUKMf1T8IcZ
sE3zzaaGOU5ar8NVsf9Kz1kPCOYv8zqykB45nUDsbE/q9cEkumL8ebjd1JApDJf0
sf/PkftMvwP69QY1CJ/achUsRqDvFGLw+ZyUyXaSdPt92H92vbNzo8hn6GuxnPHy
f/Aoxjy/o5zNocsiiJvgFBFjRBZXWhk3OJWKZwIDAQABAoIBADNiKx9Q4Uea3Uw8
STo9OAMjH/YEWQrF0XAy4a+ZT9aLab3Xw1J7txz2p9Cy6tXc1l3HHN96TKaGdoJ6
CQZFsZpwmqybjQS9Tr1amqKk124wz0PSltwu/MZ0ikMX4OWH0J0KnZS2Usm6HZiQ
F7FAM1MhEh3y1dg+vilgb4jSikWcVp7RbcMgwG0N9oQhbPqN+Bv/E5KBpYk1Rdwt
yjSBOdDenx+TF5RrdKYxC3ouKN0BJMgtIIkv+iGce1WMtSAHkNXrgxJ9AhDquREU
Op363fad01Ulvs4Z+IDlEhrpA6oUt5hr8lStFhrhVuDPqctAWz27+YNw5ioHbimA
U48EOzECgYEA7T5dQzKXIzrDha4Spr8KbCMvXsesehWG3RLZxhU7lnjSMAhBuKGU
hZMfjmSSBR/rr7ppMjN4LLmpjqTkhojg/p+MnK9XRSvmGaSxlS1K8hANjShhx6s7
xWbEsKQEPbuq1m0vCAzxgGkxLpRmM9ajJhFYEoSdVbc/hhVI72mxhiUCgYEA2+GI
ig0Wpbq5D1ISwljWHhpdi4d0MeO+wtogMo46AAX4kpgCEKDmPwX2igJKJjQJyWNB
PqHXPPQJyferun27baiNA5vEDzoCRvyLqKjyLrzSS+wDszR4mYhK8naILPonmIca
9BsUDcQw7x3rzVUlOKFpbRfT0qPVa5qn3T32apsCgYEAmYJvCloj3ZHajhdSzj5z
WgFyV1vQSLbBKy9VZoy6n+TR7G6LSBKVbdEC7Do7GcHL2Us/YlJXgmkoQ7qCfGL5
YwiODZyPVZzQKOueVK6X/gVRH3NvwakU5ehXgQzACcnzAwhnFEh7w+FNB5zSfNx3
eNxkJqdUvu/x1KrVJMU5L1kCgYEAkIokYGOUNKOXDTwterY9IpLAVX1YY4dLmfkb
W0BlXiiOq4bjLJ0oXduEolo49f4VRN5LQGnQ/I+Lc8msiK4oLEC1Wd7mNgAzCQjw
oZFVimWzdBcUo5Plhz+xzMsgXzieGMUPcdHvD9GdPUKVBGhpTF3G2ODl7LyoCdEj
cetOdesCgYAIuxFR/89S44Je5maTMkcExZpVTm1D1Zc8EmlHQ+WPjrakZSWFx2TS
o8wUd/mCwCTLRG3S2t3eUZiEi+G9gI8bE/w7ABxNCFAlHbo0SETy7T+9XeznoFbZ
0FyvVLvXQVZhKPVTF0pYkfuHo3ofbotKbTEM62EurroU1dviRJ7Seg==
-----END RSA PRIVATE KEY-----
Binary file not shown.

0 comments on commit e51a84d

Please sign in to comment.