We currently provide a service for students to read the minutes of student council meetings. Students have to authenticate with Shibboleth to get access. The current setup is based on apache2, mod_shibd and shibd. This is cumbersome to say the least. It requires this setup on every server this authentication is used, and there is no good setup to federate it from one server to another. It is also limited to apache2, which can be circumvented by providing only the protected resources by apache2. But all together, this is not an ideal solution.
The student council at ETH-Zurich already has a setup where they integrate Shibboleth into Keycloak, but by redirecting the login to an apache2 protected page. This requires the whole apache2, mod_shibd and shibd setup.
SAML all the way
This is where Keycloak, OpenID Connect and SAML come in. Shibboleth is nothing more than fancy SAML with some extra features — but it can be used as any other SAML Identity Provider (IdP). Keycloak on the other hand implements a SAML Service Provider (SP). So it looks like a perfect match.
Shibboleth provides a list of all SPs in the federation, where we already found a Keycloak setup. It was only a test setup, but worked flawlessly. So I contacted the administrator, to get some guidance on how to set it all up.
Our primary realm is completely pseudonymous, so we will only use pseudonymous identifiers. A list of identifiers supported attributes by the university IdP is public. We request the eduPersonTargetedID and eduPersonAffiliation. Therefore, we also need to configure Keycloak not to request any more data from the user, and also handle the student status from eduPersonAffiliation.
Shibboleth SAML in Keycloak
Setting up the Shibboleth in Keycloak is actually pretty simple:
- Add new SAML Identity Provider
- Request Certificate for communication with the SAML IdP
- Configure Certificate in Keycloak
- Add SAML SP to the Shibboleth Metadata File
- Disable Account Verification
- Test & Done
We will skip the simple tasks, to keep this short.
SAML Identity Provider
The first task is to set up a new SAML Identity Provider (Realm ⇾ Identity Providers ⇾ Add Provider ⇾ SAML v2.0). Below is our configuration, with some values redacted.
The relevant parts are:
- Service Provider Entity ID: Identifier of your Keycloak instance for the Shibboleth IdP
- Single Sign-On Service URL: Endpoint where the Shibboleth IdP is listening for login redirects
- Allow create: Allow the IdP to create new users on the Keycloak
- HTTP-POST Binding Response: needs to be enabled for us
- Validate Signature: Enforce signature verification for assertions coming from the IdP
- Validating X509 Certificates: PEM encoded cert of the Shibboleth IdP used for signing assertions
The next step is to get a certificate for your server. This certificate will only be used in communication with the SAML IdP. It does not need to be the same (and in our case it isn’t) as the web facing certificate. Our SP has some more information on the requirements of the certificate requirements. We generated our private key with OpenSSL, and let the CSR be signed by the university CA.
The certificate and private key need to be added to Keycloak, so it can decrypt the SAML assertions from the SP. This can also be done from the web interface, but is slightly hidden.
Go to Realm Settings ⇾ Keys ⇾ Providers ⇾ Add Keystore ⇾ RSA. There you can upload the private key and certificate as PEM encoded file. Afterwards, it should look like the picture below. We also deactivated the existing rsa-generated key pair, so Keycloak will always use the correct key. This can be done by editing the rsa-generated provider.
Shibboleth Metadata integration
The next step is to configure the IdP to interact with the SP. This could not be done by us, but has to be done manually by the IdP administrator. An excerpt from our final published metadata is:
Disable Account verification
We only want to use a pseudonymous identifier, and do not want to ask for any further details from the user when he first logs in. Some other people had a similar problem, but their approach requires more changes to Keycloak. We rely on the IdP to provide a unique static identifier, and not depend on anything else. So we disabled any validation in the registration authentication flow (Authentication ⇾ Flows ⇾ Registration).
The username is also not user-modifiable and only comes from the trusted IdP, so the user should not be able to spoof another account.
Testing & Debugging
Finally, test the setup. I also used a Chrome extension to visualize the SAML requests. You can also enable TRACE logging in Keycloak, if it still doesn’t work. With our setup, the SingleLogoutService is not working correctly, but this is most likely due to the fact, that the Shibboleth IdP login does not store any session.
From this setup, you can delegate any authentication with OpenIDConnect between your application and Keycloak, who in turn delegates it to shibboleth.
Bonus: SAML Attribute Mappers
We also request the eduPersonAffiliation attribute from the IdP. We have two choices to store this information in Keycloak, either store it as an attribute or role for the user in Keycloak. As this attribute contains a list, this is not ideal. So we also store the affiliation as role. The config can be seen below.