hslavich/simplesamlphp-bundle
Symfony bundle that integrates SimpleSAMLphp into your application for SAML 2.0 authentication. Configure identity providers, use SimpleSAMLphp as an authentication source, and protect routes with federated single sign-on via the bundle's security integration.
This bundle is a thin Symfony wrapper around SimpleSAMLphp. It is intended for Symfony 2.x/3.x-era applications and exposes a service you can call from controllers/listeners to trigger SAML authentication and read attributes.
Minimal setup:
composer require hslavich/simplesamlphp-bundle simplesamlphp/simplesamlphp
app/AppKernel.php:
new Hslavich\SimplesamlphpBundle\HslavichSimplesamlphpBundle(),
DependencyInjection/Configuration.php for the exact keys in your version; typical configuration looks like:
# app/config/config.yml
hslavich_simplesamlphp:
simplesamlphp_dir: "%kernel.root_dir%/../vendor/simplesamlphp/simplesamlphp"
auth_source: default-sp
vendor/simplesamlphp/simplesamlphp/config/config.php and config/authsources.php. Your SP entry needs the Symfony route URL as its ACS/entity endpoint, for example:
'default-sp' => [
'saml:SP',
'entityID' => 'https://app.example.com/saml/metadata',
'idp' => 'https://idp.example.com/metadata',
'certificate' => 'saml.crt',
'privatekey' => 'saml.pem',
],
metadata/saml20-idp-remote.php.Where to look first:
Resources/config/services.xml to confirm the auth service ID (older READMEs commonly reference simplesamlphp_auth; some versions use hslavich.simplesamlphp.auth).DependencyInjection/Configuration.php for exact config keys.config/config.php and config/authsources.php for SP/IdP wiring./simplesaml if it is exposed in your environment.First practical use case: protect a controller action and retrieve the authenticated user’s attributes.
public function dashboardAction()
{
$auth = $this->get('simplesamlphp_auth'); // confirm service ID in services.xml
if (!$auth->isAuthenticated()) {
$auth->requireAuth([
'ReturnTo' => $this->generateUrl('dashboard', [], UrlGeneratorInterface::ABSOLUTE_URL),
]);
}
$attributes = $auth->getAttributes();
$mail = $attributes['mail'][0] ?? null;
return $this->render('AppBundle:Dashboard:index.html.twig', [
'mail' => $mail,
]);
}
Controller-level authentication gate. The simplest day-to-day pattern is to call the auth service at the start of a controller or in a kernel request listener. requireAuth() redirects to the IdP and exits; after the IdP posts back, SimpleSAMLphp processes the assertion and the user returns to ReturnTo.
$auth = $this->get('simplesamlphp_auth');
$auth->requireAuth([
'ReturnTo' => $this->generateUrl('app_home', [], UrlGeneratorInterface::ABSOLUTE_URL),
]);
Use this for a small number of protected routes, or in a listener that checks $request->getPathInfo() against protected patterns.
Firewall-based authentication. If your bundle version includes a Symfony security factory/listener, wire SAML into security.yml rather than manually creating tokens. Keep the SAML endpoints public and protect the rest:
security:
firewalls:
saml:
pattern: ^/saml
security: false
main:
anonymous: ~
# If the bundle exposes a security factory:
saml:
provider: saml_user_provider
check_path: /saml/acs
If the bundle does not provide a firewall factory, use a controller to call requireAuth(), then create a UsernamePasswordToken and store it in the token storage. This is also the cleanest place to provision local users.
Attribute-to-user provisioning. Most applications map a stable SAML attribute (eduPersonPrincipalName, mail, uid, or NameID) onto an application User row.
$attrs = $auth->getAttributes();
$uid = $attrs['eduPersonPrincipalName'][0]
?? $attrs['mail'][0]
?? $auth->getNameId();
$user = $userRepository->findOneBy(['samlId' => $uid]);
if (!$user) {
$user = new User();
$user->setSamlId($uid);
$user->setEmail($attrs['mail'][0] ?? null);
$user->setRoles(['ROLE_USER']);
$entityManager->persist($user);
$entityManager->flush();
}
Then set the security token:
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get('security.token_storage')->setToken($token);
On Symfony 2.x, use security.context instead of security.token_storage.
Login/logout routes. Define explicit routes so the IdP metadata and application links are stable:
public function loginAction()
{
$this->get('simplesamlphp_auth')->requireAuth([
'ReturnTo' => $this->generateUrl('app_home', [], UrlGeneratorInterface::ABSOLUTE_URL),
]);
}
public function logoutAction()
{
$this->get('simplesamlphp_auth')->logout(
$this->generateUrl('app_home', [], UrlGeneratorInterface::ABSOLUTE_URL)
);
}
Keep /saml/login, /saml/acs, /saml/metadata, and /saml/logout outside any authenticated firewall pattern.
Environment-specific IdP configuration. Use Symfony parameters to switch between a local test IdP and production IdP:
# app/config/parameters.yml
parameters:
saml_auth_source: default-sp
saml_idp_metadata: https://idp.example.com/metadata
hslavich_simplesamlphp:
simplesamlphp_dir: "%kernel.root_dir%/../vendor/simplesamlphp/simplesamlphp"
auth_source: "%saml_auth_source%"
For local development, use SimpleSAMLphp’s exampleauth or a test IdP rather than pointing at production.
Twig access to attributes. Do not call the auth service directly from Twig. Populate request attributes in a listener or controller:
$request->attributes->set('saml_attributes', $auth->getAttributes());
Then read them in Twig via app.request.attributes.get('saml_attributes'), or expose a small Twig extension.
Metadata endpoint. Point the SP entityID and ACS URL to Symfony routes and make sure the metadata consumed by the IdP matches those URLs exactly. If SimpleSAMLphp serves metadata itself, keep its URL in sync with the Symfony route configuration.
This bundle is effectively abandoned. The last release was in 2017, it has very few stars and no dependents. Expect Composer conflicts with Symfony 4+, newer PHP versions, and modern SimpleSAMLphp releases. Before adopting it, test installation against your framework version. For new projects, prefer direct simplesamlphp/simplesamlphp integration behind a small service, or a maintained SAML bundle.
Composer dependency constraints are the first blocker. The bundle’s composer.json likely pins old Symfony/SimpleSAMLphp versions. If composer require fails, do not force it blindly; either pin an older framework or wrap SimpleSAMLphp directly.
Session collision between Symfony and SimpleSAMLphp. Both use PHP sessions. Common symptoms are lost Symfony sessions after the IdP round trip, or SimpleSAMLphp overwriting application session data. Mitigations include configuring SimpleSAMLphp with a separate session name/save path, calling session_write_close() before requireAuth(), and verifying session.phpsession.* settings in SimpleSAMLphp.
Autoload and path issues. The simplesamlphp_dir must be the real SimpleSAMLphp installation directory containing lib/_autoload.php. Wrong paths produce class-not-found errors for SimpleSAML_Configuration/SimpleSAML_Auth_Simple. Ensure the directory is readable by the web server.
ReturnTo must be trusted. SimpleSAMLphp validates return URLs. Set trusted.url.domains in its config or use absolute Symfony-generated URLs. Do not pass user-supplied redirect targets into ReturnTo.
Logout is often local-only. logout() may clear the SimpleSAMLphp session without performing IdP single logout. If you need SLO, configure the IdP SLO endpoint and test the full redirect chain. Always redirect the user after logout.
Firewall ordering matters. SAML endpoints must be reachable anonymously. If your main firewall pattern catches /saml, the IdP POST will be redirected to a login page and authentication will fail with confusing loops.
Attribute names vary by IdP. Do not hard-code mail as the only identifier. Log the full attribute array during integration, then map defensively with fallbacks. Use getNameId() if the IdP only supplies a NameID.
Debugging is easiest through SimpleSAMLphp. Enable 'debug' => true and a file logging handler in SimpleSAMLphp’s config/config.php, then inspect var/log inside the SimpleSAMLphp directory. The admin UI at /simplesaml shows auth source and metadata status. Symfony’s profiler will not show SAML assertion details.
Test with a local IdP first. SimpleSAMLphp’s exampleauth auth source or a local test IdP lets you verify attribute mapping and redirect URLs before involving a real IdP. Production certificate and clock-skew issues are much harder to debug.
Sign AuthnRequests and validate IdP certificates. In production, require signed requests and validate the IdP signing certificate. Misconfigured certificates usually appear as generic “unable to validate request” or “response validation failed” errors in SimpleSAMLphp logs.
Extension points are limited. You can decorate the bundle’s auth service or override its service definition, but the bundle is thin. Custom user provisioning, role mapping, and audit logging belong in your application listeners/controllers, not in bundle configuration. Check Resources/config/services.xml and any compiler passes before overriding service IDs.
Plan a migration path. If this bundle becomes a blocker, isolate SAML behind your own SamlAuthenticator interface and swap the implementation. Direct SimpleSAMLphp integration or a maintained SAML bundle will be easier to support long term.
How can I help you explore Laravel packages today?