I’ve been running my nextcloud instance for quite some years now, and I finally decided to change its authentication from LDAP to SAML for a better single sign on experience.
By using keycloak as IdP there’ll also be an option to enable multi factor authentication (MFA) for all connected applications at once.
Where I come from
As I mentioned I’ve been authenticating my nextcloud instance against my (Samba based) LDAP directory service.
Maybe I’ll find some time to describe that in detail later on, but for now let’s assume that a working LDAP based nextcloud is up and running.
What needs to be done?
First of all we’ll need a nextcloud app that can handle SAML authentication. And (not very surprising) there’s one ready to be deployed in the app store called user_saml
.
What settings do we need…
… for keycloak (IdP)?
Client settings | |
Client ID | https://cloud.mydomain.de |
Valid redirect URLs | https://cloud.mydomain.de/index.php/apps/user_saml/saml/acs |
Sign documents | On |
Sign assertions | On |
… for nextcloud (user_saml, SP)?
Go to "Administrative Settings"
and select "SSO & SAML Authentication"
.
General | |
Attribute to map the UID to | uid |
Service Provider Data | |
Name ID format | Transient |
X.509 certificate of the Service Provider | Can be exported/extracted from keycloak (s. below) |
Private key of the Service Provider | Can be exported/extracted from keycloak (s. below) |
Service Provider EntityId (optional) | https://cloud.mydomain.de |
Identity Provider Data | |
Identifier of the IdP entity | https://keycloak.mydomain.de/realms/MYDOMAIN |
Identifier of the IdP entity | https://keycloak.mydomain.de/realms/MYDOMAIN/protocol/saml |
Security settings | |
Signatures and encryption offered | Select all |
Signatures and encryption required | Select the first two |
Even more information
This is a basic application configuration:
linux # sudo -u www-data php occ config:list user_saml
{
"apps": {
"user_saml": {
"installed_version": "6.6.0",
"types": "authentication",
"enabled": "yes",
"type": "saml",
"general-require_provisioned_account": "1",
"general-allow_multiple_user_back_ends": "1"
}
}
}
So in my case I want to re-use the existing LDAP accounts and just change the authentication. So for now we’ll keep both LDAP and SAML authentication enabled (allow_multiple_user_back_ends": "1"
) and we’ll not auto-create new users, instead they need to be provided by another source (LDAP in my case, require_provisioned_account": "1"
).
Detailed user_saml app configuration:
linux # sudo -u www-data php occ saml:config:get
- 1:
- general-idp0_display_name: SSO Login (Keycloak)
- general-uid_mapping: uid
- sp-entityId: https://cloud.mydomain.de
- idp-entityId: https://keycloak.mydomain.de/realms/MYDOMAIN
- idp-singleSignOnService.url: https://keycloak.mydomain.de/realms/MYDOMAIN/protocol/saml
- sp-x509cert: -----BEGIN CERTIFICATE-----
MIICwTCCAakCBgGXhw/ZmzANBgkqhkiG9w0BAQsFADAkMSIwIAYDVQQDDBlodHRw
<...>
zbk2xa10eF0Iv5P65AWl6FNU7KAkwUxlffLqneXdvZc0o3bXKw==
-----END CERTIFICATE-----
- sp-privateKey: -----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDAyowcmut/n1FS
<...>
ZEEg1UCBooxPcH6uH0amPvhsuUO2IDg7djoaU0P/elOwN5Tr6Av3tcj0hkpXYZYK
NnSt+vDb7e63a5eM2Sn4lQ==
-----END PRIVATE KEY-----
- idp-x509cert: -----BEGIN CERTIFICATE-----
MIICnzCCAYcCBgF/H7/K6zANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhMSU5V
<...>
P8dQpwufWY7z/Wlp57YB46QHFYjyK7OIJaf1jPyoaaNpqm3PpSJnXSaIeaWDmLYO
/LYe
-----END CERTIFICATE-----
- security-wantMessagesSigned: 1
- security-wantAssertionsSigned: 1
- security-wantAssertionsEncrypted: 0
- security-wantNameIdEncrypted: 0
- security-nameIdEncrypted: 1
- security-authnRequestsSigned: 1
- security-logoutRequestSigned: 1
- security-logoutResponseSigned: 1
- security-signMetadata: 1
- security-wantNameId: 0
- security-wantXMLValidation: 1
- sp-name-id-format: urn:oasis:names:tc:SAML:2.0:nameid-format:transient
- saml-attribute-mapping-displayName_mapping: displayname
- saml-attribute-mapping-email_mapping: email
Make sure to get the right certificates/keys from keycloak:
Getting certificates and keys
The idp-x509cert
can be retrieved from your IdP’s metadata (URL):
linux # curl -s https://keycloak.mydomain.de/realms/MYDOMAIN/protocol/saml/descriptor | xmllint -format - > /tmp/out.xml
<...>
linux # xmllint --xpath "/*[local-name()='EntityDescriptor' and namespace-uri()='urn:oasis:names:tc:SAML:2.0:metadata']/*[local-name()='IDPSSODescriptor' and namespace-uri()='urn:oasis:names:tc:SAML:2.0:metadata']/*[local-name()='KeyDescriptor' and namespace-uri()='urn:oasis:names:tc:SAML:2.0:metadata']/*[local-name()='KeyInfo' and namespace-uri()='http://www.w3.org/2000/09/xmldsig#']/*[local-name()='X509Data' and namespace-uri()='http://www.w3.org/2000/09/xmldsig#']/*[local-name()='X509Certificate' and namespace-uri()='http://www.w3.org/2000/09/xmldsig#']/text()" /tmp/out.xml > /tmp/idp.pem
<...>
This will however only deliver the content of the certificate, make sure to add the header and footer to this file:
-----BEGIN CERTIFICATE-----
<... content should be here ...>
-----END CERTIFICATE-----
Verify the certificate with:
linux # openssl x509 -in /tmp/idp.pem
This will also add the typical line breaks upon output. If you want to see (only) the plain-text output, add options -noout
and -text
:
linux # openssl x509 -in /tmp/idp.pem -noout -text
The sp-x509cert
and the sp-privateKey
will both be created by keycloak while creating a new client.
They can be exported by selecting the nextcloud client from "Clients"
. Then select the tab "Keys"
, go to "Certificate"
and "Export"
this key in "Archive format"
"PKCS12"
(you’ll be forced to protect the exported cert/key with a password!).
The export will then be downloaded as a file called keystore.p12
. You can export cert and key in unencrypted PEM
format like this:
linux # openssl pkcs12 -legacy -in keystore.p12 -out sp.key -nocerts -nodes
Enter Import Password:
linux # openssl pkcs12 -legacy -in keystore.p12 -out sp.pem -clcerts -nokeys
Enter Import Password: