Spaces:
No application file
No application file
namespace Mautic\UserBundle\Security\SAML\Store; | |
use LightSaml\Credential\KeyHelper; | |
use LightSaml\Credential\X509Certificate; | |
use LightSaml\Credential\X509Credential; | |
use LightSaml\Store\Credential\CredentialStoreInterface; | |
use Mautic\CoreBundle\Helper\CoreParametersHelper; | |
use RobRichards\XMLSecLibs\XMLSecurityKey; | |
class CredentialsStore implements CredentialStoreInterface | |
{ | |
private ?X509Credential $credentials = null; | |
public function __construct( | |
private CoreParametersHelper $coreParametersHelper, | |
private string $entityId | |
) { | |
} | |
public function getByEntityId($entityId): array | |
{ | |
// EntityIds do not match | |
if ($entityId !== $this->entityId) { | |
return []; | |
} | |
if (!$this->credentials) { | |
$this->delegateAndCreateCredentials(); | |
} | |
return [$this->credentials]; | |
} | |
private function delegateAndCreateCredentials(): void | |
{ | |
// Credentials are required or SP will cause a never ending login loop as it throws an exception | |
$samlEnabled = (bool) $this->coreParametersHelper->get('saml_idp_metadata'); | |
if (!$samlEnabled || !$certificateContent = $this->coreParametersHelper->get('saml_idp_own_certificate')) { | |
$this->credentials = $this->createDefaultCredentials(); | |
return; | |
} | |
$this->credentials = $this->createOwnCredentials(); | |
} | |
private function createOwnCredentials(): X509Credential | |
{ | |
$certificateContent = base64_decode($this->coreParametersHelper->get('saml_idp_own_certificate')); | |
$privateKeyContent = base64_decode($this->coreParametersHelper->get('saml_idp_own_private_key')); | |
$keyPassword = (string) $this->coreParametersHelper->get('saml_idp_own_password'); | |
return $this->createCredentials($certificateContent, $privateKeyContent, $keyPassword); | |
} | |
private function createDefaultCredentials(): X509Credential | |
{ | |
$cache_dir = $this->coreParametersHelper->get('cache_path'); | |
$keyPassword = ''; | |
if (!file_exists($cache_dir.'/saml_default.key') || !file_exists($cache_dir.'/saml_default.crt')) { | |
$dn = ['commonName' => 'Mautic dummy cert']; | |
// Generate a new private (and public) key pair | |
$privkey = openssl_pkey_new([ | |
'private_key_bits' => 2048, | |
'private_key_type' => OPENSSL_KEYTYPE_RSA, | |
]); | |
// Generate a certificate signing request | |
$csr = openssl_csr_new($dn, $privkey, ['digest_alg' => 'sha256']); | |
// Generate a self-signed cert, valid for 365 days | |
$x509 = openssl_csr_sign($csr, null, $privkey, $days=365, ['digest_alg' => 'sha256']); | |
openssl_x509_export_to_file($x509, $cache_dir.'/saml_default.crt'); | |
openssl_pkey_export_to_file($privkey, $cache_dir.'/saml_default.key', $keyPassword); | |
} | |
$cert = file_get_contents($cache_dir.'/saml_default.crt'); | |
$privateKey = file_get_contents($cache_dir.'/saml_default.key'); | |
return $this->createCredentials($cert, $privateKey, $keyPassword); | |
} | |
private function createCertificate(string $certificateContent): X509Certificate | |
{ | |
$certificate = new X509Certificate(); | |
$certificate->loadPem($certificateContent); | |
return $certificate; | |
} | |
private function createPrivateKey(string $privateKeyContent, string $keyPassword, X509Certificate $certificate): XMLSecurityKey | |
{ | |
return KeyHelper::createPrivateKey($privateKeyContent, $keyPassword, false, $certificate->getSignatureAlgorithm()); | |
} | |
private function createCredentials(string $certificateContent, string $privateKeyContent, string $keyPassword): X509Credential | |
{ | |
$certificate = $this->createCertificate($certificateContent); | |
$privateKey = $this->createPrivateKey($privateKeyContent, $keyPassword, $certificate); | |
$credentials = new X509Credential($certificate, $privateKey); | |
$credentials->setEntityId($this->entityId); | |
return $credentials; | |
} | |
} | |