You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2018/05/04 07:07:35 UTC

[cloudstack] 05/08: saml2: Fixes #2548 SAML2 cert encoding and decoding

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 <ro...@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 <ro...@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
rohit@apache.org.