Nextcloud and Keycloak (SAML)


Preamble: we've started Single-Sign On implementation between our products, the ManageIQ supports SSO using SAML v2.0 and there is good documentation on it using Keycloak authentication server.
I did not find any SSO examples for Nextcloud and Keycloak with SAML protocol, so that's why I published this article.
Tip: if you are going integrate Nextcloud with Shibboleth - see https://help.nextcloud.com/t/how-does-the-user-saml-app-work/1419/5


Assume that you have installed Keycloak server and configured user authentication provider (we use Domino LDAP for this purpose).
Also assume that you have installed and configured Nextcloud and can login with admin account.

Step 1. Activate user_saml plugin in nextcloud


Hint: If you failed to configure SAML correctly - you can not login even with admin account. So I recommend to use two different browsers - stay logged as admin in one browser and test SAML login in another one. Alternatively if you failed to login as admin you can disable user_saml app from command line and login back as usual admin account.

sudo -u apache php console.php app:disable user_saml

Step 2. Go to "Admin -> SAML Authentication"


You have to fill following form to configure SAML on Nextcloud and to generate Metadata XML, which then will be imported to Keycloak server.


Some terms used in this form:

  • Service Provider (SP) - Nextcloud.
  • Identity Provider (IdP) - Keycloak.

SP and IdP exchanges information with XML messages, some part of this information can be encrypted and signed with private keys and certificates (!!! it's not related to HTTPS/SSL - it's another certificate).

Step 3. Configure user map attribute (user property) 

email - attribute which will be used to map user ID, we use email, but in your case it can be something else, like uid or username

Step 4. Generate certificate and private key on SP (Nextcloud)

From SP side you can provide X.509 certificate and Private key and sign XML messages with them, so lets generate it:

cd /var/www/html/nc
mkdir certs
cd certs
openssl req -newkey rsa:2048 -nodes -keyout user_saml.key \
        -x509 -days 1024 -out user_saml.crt

Click "ServiceProvider settings" link and copy content of files user_saml.crt to user_saml.key to the first and second field appropriately.

Step 5. Configure IdP (Keycloak) URL

Fortunately, Keycloak use only one URL endpoint for all  SAML requests:

http(s)://{host}:{port}/auth/realms/{realm}/protocol/saml

In Keycloak we use realm named 'master':


In our case specify in all three URL fields: http://172.20.140.174:8080/auth/realms/master/protocol/saml

Step 6. IdP (Keycloak) realm certificate and security settings

Copy it from: Realm settings -> Keys -> All -> Certificate

Configure Security Settings:

  • Offered:
    • Indicates whether the <samlp:AuthnRequest> messages sent by this SP will be signed. [Metadata of the SP will offer this info]
    • Indicates whether the <samlp:logoutRequest> messages sent by this SP will be signed.
    • Indicates whether the <samlp:logoutResponse> messages sent by this SP will be signed.
  • Required:
    • Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest> and <samlp:LogoutResponse> elements received by this SP to be signed.
    • Indicates a requirement for the <saml:Assertion> elements received by this SP to be signed. [Metadata of the SP will offer this info]
    • Indicates a requirement for the <saml:Assertion> elements received by this SP to be encrypted. (Update: Have some issue here, so could not configure Assertion encryption properly)


Step 7. Configure Keycloak client


If everything is ok, you will see green label "Metadata valid". Download it using nearby button.
It should looks like: https://drive.google.com/open?id=0B3eCoRSksDuBb25BQVRjY2g1ekk

Nextcloud is a client for Keycloak Identity Provider, so on Keycloak server "Clients -> Create -> Import: Select File", select downloaded Metadata XML, then Save.



You should get following client details:



Step 8. Create UID attribute mapper

We used email SAML attribute in Nextcloud, so we have to create the same in Keycloak, on tab "Mappers->Create":


  • Name: email
  • Mapper Type: User Property
  • Property: email
  • SAML Attribute Name: email
  • SAML Attribute NameFormat: "URI Reference".

