116 lines
3.2 KiB
PHP
116 lines
3.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\File;
|
|
|
|
class GenerateSamlKeysCommand extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $signature = 'saml:generate-keys {--force : Overwrite existing keys}';
|
|
|
|
/**
|
|
* The console command description.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $description = 'Generate self-signed SAML private key and public certificate for the IdP';
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*/
|
|
public function handle(): int
|
|
{
|
|
$directory = storage_path('app/saml');
|
|
$keyPath = "{$directory}/idp.key";
|
|
$certPath = "{$directory}/idp.crt";
|
|
|
|
if (! File::exists($directory)) {
|
|
File::makeDirectory($directory, 0755, true);
|
|
}
|
|
|
|
if (File::exists($keyPath) && File::exists($certPath) && ! $this->option('force')) {
|
|
$this->info('SAML keys already exist. Use --force to overwrite them.');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$this->info('Generating SAML keys...');
|
|
|
|
$config = [
|
|
'digest_alg' => 'sha256',
|
|
'private_key_bits' => 2048,
|
|
'private_key_type' => OPENSSL_KEYTYPE_RSA,
|
|
];
|
|
|
|
// Create keypair
|
|
$res = openssl_pkey_new($config);
|
|
if (false === $res) {
|
|
$this->error('Failed to generate private key. Ensure OpenSSL is configured.');
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
// Export private key
|
|
if (! openssl_pkey_export($res, $privKey)) {
|
|
$this->error('Failed to export private key.');
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
// Generate CSR and self-signed certificate
|
|
$dn = [
|
|
'countryName' => 'US',
|
|
'stateOrProvinceName' => 'California',
|
|
'localityName' => 'San Francisco',
|
|
'organizationName' => 'Laravel SSO',
|
|
'organizationalUnitName' => 'IT Department',
|
|
'commonName' => 'laravel-sso-idp',
|
|
'emailAddress' => 'admin@sso.local',
|
|
];
|
|
|
|
$csr = openssl_csr_new($dn, $res, ['digest_alg' => 'sha256']);
|
|
if (false === $csr) {
|
|
$this->error('Failed to create CSR.');
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$cert = openssl_csr_sign($csr, null, $res, 3650, ['digest_alg' => 'sha256']); // 10 years validity
|
|
if (false === $cert) {
|
|
$this->error('Failed to sign certificate.');
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
if (! openssl_x509_export($cert, $certOut)) {
|
|
$this->error('Failed to export certificate.');
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
// Write files
|
|
File::put($keyPath, $privKey);
|
|
File::put($certPath, $certOut);
|
|
|
|
// Update or add .gitignore inside the saml directory
|
|
$gitignorePath = "{$directory}/.gitignore";
|
|
if (! File::exists($gitignorePath)) {
|
|
File::put($gitignorePath, "idp.key\n");
|
|
}
|
|
|
|
$this->info('Keys generated successfully:');
|
|
$this->line("- Private Key: {$keyPath}");
|
|
$this->line("- Certificate: {$certPath}");
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|