From 33ec3edb905ac0b8060003eea6c3fc5d2f8a77e3 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 10 Sep 2024 11:47:58 +0200 Subject: [PATCH 1/5] ci: Update workflows [skip-ci] Signed-off-by: Joas Schilling Signed-off-by: Sebastian Sterk <7263970+sebastiansterk@users.noreply.github.com> --- .github/workflows/command-rebase.yml | 51 ---------------------------- 1 file changed, 51 deletions(-) delete mode 100644 .github/workflows/command-rebase.yml diff --git a/.github/workflows/command-rebase.yml b/.github/workflows/command-rebase.yml deleted file mode 100644 index ec95ccb..0000000 --- a/.github/workflows/command-rebase.yml +++ /dev/null @@ -1,51 +0,0 @@ -# This workflow is provided via the organization template repository -# -# https://github.com/nextcloud/.github -# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization - -name: Rebase command - -on: - issue_comment: - types: created - -permissions: - contents: read - -jobs: - rebase: - runs-on: ubuntu-latest - permissions: - contents: none - - # On pull requests and if the comment starts with `/rebase` - if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/rebase') - - steps: - - name: Add reaction on start - uses: peter-evans/create-or-update-comment@ca08ebd5dc95aa0cd97021e9708fcd6b87138c9b # v3.0.1 - with: - token: ${{ secrets.COMMAND_BOT_PAT }} - repository: ${{ github.event.repository.full_name }} - comment-id: ${{ github.event.comment.id }} - reaction-type: "+1" - - - name: Checkout the latest code - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - with: - fetch-depth: 0 - token: ${{ secrets.COMMAND_BOT_PAT }} - - - name: Automatic Rebase - uses: cirrus-actions/rebase@b87d48154a87a85666003575337e27b8cd65f691 # 1.8 - env: - GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }} - - - name: Add reaction on failure - uses: peter-evans/create-or-update-comment@ca08ebd5dc95aa0cd97021e9708fcd6b87138c9b # v3.0.1 - if: failure() - with: - token: ${{ secrets.COMMAND_BOT_PAT }} - repository: ${{ github.event.repository.full_name }} - comment-id: ${{ github.event.comment.id }} - reaction-type: "-1" From 1efd392f16fc1b7aaf8e87a177000dad09db26c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 20:47:58 +0000 Subject: [PATCH 2/5] Bump symfony/process from 5.4.7 to 5.4.46 Bumps [symfony/process](https://github.com/symfony/process) from 5.4.7 to 5.4.46. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/7.1/CHANGELOG.md) - [Commits](https://github.com/symfony/process/compare/v5.4.7...v5.4.46) --- updated-dependencies: - dependency-name: symfony/process dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: Sebastian Sterk <7263970+sebastiansterk@users.noreply.github.com> --- composer.lock | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/composer.lock b/composer.lock index 54c66d8..df57c57 100644 --- a/composer.lock +++ b/composer.lock @@ -3707,26 +3707,23 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.25.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -3770,7 +3767,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -3786,7 +3783,7 @@ "type": "tidelift" } ], - "time": "2022-03-04T08:16:47+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php81", @@ -3869,16 +3866,16 @@ }, { "name": "symfony/process", - "version": "v5.4.7", + "version": "v5.4.46", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb" + "reference": "01906871cb9b5e3cf872863b91aba4ec9767daf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/38a44b2517b470a436e1c944bf9b9ba3961137fb", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb", + "url": "https://api.github.com/repos/symfony/process/zipball/01906871cb9b5e3cf872863b91aba4ec9767daf4", + "reference": "01906871cb9b5e3cf872863b91aba4ec9767daf4", "shasum": "" }, "require": { @@ -3911,7 +3908,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.7" + "source": "https://github.com/symfony/process/tree/v5.4.46" }, "funding": [ { @@ -3927,7 +3924,7 @@ "type": "tidelift" } ], - "time": "2022-03-18T16:18:52+00:00" + "time": "2024-11-06T09:18:28+00:00" }, { "name": "symfony/service-contracts", @@ -4279,5 +4276,5 @@ "platform-overrides": { "php": "7.3" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } From 2aeb5a26b88b87cf2abb0923cf55c492fc6a02f9 Mon Sep 17 00:00:00 2001 From: Ralf Date: Mon, 28 Oct 2024 20:18:45 +0100 Subject: [PATCH 3/5] Make NC30 compatible Make the app compatible with Nextcloud 30 Signed-off-by: Ralf Signed-off-by: Sebastian Sterk <7263970+sebastiansterk@users.noreply.github.com> --- appinfo/info.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index 949c081..34cbe12 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -16,7 +16,7 @@ Read the [documentation](https://github.com/nextcloud/user_external#readme) to learn how to configure it! ]]> - 3.4.0 + 3.5.0 agpl Robin Appelman UserExternal @@ -33,6 +33,6 @@ Read the [documentation](https://github.com/nextcloud/user_external#readme) to l https://github.com/nextcloud/user_external/issues https://github.com/nextcloud/user_external.git - + From 6fca339250823c646a79305be962e977845736af Mon Sep 17 00:00:00 2001 From: Sebastian Sterk <7263970+sebastiansterk@users.noreply.github.com> Date: Fri, 25 Jul 2025 00:02:44 +0200 Subject: [PATCH 4/5] feat: add http post generic auth Signed-off-by: Sebastian Sterk <7263970+sebastiansterk@users.noreply.github.com> --- README.md | 50 +++++++++++++++++++++ appinfo/info.xml | 3 +- lib/HTTP.php | 115 +++++++++++++++++++++++++++++++++++++++++++++++ tests/config.php | 8 ++++ tests/http.php | 40 +++++++++++++++++ 5 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 lib/HTTP.php create mode 100644 tests/http.php diff --git a/README.md b/README.md index e4114dc..d562766 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,56 @@ Add the following to your `config.php`: [BasicAuth_0]: https://en.wikipedia.org/wiki/Basic_access_authentication +HTTP (Generic HTTP Auth Interface) +------ + +Authenticate users against a generic HTTP authentication interface. This backend sends HTTP POST requests with user credentials to a configured endpoint and expects specific response codes for authentication validation. + +### Configuration +The HTTP backend accepts three parameters: endpoint URL, optional hash algorithm, and optional access key. + +**⚠⚠ Warning:** make sure to use the URL of a correctly configured HTTP authentication server. The server must validate credentials properly and return HTTP 202 for successful authentication. ⚠⚠ + +Add the following to your `config.php`: + + 'user_backends' => array( + array( + 'class' => '\OCA\UserExternal\HTTP', + 'arguments' => array('https://example.com/auth_endpoint'), + ), + ), + +For password hashing (e.g., MD5, SHA1, SHA256), add the hash algorithm as second parameter: + + 'user_backends' => array( + array( + 'class' => '\OCA\UserExternal\HTTP', + 'arguments' => array('https://example.com/auth_endpoint', 'md5'), + ), + ), + +For additional security with an access key: + + 'user_backends' => array( + array( + 'class' => '\OCA\UserExternal\HTTP', + 'arguments' => array('https://example.com/auth_endpoint', 'sha1', 'your_secret_access_key'), + ), + ), + +### HTTP Request Format +The backend sends POST requests with the following parameters: +- `user`: The username +- `password`: The password (hashed if hash algorithm is specified) +- `accessKey`: The access key (if provided) + +### Expected Response +The HTTP server must return HTTP status code **202** for successful authentication. Any other status code is treated as authentication failure. + +### Dependencies +Uses Nextcloud's built-in HTTP client service (no additional dependencies required). + + SSH --- diff --git a/appinfo/info.xml b/appinfo/info.xml index 34cbe12..3e333a6 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -3,7 +3,7 @@ xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd"> user_external External user authentication - Use external user authentication methods like IMAP, SMB, FTP, WebDAV, HTTP BasicAuth, SSH and XMPP + Use external user authentication methods like IMAP, SMB, FTP, WebDAV, HTTP BasicAuth, HTTP (Generic), SSH and XMPP + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\UserExternal; + +use OCP\Http\Client\IClientService; + +/** + * User authentication against a generic HTTP auth interface + * + * @category Apps + * @package UserExternal + * @author Sebastian Sterk https://wiuwiu.de/Imprint + * @license http://www.gnu.org/licenses/agpl AGPL + */ +class HTTP extends Base { + private $hashAlgo; + private $accessKey; + private $authenticationEndpoint; + private $httpClientService; + + /** + * Create new HTTP authentication provider + * + * @param string $authenticationEndpoint The HTTP endpoint URL for authentication + * @param string|false $hashAlgo Hash algorithm for password (false for plain text) + * @param string $accessKey Access key for additional security + */ + public function __construct($authenticationEndpoint, $hashAlgo = false, $accessKey = '') { + parent::__construct($authenticationEndpoint); + $this->authenticationEndpoint = $authenticationEndpoint; + $this->hashAlgo = $hashAlgo; + $this->accessKey = $accessKey; + $this->httpClientService = \OC::$server->get(IClientService::class); + } + + /** + * Send user credentials to HTTP endpoint + * + * @param string $user The username + * @param string $password The password + * + * @return bool True if authentication successful, false otherwise + */ + public function sendUserData($user, $password) { + if ($this->hashAlgo !== false) { + $password = $this->hashPassword($password); + } + + try { + $client = $this->httpClientService->newClient(); + + $response = $client->post($this->authenticationEndpoint, [ + 'form_params' => [ + 'accessKey' => $this->accessKey, + 'user' => $user, + 'password' => $password + ], + 'timeout' => 10, + ]); + + $statusCode = $response->getStatusCode(); + + if ($statusCode === 202) { + return true; + } else { + return false; + } + } catch (\Exception $e) { + \OC::$server->getLogger()->error( + 'ERROR: Could not connect to HTTP auth endpoint: ' . $e->getMessage(), + ['app' => 'user_external'] + ); + return false; + } + } + + /** + * Hash password using configured algorithm + * + * @param string $password The plain text password + * + * @return string The hashed password + */ + private function hashPassword($password) { + return hash($this->hashAlgo, $password); + } + + /** + * Check if the password is correct without logging in the user + * + * @param string $uid The username + * @param string $password The password + * + * @return string|false The username on success, false on failure + */ + public function checkPassword($uid, $password) { + if (isset($uid) && isset($password)) { + $authenticationStatus = $this->sendUserData($uid, $password); + if ($authenticationStatus) { + $uid = mb_strtolower($uid); + $this->storeUser($uid); + return $uid; + } else { + return false; + } + } + return false; + } +} diff --git a/tests/config.php b/tests/config.php index 3cfadba..aa48028 100644 --- a/tests/config.php +++ b/tests/config.php @@ -32,4 +32,12 @@ 'user' => 'test',//valid username/password combination 'password' => 'test', ), + 'http' => array( + 'run' => false, + 'endpoint' => 'localhost/http_auth', + 'hashAlgo' => false, // or 'md5', 'sha1', etc. + 'accessKey' => 'your_access_key', + 'user' => 'test',//valid username/password combination + 'password' => 'test', + ), ); diff --git a/tests/http.php b/tests/http.php new file mode 100644 index 0000000..885d6ef --- /dev/null +++ b/tests/http.php @@ -0,0 +1,40 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class Test_User_HTTP extends \Test\TestCase { + /** + * @var OC_User_HTTP $instance + */ + private $instance; + + private function getConfig() { + return include(__DIR__.'/config.php'); + } + + public function skip() { + $config = $this->getConfig(); + $this->skipUnless($config['http']['run']); + } + + protected function setUp() { + parent::setUp(); + + $config = $this->getConfig(); + $this->instance = new OC_User_HTTP( + $config['http']['endpoint'], + $config['http']['hashAlgo'], + $config['http']['accessKey'] + ); + } + + public function testLogin() { + $config = $this->getConfig(); + $this->assertEquals($config['http']['user'], $this->instance->checkPassword($config['http']['user'], $config['http']['password'])); + $this->assertFalse($this->instance->checkPassword($config['http']['user'], $config['http']['password'].'foo')); + } +} From 06d086b365270abb947de9c57de422b9ed770877 Mon Sep 17 00:00:00 2001 From: Sebastian Sterk <7263970+sebastiansterk@users.noreply.github.com> Date: Wed, 15 Oct 2025 21:25:34 +0200 Subject: [PATCH 5/5] chore: add protocoll for http_auth endpoint Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Sebastian Sterk <7263970+sebastiansterk@users.noreply.github.com> --- tests/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/config.php b/tests/config.php index aa48028..8bd30e8 100644 --- a/tests/config.php +++ b/tests/config.php @@ -34,7 +34,7 @@ ), 'http' => array( 'run' => false, - 'endpoint' => 'localhost/http_auth', + 'endpoint' => 'http://localhost/http_auth', 'hashAlgo' => false, // or 'md5', 'sha1', etc. 'accessKey' => 'your_access_key', 'user' => 'test',//valid username/password combination