Step 9. Configure Logout (SLO Request)

SSO assumes that you can do "single logout" also, so Keycloak should be able to send logout message to the clients (aka Service Providers, aka Nextcloud).
Go to "Fine Grain SAML Endpoint Configuration" and specify attribute "Logout Service Redirect Binding URL" Nextcloud SAML URL, but ending with /sls:
http://172.20.140.180/nc/index.php/apps/user_saml/saml/sls




That's all. From this point you can do login to Nextcloud using Keycloak SAML protocol and successfully logout.

Comments are welcome and if I missed something, please, point this out.


3 comments:

Wordpress Parallax-One theme


We use quite cool Parallax-One theme for our cloud representation website. But recently I had the issue after changed website hostname.

All uploaded resources, like http://hostname/wp-content/uploads/2016/08/icon8.png, were linked to old hostname. The theme saved links in wordpress option "theme_mods_Parallax-One", and does not renew it after moving to new hostname.

First thought is quick fix by updating this option directly in database:

mysql -u root -p
mysql> use  wordpress;
mysql> select option_id, option_value from wp_options where option_name = 'theme_mods_Parallax-One'
mysql> | 169 | a:35:{i:0;b:0;s:26:"parallax_one_logos_content";
       s:1255:"[{"text":"undefined","link":"#",
       "image_url":"http:\/\/old_hostname\/wp-content\/uploads\/2016\/08\/turnkey_logo.jpg",
       "title":"undefined","subtitle": ...

But wp_options are PHP serialized objects, so if length of new_hostname and old_hostname is not equal, you have got a problem. You have to change length of the string encoded as follows:
s:<string length>:"string value"
And if there is missmatched something - theme will not load.

So let me introduce a little addition to Parallax-One theme. This patch adds input field 'Uploads Resource Hostname' to the inc/customizer.php. On saving changes it updates all upload URL hostnames to the specified hostname.

--- /root/customizer.php        2016-10-07 07:50:12.044940980 +0000
+++ customizer.php      2016-10-10 07:56:31.812266652 +0000
@@ -903,6 +903,36 @@
                'section'               => 'parallax_one_general_section',
                'priority'      => 12,
        ));
+
+        /** FIX change uploads resources hostname **/
+       $wp_customize->add_setting( 'parallax_one_uploads_hostname', array(
+               'sanitize_callback' => 'parallax_one_sanitize_input',
+                'validate_callback' => 'update_uploads_hostname',
+                'transport' => 'postMessage'
+       ));
+       $wp_customize->add_control( 'parallax_one_uploads_hostname', array(
+               'label'                 => esc_html__('Uploads Resource Hostname','parallax-one'),
+               'section'               => 'parallax_one_general_section',
+               'priority'      => 13,
+       ));
+        function update_uploads_hostname($validity, $value) {
+          if (!isset($value) || $value == "" || $value == $_SERVER['HOST_NAME']) return $validity;
+          $mods = get_option("theme_mods_Parallax-One");
+          $replace = function (&$url, $new_hostname) {
+            $url = preg_replace('/(http[s]?:(\\\\)?\/(\\\\)?\/)[^\\\\\/]+((\\\\)?\/wp-content(\\\\)?\/uploads)/', "$1$new_hostname$4", $url);
+            $url = preg_replace('/((http[s]?:)?(\\\\)?\/(\\\\)?\/)[^\\\\\/]+((\\\\)?\/wp-content(\\\\)?\/themes)/', "$1$new_hostname$5", $url);
+          };
+          foreach (array_keys($mods) as $key) {
+            if (is_string($mods[$key])) $replace($mods[$key], $value);
+            if (is_object($mods[$key])) { //for URLs in attachments, saved as objects, go through all string properties
+              foreach ($mods[$key] as $prop=>$pvalue) {
+                if (is_string($pvalue)) $replace($mods[$key]->$prop, $value);
+              }
+            }
+          }
+          update_option( "theme_mods_Parallax-One", $mods );
+          return $validity;
+        }


        /*********************************/

1 comments: