mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
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.yadav@shapeblue.com>
This commit is contained in:
parent
8533def696
commit
6412e50471
@ -32,7 +32,6 @@ import java.security.PublicKey;
|
|||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -147,11 +146,11 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage
|
|||||||
try {
|
try {
|
||||||
KeyPair keyPair = CertUtils.generateRandomKeyPair(4096);
|
KeyPair keyPair = CertUtils.generateRandomKeyPair(4096);
|
||||||
_ksDao.save(SAMLPluginConstants.SAMLSP_KEYPAIR,
|
_ksDao.save(SAMLPluginConstants.SAMLSP_KEYPAIR,
|
||||||
CertUtils.privateKeyToPem(keyPair.getPrivate()),
|
SAMLUtils.encodePrivateKey(keyPair.getPrivate()),
|
||||||
CertUtils.publicKeyToPem(keyPair.getPublic()), "samlsp-keypair");
|
SAMLUtils.encodePublicKey(keyPair.getPublic()), "samlsp-keypair");
|
||||||
keyStoreVO = _ksDao.findByName(SAMLPluginConstants.SAMLSP_KEYPAIR);
|
keyStoreVO = _ksDao.findByName(SAMLPluginConstants.SAMLSP_KEYPAIR);
|
||||||
s_logger.info("No SAML keystore found, created and saved a new Service Provider 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);
|
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;
|
KeyPair spKeyPair = null;
|
||||||
X509Certificate spX509Key = null;
|
X509Certificate spX509Key = null;
|
||||||
if (keyStoreVO != null) {
|
if (keyStoreVO != null) {
|
||||||
|
final PrivateKey privateKey = SAMLUtils.decodePrivateKey(keyStoreVO.getCertificate());
|
||||||
PrivateKey privateKey = null;
|
final PublicKey publicKey = SAMLUtils.decodePublicKey(keyStoreVO.getKey());
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (privateKey != null && publicKey != null) {
|
if (privateKey != null && publicKey != null) {
|
||||||
spKeyPair = new KeyPair(publicKey, privateKey);
|
spKeyPair = new KeyPair(publicKey, privateKey);
|
||||||
KeystoreVO x509VO = _ksDao.findByName(SAMLPluginConstants.SAMLSP_X509CERT);
|
KeystoreVO x509VO = _ksDao.findByName(SAMLPluginConstants.SAMLSP_X509CERT);
|
||||||
|
|||||||
@ -28,15 +28,20 @@ import java.math.BigInteger;
|
|||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.KeyFactory;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.Signature;
|
import java.security.Signature;
|
||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
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.List;
|
||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
import java.util.zip.DeflaterOutputStream;
|
||||||
@ -264,12 +269,6 @@ public class SAMLUtils {
|
|||||||
return url;
|
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 {
|
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("userid", URLEncoder.encode(loginResponse.getUserId(), HttpUtils.UTF_8)));
|
||||||
resp.addCookie(new Cookie("domainid", URLEncoder.encode(loginResponse.getDomainId(), 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()));
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,12 +64,14 @@ public class SAMLUtilsTest extends TestCase {
|
|||||||
public void testX509Helpers() throws Exception {
|
public void testX509Helpers() throws Exception {
|
||||||
KeyPair keyPair = CertUtils.generateRandomKeyPair(4096);
|
KeyPair keyPair = CertUtils.generateRandomKeyPair(4096);
|
||||||
|
|
||||||
String privateKeyString = CertUtils.privateKeyToPem(keyPair.getPrivate());
|
String privateKeyString = SAMLUtils.encodePrivateKey(keyPair.getPrivate());
|
||||||
String publicKeyString = CertUtils.publicKeyToPem(keyPair.getPublic());
|
String publicKeyString = SAMLUtils.encodePublicKey(keyPair.getPublic());
|
||||||
|
|
||||||
PrivateKey privateKey = CertUtils.pemToPrivateKey(privateKeyString);
|
PrivateKey privateKey = SAMLUtils.decodePrivateKey(privateKeyString);
|
||||||
PublicKey publicKey = CertUtils.pemToPublicKey(publicKeyString);
|
PublicKey publicKey = SAMLUtils.decodePublicKey(publicKeyString);
|
||||||
|
|
||||||
|
assertNotNull(privateKey);
|
||||||
|
assertNotNull(publicKey);
|
||||||
assertTrue(privateKey.equals(keyPair.getPrivate()));
|
assertTrue(privateKey.equals(keyPair.getPrivate()));
|
||||||
assertTrue(publicKey.equals(keyPair.getPublic()));
|
assertTrue(publicKey.equals(keyPair.getPublic()));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1881,7 +1881,6 @@
|
|||||||
<script type="text/javascript" src="scripts/network.js"></script>
|
<script type="text/javascript" src="scripts/network.js"></script>
|
||||||
<script type="text/javascript" src="scripts/domains.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/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/projectSelect.js"></script>
|
||||||
<script type="text/javascript" src="scripts/ui-custom/saml.js"></script>
|
<script type="text/javascript" src="scripts/ui-custom/saml.js"></script>
|
||||||
<script type="text/javascript" src="scripts/ui-custom/ca.js"></script>
|
<script type="text/javascript" src="scripts/ui-custom/ca.js"></script>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user