feat: add OIDC admin login for WHMCS
Introduces a new OIDC (OpenID Connect) based authentication mechanism for WHMCS admins, allowing secure logins using an external OIDC provider. This commit adds necessary configuration files, updates the .gitignore to exclude vendor-specific files and the config.php, adds a LICENSE file, and outlines the installation and usage in the README.md. The key functionalities include setting up an OIDC client with the required scopes and handling user authentication and session management within WHMCS. This enhancement leverages openid-connect-php library for OIDC interactions and streamlines admin login processes, aiming to improve security and ease of use by integrating with modern identity providers. Note: This module is a proof of concept and should be used cautiously in production environments.
This commit is contained in:
commit
28ae0b2761
7 changed files with 420 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
vendor/
|
||||
config.php
|
19
LICENSE
Normal file
19
LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2024 Kumi Systems e.U. <support@kumi.systems>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
45
README.md
Normal file
45
README.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
# Simple WHMCS OIDC Admin Login
|
||||
|
||||
This is a simple WHMCS OIDC Admin Login module that allows WHMCS administrators
|
||||
to login to the WHMCS admin area using an OIDC provider.
|
||||
|
||||
It is not a full-fledged WHMCS module (yet), but so far only a script that
|
||||
allows WHMCS administrators to login to the WHMCS admin area using an OIDC
|
||||
provider.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
The module was developed as a proof of concept and is not intended for
|
||||
production use. It may have security vulnerabilities and may not work as
|
||||
expected.
|
||||
|
||||
This module is provided as-is, not supported, and not endorsed by WHMCS. Use it
|
||||
at your own risk.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Install the module by uploading it to your WHMCS installation directory.
|
||||
|
||||
```bash
|
||||
cd /path/to/whmcs/modules/security
|
||||
git clone https://git.private.coffee/kumisystems/whmcs-oidc_admin_login.git oidc_admin_login
|
||||
```
|
||||
|
||||
2. Configure the module by editing the `oidc_admin_login/config.php` file.
|
||||
|
||||
## Usage
|
||||
|
||||
You can access the OIDC Admin Login page by visiting the following URL:
|
||||
|
||||
```
|
||||
https://your-whmcs-domain.com/modules/security/oidc_admin_login.php
|
||||
```
|
||||
|
||||
If you are not logged in, you will be redirected to the OIDC provider login
|
||||
page. After you have logged in, you will be redirected back to the WHMCS admin
|
||||
area.
|
||||
|
||||
## License
|
||||
|
||||
This module is licensed under the MIT License. See the [LICENSE](LICENSE) file
|
||||
for details.
|
5
composer.json
Normal file
5
composer.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"require": {
|
||||
"jumbojett/openid-connect-php": "^1.0"
|
||||
}
|
||||
}
|
287
composer.lock
generated
Normal file
287
composer.lock
generated
Normal file
|
@ -0,0 +1,287 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c6deed93995bf2c39b35a421c16edbdd",
|
||||
"packages": [
|
||||
{
|
||||
"name": "jumbojett/openid-connect-php",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jumbojett/OpenID-Connect-PHP.git",
|
||||
"reference": "4af1d11497ec765dccddf928c14c04535ca96017"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/jumbojett/OpenID-Connect-PHP/zipball/4af1d11497ec765dccddf928c14c04535ca96017",
|
||||
"reference": "4af1d11497ec765dccddf928c14c04535ca96017",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"php": ">=7.0",
|
||||
"phpseclib/phpseclib": "~3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"yoast/phpunit-polyfills": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"description": "Bare-bones OpenID Connect client",
|
||||
"support": {
|
||||
"issues": "https://github.com/jumbojett/OpenID-Connect-PHP/issues",
|
||||
"source": "https://github.com/jumbojett/OpenID-Connect-PHP/tree/v1.0.0"
|
||||
},
|
||||
"time": "2023-12-13T09:52:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
"version": "v2.6.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/constant_time_encoding.git",
|
||||
"reference": "58c3f47f650c94ec05a151692652a868995d2938"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/58c3f47f650c94ec05a151692652a868995d2938",
|
||||
"reference": "58c3f47f650c94ec05a151692652a868995d2938",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7|^8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6|^7|^8|^9",
|
||||
"vimeo/psalm": "^1|^2|^3|^4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ParagonIE\\ConstantTime\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Steve 'Sc00bz' Thomas",
|
||||
"email": "steve@tobtu.com",
|
||||
"homepage": "https://www.tobtu.com",
|
||||
"role": "Original Developer"
|
||||
}
|
||||
],
|
||||
"description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
|
||||
"keywords": [
|
||||
"base16",
|
||||
"base32",
|
||||
"base32_decode",
|
||||
"base32_encode",
|
||||
"base64",
|
||||
"base64_decode",
|
||||
"base64_encode",
|
||||
"bin2hex",
|
||||
"encoding",
|
||||
"hex",
|
||||
"hex2bin",
|
||||
"rfc4648"
|
||||
],
|
||||
"support": {
|
||||
"email": "info@paragonie.com",
|
||||
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
|
||||
"source": "https://github.com/paragonie/constant_time_encoding"
|
||||
},
|
||||
"time": "2022-06-14T06:56:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v9.99.100",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">= 7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*",
|
||||
"vimeo/psalm": "^1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"polyfill",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"support": {
|
||||
"email": "info@paragonie.com",
|
||||
"issues": "https://github.com/paragonie/random_compat/issues",
|
||||
"source": "https://github.com/paragonie/random_compat"
|
||||
},
|
||||
"time": "2020-10-15T08:29:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "3.0.37",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "cfa2013d0f68c062055180dd4328cc8b9d1f30b8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/cfa2013d0f68c062055180dd4328cc8b9d1f30b8",
|
||||
"reference": "cfa2013d0f68c062055180dd4328cc8b9d1f30b8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"paragonie/constant_time_encoding": "^1|^2",
|
||||
"paragonie/random_compat": "^1.4|^2.0|^9.99.99",
|
||||
"php": ">=5.6.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Install the DOM extension to load XML formatted public keys.",
|
||||
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
|
||||
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
|
||||
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
|
||||
"ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"phpseclib/bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"phpseclib3\\": "phpseclib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jim Wigginton",
|
||||
"email": "terrafrost@php.net",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Patrick Monnerat",
|
||||
"email": "pm@datasphere.ch",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Andreas Fischer",
|
||||
"email": "bantu@phpbb.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Hans-Jürgen Petrich",
|
||||
"email": "petrich@tronic-media.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "graham@alt-three.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
|
||||
"homepage": "http://phpseclib.sourceforge.net",
|
||||
"keywords": [
|
||||
"BigInteger",
|
||||
"aes",
|
||||
"asn.1",
|
||||
"asn1",
|
||||
"blowfish",
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"encryption",
|
||||
"rsa",
|
||||
"security",
|
||||
"sftp",
|
||||
"signature",
|
||||
"signing",
|
||||
"ssh",
|
||||
"twofish",
|
||||
"x.509",
|
||||
"x509"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.37"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/terrafrost",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpseclib",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-03T02:14:58+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.2.0"
|
||||
}
|
11
config.dist.php
Normal file
11
config.dist.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
if (!defined("WHMCS")) {
|
||||
die("This file cannot be accessed directly");
|
||||
}
|
||||
|
||||
// OIDC Provider details
|
||||
$oidcProviderUrl = 'https://kumidc.local'; // The URL of your OIDC Provider
|
||||
$clientID = '123456'; // Your OIDC Client ID
|
||||
$clientSecret = 'thisisaverylongsecretstring'; // Your OIDC Client Secret
|
||||
|
51
oidc_admin_login.php
Normal file
51
oidc_admin_login.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
require_once "../../../init.php";
|
||||
|
||||
require_once "config.php";
|
||||
|
||||
use Jumbojett\OpenIDConnectClient;
|
||||
|
||||
// Initialize the OIDC client
|
||||
$oidc = new OpenIDConnectClient($oidcProviderUrl, $clientID, $clientSecret);
|
||||
$oidc->addScope(['openid', 'email', 'profile']);
|
||||
|
||||
try {
|
||||
// Authenticate the user with the OIDC provider
|
||||
$oidc->authenticate();
|
||||
|
||||
// Fetch the user's details
|
||||
$userInfo = $oidc->requestUserInfo();
|
||||
|
||||
// The 'preferred_username' claim will be used as the WHMCS username
|
||||
if (isset($userInfo->preferred_username)) {
|
||||
$username = $userInfo->preferred_username;
|
||||
|
||||
// Initialize WHMCS authentication class
|
||||
$auth = new WHMCS\Auth();
|
||||
|
||||
// Attempt to find and authenticate the user by username
|
||||
if ($auth->getInfobyUsername($username)) {
|
||||
// Set session variables for the logged-in user
|
||||
$auth->setSessionVars();
|
||||
|
||||
$redirectUri = '/admin/';
|
||||
header('Location: ' . $redirectUri);
|
||||
exit;
|
||||
} else {
|
||||
// Handle the error case where the username doesn't exist in WHMCS
|
||||
error_log("OIDC SSO login failed: Username not found in WHMCS");
|
||||
// TODO: Redirect to a failure page
|
||||
die("OIDC SSO login failed: Username not found in WHMCS");
|
||||
}
|
||||
} else {
|
||||
// Handle missing username claim
|
||||
error_log("OIDC SSO login failed: Username claim not found in user info");
|
||||
exit;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Handle errors, such as authentication failures
|
||||
error_log("OIDC SSO login error: " . $e->getMessage());
|
||||
die("OIDC SSO login error: " . $e->getMessage());
|
||||
}
|
Loading…
Reference in a new issue