## Getting Started
### **Minimal Setup in Laravel**
1. **Installation**
```bash
composer require simplesamlphp/saml2:^4.19.1
No additional autoload changes required in composer.json (v4.19.1+ handles PSR-4 auto-loading natively).
First Use Case: Secure Auth Flow with CVE-2025-66475 Mitigation
config/saml.php:
'sp' => [
'entityId' => 'urn:your-sp-entity-id',
'assertionConsumerService' => [
'url' => route('saml/acs'),
'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
],
'privateKey' => file_get_contents(storage_path('saml/sp-key.pem')),
'certificate' => file_get_contents(storage_path('saml/sp-cert.pem')),
'security' => [
'wantAssertionsSigned' => true, // **MANDATORY** for CVE-2025-66475
'wantAttributeStatement' => true,
'wantNameIdEncrypted' => true, // New in v4.19.1
],
],
openssl genpkey -algorithm RSA -out sp-key.pem -pkeyopt rsa_keygen_bits:4096
openssl rsa -pubout -in sp-key.pem -out sp-cert.pem
Fails silently with weak keys (RSA < 2048) during assertion validation.Updated Controller with Assertion Validation
use SimpleSAML\Authn\Simple;
use SimpleSAML\Error\Error;
class SamlController extends Controller {
public function assertionConsumerService() {
$as = new Simple();
try {
if (!$as->isAuthenticated()) {
throw new Error("Authentication failed");
}
// **NEW**: Explicit signature check (CVE-2025-66475)
if (!$as->isAssertionSigned()) {
throw new Error("Unsigned assertion rejected (security violation)");
}
$attributes = $as->getAttributes();
$this->validateAttributes($attributes);
auth()->loginUsingId($attributes['uid'][0]);
return redirect()->intended('/dashboard');
} catch (Error $e) {
\Log::critical('SAML Security Error: ' . $e->getMessage());
return back()->withErrors(['saml' => 'Login failed: ' . $e->getMessage()]);
}
}
}
$as = new Simple();
$as->requireAuthn([
'idp' => 'idp-entity-id',
'authContext' => 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport',
'nameIdPolicy' => [
'format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
'allowCreate' => false, // Prevent IDP from generating NameIDs
],
]);
New: nameIdPolicy now supports allowCreate: false to block IDP-generated NameIDs (v4.19.1).
protected function validateAttributes(array $attributes): void {
if (empty($attributes['email'])) {
throw new Error("Missing email attribute");
}
if (!filter_var($attributes['email'][0], FILTER_VALIDATE_EMAIL)) {
throw new Error("Invalid email format");
}
// **NEW**: Type enforcement for numeric attributes
if (isset($attributes['user_id']) && !is_numeric($attributes['user_id'][0])) {
throw new Error("Invalid user_id type");
}
}
$slo = new \SimpleSAML\Authn\SLO();
$slo->setWantResponse(true); // **REQUIRED** for security compliance
$slo->setBinding('urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect');
$slo->processSLO();
New: setWantResponse(true) is now mandatory for SLO to enforce IDP confirmation.
$metadata = $as->getSPMetadata([
'includeSecurity' => true,
'includeNameIdFormat' => true,
]);
file_put_contents(storage_path('saml/sp-metadata.xml'), $metadata);
New: Explicitly include NameIDFormat in metadata to prevent IDP misconfigurations.
try {
$as->requireAuthn();
} catch (\SimpleSAML\Error\Error $e) {
\Log::channel('security')->error('SAML Error', [
'code' => $e->getCode(),
'message' => $e->getMessage(),
'security_impact' => $this->isSecurityCritical($e->getCode()),
]);
throw $e; // Re-throw for middleware handling
}
New: Log security-impact flag for critical errors (e.g., UNSIGNED_ASSERTION).
CVE-2025-66475: Unsigned Assertion Bypass
wantAssertionsSigned: true to SP config and validate with:
if (!$as->isAssertionSigned()) {
abort(403, 'Security violation: Unsigned assertion');
}
SimpleSAML\Logger::setLogger() with level DEBUG to trace assertion validation.NameID Encryption Enforcement
NAMEID_NOT_ENCRYPTED if IDP sends unencrypted NameIDs.wantNameIdEncrypted: true in SP config and regenerate keys:
openssl genpkey -algorithm RSA -out sp-key.pem -pkeyopt rsa_keygen_bits:4096
openssl pkcs8 -topk8 -inform PEM -outform DER -in sp-key.pem -out sp-key.der -nocrypt
Clock Skew Rejections (Stricter Defaults)
CLOCK_SKEW if server time differs by >60s (default was 300s).$as->setAllowedClockSkew(60); // 1 minute (recommended)
Enable Verbose Logging:
\SimpleSAML\Logger::setLogger(new \SimpleSAML\Logger\File(
storage_path('logs/saml.log'),
\SimpleSAML\Logger::DEBUG
));
Validate Metadata Manually:
php artisan saml:validate-metadata --idp=idp-metadata.xml --sp=sp-metadata.xml
New CLI command in v4.19.1.
Test with saml:test Artisan Command:
php artisan saml:test --idp=test-idp --assertion=unsigned
Simulates CVE-2025-66475 scenarios.
$as->setAttributeMapper(new class implements \SimpleSAML\Attribute\Mapper\MapperInterface {
public function map(array $attributes): array {
return [
'uid' => $attributes['userPrincipalName'] ?? [],
'email' => array_map('strtolower', $attributes['mail'] ?? []),
];
}
});
namespace App\Http\Middleware;
use Closure;
use SimpleSAML\Error\Error;
class VerifySamlSignature {
public function handle($request, Closure $next) {
if (session()->has('saml.assertion')) {
$as = new \SimpleSAML\Authn\Simple();
if (!$as->isAssertionSigned()) {
abort(403, 'Invalid SAML signature');
}
}
return $next($request);
}
}
$metadata = cache()->remember('saml.sp.metadata', 3
How can I help you explore Laravel packages today?