This is an automated email from the ASF dual-hosted git repository. rohit pushed a commit to branch 4.11 in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 6412e50471bf447de24c7a72713ec2294cb2ce1e Author: Rohit Yadav <rohit.ya...@shapeblue.com> AuthorDate: Wed May 2 17:57:32 2018 +0530 saml2: Fixes #2548 SAML2 cert encoding and decoding This fixes SAML2 certificate encoding/decoding issue due to refactoring regression introduced in 7ce54bf7a85d6df72f84c00fadf9b0fd42ab0d99 that did not account for base64 based encoding/decoding. The changes effectively restore the same logic as used in previous versions. Signed-off-by: Rohit Yadav <rohit.ya...@shapeblue.com> --- .../cloudstack/saml/SAML2AuthManagerImpl.java | 22 ++---- .../src/org/apache/cloudstack/saml/SAMLUtils.java | 89 ++++++++++++++++++++-- .../test/org/apache/cloudstack/SAMLUtilsTest.java | 10 ++- ui/index.html | 1 - 4 files changed, 94 insertions(+), 28 deletions(-) diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java index d280ed5..f0a5bab 100644 --- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java @@ -32,7 +32,6 @@ import java.security.PublicKey; import java.security.SignatureException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -147,11 +146,11 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage try { KeyPair keyPair = CertUtils.generateRandomKeyPair(4096); _ksDao.save(SAMLPluginConstants.SAMLSP_KEYPAIR, - CertUtils.privateKeyToPem(keyPair.getPrivate()), - CertUtils.publicKeyToPem(keyPair.getPublic()), "samlsp-keypair"); + SAMLUtils.encodePrivateKey(keyPair.getPrivate()), + SAMLUtils.encodePublicKey(keyPair.getPublic()), "samlsp-keypair"); keyStoreVO = _ksDao.findByName(SAMLPluginConstants.SAMLSP_KEYPAIR); s_logger.info("No SAML keystore found, created and saved a new Service Provider keypair"); - } catch (final NoSuchProviderException | NoSuchAlgorithmException | IOException e) { + } catch (final NoSuchProviderException | NoSuchAlgorithmException e) { s_logger.error("Unable to create and save SAML keypair, due to: ", e); } } @@ -166,19 +165,8 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage KeyPair spKeyPair = null; X509Certificate spX509Key = null; if (keyStoreVO != null) { - - PrivateKey privateKey = null; - try { - privateKey = CertUtils.pemToPrivateKey(keyStoreVO.getCertificate()); - } catch (final InvalidKeySpecException | IOException e) { - s_logger.error("Failed to read private key, due to error: ", e); - } - PublicKey publicKey = null; - try { - publicKey = CertUtils.pemToPublicKey(keyStoreVO.getKey()); - } catch (final InvalidKeySpecException | IOException e) { - s_logger.error("Failed to read public key, due to error: ", e); - } + final PrivateKey privateKey = SAMLUtils.decodePrivateKey(keyStoreVO.getCertificate()); + final PublicKey publicKey = SAMLUtils.decodePublicKey(keyStoreVO.getKey()); if (privateKey != null && publicKey != null) { spKeyPair = new KeyPair(publicKey, privateKey); KeystoreVO x509VO = _ksDao.findByName(SAMLPluginConstants.SAMLSP_X509CERT); diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLUtils.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLUtils.java index 364ef86..5b00d47 100644 --- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLUtils.java +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLUtils.java @@ -28,15 +28,20 @@ import java.math.BigInteger; import java.net.URLEncoder; import java.nio.charset.Charset; import java.security.InvalidKeyException; +import java.security.KeyFactory; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; +import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; import java.security.SignatureException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; import java.util.List; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; @@ -264,12 +269,6 @@ public class SAMLUtils { return url; } - public static X509Certificate generateRandomX509Certificate(KeyPair keyPair) throws NoSuchAlgorithmException, NoSuchProviderException, CertificateException, SignatureException, InvalidKeyException, OperatorCreationException { - return CertUtils.generateV1Certificate(keyPair, - "CN=ApacheCloudStack", "CN=ApacheCloudStack", - 3, "SHA256WithRSA"); - } - public static void setupSamlUserCookies(final LoginCmdResponse loginResponse, final HttpServletResponse resp) throws IOException { resp.addCookie(new Cookie("userid", URLEncoder.encode(loginResponse.getUserId(), HttpUtils.UTF_8))); resp.addCookie(new Cookie("domainid", URLEncoder.encode(loginResponse.getDomainId(), HttpUtils.UTF_8))); @@ -284,4 +283,82 @@ public class SAMLUtils { resp.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly", ApiConstants.SESSIONKEY, loginResponse.getSessionKey())); } + /** + * Returns base64 encoded PublicKey + * @param key PublicKey + * @return public key encoded string + */ + public static String encodePublicKey(PublicKey key) { + try { + KeyFactory keyFactory = CertUtils.getKeyFactory(); + if (keyFactory == null) return null; + X509EncodedKeySpec spec = keyFactory.getKeySpec(key, X509EncodedKeySpec.class); + return new String(org.bouncycastle.util.encoders.Base64.encode(spec.getEncoded()), Charset.forName("UTF-8")); + } catch (InvalidKeySpecException e) { + s_logger.error("Unable to create KeyFactory:" + e.getMessage()); + } + return null; + } + + /** + * Returns base64 encoded PrivateKey + * @param key PrivateKey + * @return privatekey encoded string + */ + public static String encodePrivateKey(PrivateKey key) { + try { + KeyFactory keyFactory = CertUtils.getKeyFactory(); + if (keyFactory == null) return null; + PKCS8EncodedKeySpec spec = keyFactory.getKeySpec(key, + PKCS8EncodedKeySpec.class); + return new String(org.bouncycastle.util.encoders.Base64.encode(spec.getEncoded()), Charset.forName("UTF-8")); + } catch (InvalidKeySpecException e) { + s_logger.error("Unable to create KeyFactory:" + e.getMessage()); + } + return null; + } + + /** + * Decodes base64 encoded public key to PublicKey + * @param publicKey encoded public key string + * @return returns PublicKey + */ + public static PublicKey decodePublicKey(String publicKey) { + byte[] sigBytes = org.bouncycastle.util.encoders.Base64.decode(publicKey); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(sigBytes); + KeyFactory keyFactory = CertUtils.getKeyFactory(); + if (keyFactory == null) + return null; + try { + return keyFactory.generatePublic(x509KeySpec); + } catch (InvalidKeySpecException e) { + s_logger.error("Unable to create PrivateKey from privateKey string:" + e.getMessage()); + } + return null; + } + + /** + * Decodes base64 encoded private key to PrivateKey + * @param privateKey encoded private key string + * @return returns PrivateKey + */ + public static PrivateKey decodePrivateKey(String privateKey) { + byte[] sigBytes = org.bouncycastle.util.encoders.Base64.decode(privateKey); + PKCS8EncodedKeySpec pkscs8KeySpec = new PKCS8EncodedKeySpec(sigBytes); + KeyFactory keyFactory = CertUtils.getKeyFactory(); + if (keyFactory == null) + return null; + try { + return keyFactory.generatePrivate(pkscs8KeySpec); + } catch (InvalidKeySpecException e) { + s_logger.error("Unable to create PrivateKey from privateKey string:" + e.getMessage()); + } + return null; + } + + public static X509Certificate generateRandomX509Certificate(KeyPair keyPair) throws NoSuchAlgorithmException, NoSuchProviderException, CertificateException, SignatureException, InvalidKeyException, OperatorCreationException { + return CertUtils.generateV1Certificate(keyPair, + "CN=ApacheCloudStack", "CN=ApacheCloudStack", + 3, "SHA256WithRSA"); + } } diff --git a/plugins/user-authenticators/saml2/test/org/apache/cloudstack/SAMLUtilsTest.java b/plugins/user-authenticators/saml2/test/org/apache/cloudstack/SAMLUtilsTest.java index 4986d7a..4784134 100644 --- a/plugins/user-authenticators/saml2/test/org/apache/cloudstack/SAMLUtilsTest.java +++ b/plugins/user-authenticators/saml2/test/org/apache/cloudstack/SAMLUtilsTest.java @@ -64,12 +64,14 @@ public class SAMLUtilsTest extends TestCase { public void testX509Helpers() throws Exception { KeyPair keyPair = CertUtils.generateRandomKeyPair(4096); - String privateKeyString = CertUtils.privateKeyToPem(keyPair.getPrivate()); - String publicKeyString = CertUtils.publicKeyToPem(keyPair.getPublic()); + String privateKeyString = SAMLUtils.encodePrivateKey(keyPair.getPrivate()); + String publicKeyString = SAMLUtils.encodePublicKey(keyPair.getPublic()); - PrivateKey privateKey = CertUtils.pemToPrivateKey(privateKeyString); - PublicKey publicKey = CertUtils.pemToPublicKey(publicKeyString); + PrivateKey privateKey = SAMLUtils.decodePrivateKey(privateKeyString); + PublicKey publicKey = SAMLUtils.decodePublicKey(publicKeyString); + assertNotNull(privateKey); + assertNotNull(publicKey); assertTrue(privateKey.equals(keyPair.getPrivate())); assertTrue(publicKey.equals(keyPair.getPublic())); } diff --git a/ui/index.html b/ui/index.html index b94e8e5..5003f00 100644 --- a/ui/index.html +++ b/ui/index.html @@ -1881,7 +1881,6 @@ <script type="text/javascript" src="scripts/network.js"></script> <script type="text/javascript" src="scripts/domains.js"></script> <script type="text/javascript" src="scripts/docs.js"></script> - <script type="text/javascript" src="scripts/vm_snapshots.js"></script> <script type="text/javascript" src="scripts/ui-custom/projectSelect.js"></script> <script type="text/javascript" src="scripts/ui-custom/saml.js"></script> <script type="text/javascript" src="scripts/ui-custom/ca.js"></script> -- To stop receiving notification emails like this one, please contact ro...@apache.org.