Skip to content

Client Certificate Authentication Support for both Nextcloud and Collabora etc #52198

@extorn

Description

@extorn

** Nextcloud does not have internal support for client certificates being used for http authentication **

This is a problem when accessing the /settings/admin/overview page as it cannot connect to my server (403 error)
This is also a problem when integrating with 3rd party apps such as Collabora on my site (also protected with client certificates

** Proposed solution **

I have edited the Client.php file: /app/www/public/lib/private/Http/Client/Client.php to add support. The diff below will allow users to enable this in the main nextcloud config.php file and also specify a path to appropriate certificate, key, and if required, password for that key (all in pem format). It would be great if you could take a look at the diff and merge this into the code for nextcloud for an upcoming release as I've seen that others also desire this feature. Many thanks.

** Usage **

  1. change the /app/www/public/lib/private/Http/Client/Client.php file as shown below
  2. One of a or b
    2a. copy the client ssl certificate to $SERVERROOT/config/client_ssl/cert.pem and the key to $SERVERROOT/config/client_ssl/key.pem
    2b. edit config.php (for me: /config/www/nextcloud/config/config.php) to set the locaton for these files. e.g.
    'internal_client_authentication_cert' => '/config/client_ssl/nextcloud_server_cert.pem',
    'internal_client_authentication_key' => '/config/client_ssl/nextcloud_server_key.pem',
    'internal_client_authentication_key_pass' => 'my password',
  3. edit config.php (for me: /config/www/nextcloud/config/config.php) to enable client authentication support
    'client_authentication_enabled' => true,
+++ Client.php
@@ -5,6 +5,8 @@
  * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  * SPDX-License-Identifier: AGPL-3.0-only
+ *
+ * /app/www/public/lib/private/Http/Client/Client.php
  */
 namespace OC\Http\Client;

@@ -80,6 +82,14 @@

                $options = array_merge($defaults, $options);

+               if ($this->isClientAuthenticationEnabled($options)) {
+                    $client_auth_options = [
+                        RequestOptions::CERT => $this->getClientAuthenticationCert($options),
+                        RequestOptions::SSL_KEY => $this->getClientAuthenticationKey($options),
+                    ];
+                    $options = array_merge($client_auth_options, $options);
+                }
+
                if (!isset($options[RequestOptions::HEADERS]['User-Agent'])) {
                        $options[RequestOptions::HEADERS]['User-Agent'] = 'Nextcloud Server Crawler';
                }
@@ -107,6 +117,37 @@

                return $this->certificateManager->getAbsoluteBundlePath();
        }
+
+        private function isClientAuthenticationEnabled(array $options): bool {
+                if (($options['nextcloud']['client_authentication_enabled'] ?? false) ||
+                        $this->config->getSystemValueBool('client_authentication_enabled', false)) {
+                        return true;
+                }
+
+                return false;
+        }
+
+        private function getClientAuthenticationCert(array $options): ?string {
+                $clientCert = $this->config->getSystemValueString('internal_client_authentication_cert', \OC::$SERVERROOT . '/config/client_ssl/cert.pem');
+                if ($clientCert === '') {
+                        return null;
+                }
+                return $clientCert;
+        }
+
+/* PHP8+        private function getClientAuthenticationKey(array $options): ?array|?string {*/
+        private function getClientAuthenticationKey(array $options) {
+                $clientKey = $this->config->getSystemValueString('internal_client_authentication_key', \OC::$SERVERROOT . '/config/client_ssl/key.pem');
+                $clientKeyPass = $this->config->getSystemValueString('internal_client_authentication_key_pass', '<not specified>');
+                if ($clientKey === '') {
+                        return null;
+                }
+                if ($clientKeyPass === '<not specified>') {
+                        return $clientKey;
+                } else {
+                        return array($clientKey, $clientKeyPass);
+                }
+        }

        /**
         * Returns a null or an associative array specifying the proxy URI for```

**Here is the full file for your convenience:**

[Client.php.txt](https://github.com/user-attachments/files/19754845/Client.php.txt)

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions