Skip to content

Commit

Permalink
Merge pull request Leantime#2747 from xdubx/master
Browse files Browse the repository at this point in the history
fix: public key creation based on e and n
  • Loading branch information
marcelfolaron authored Oct 15, 2024
2 parents b712d67 + 7ff8f0c commit 0f4fdb0
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 10 deletions.
5 changes: 5 additions & 0 deletions app/Core/Configuration/DefaultConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ class DefaultConfig
*/
public string $oidcClientSecret = '';

/**
* @var string Custom Auto discover URL
*/
public string $oidcAutoDiscoverUrl = '';

/**
* @var string OIDC Auth URL
*/
Expand Down
1 change: 1 addition & 0 deletions app/Core/Configuration/Environment.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class Environment implements ArrayAccess, ConfigContract
'ldapDomain' => 'LEAN_LDAP_LDAP_DOMAIN',
'oidcClientId' => 'LEAN_OIDC_CLIENT_ID',
'oidcClientSecret' => 'LEAN_OIDC_CLIENT_SECRET',
'oidcAutoDiscoverUrl' => 'LEAN_OIDC_AUTO_DISCOVER',
'oidcAuthUrl' => 'LEAN_OIDC_AUTH_URL_OVERRIDE',
'oidcTokenUrl' => 'LEAN_OIDC_TOKEN_URL_OVERRIDE',
'oidcJwksUrl' => 'LEAN_OIDC_JWKS_URL_OVERRIDE',
Expand Down
45 changes: 39 additions & 6 deletions app/Domain/Oidc/Services/Oidc.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use Leantime\Domain\Users\Repositories\Users as UserRepository;
use OpenSSLAsymmetricKey;
use Symfony\Component\HttpFoundation\Response;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Math\BigInteger;

/**
*
Expand All @@ -28,6 +30,7 @@ class Oidc
private bool $configLoaded = false;

private string $providerUrl = '';
private string $autoDiscoverUrl = '';
private string $clientId = '';
private string $clientSecret = '';
private string $authUrl = '';
Expand Down Expand Up @@ -75,6 +78,7 @@ public function __construct(
$providerUrl = $this->config->get('oidcProviderUrl');

$this->providerUrl = !empty($providerUrl) ? $this->trimTrailingSlash($providerUrl) : $providerUrl;
$this->autoDiscoverUrl = $this->config->get('oidcAutoDiscoverUrl', '');
$this->clientId = $this->config->get('oidcClientId', '');
$this->clientSecret = $this->config->get('oidcClientSecret', '');
$this->authUrl = $this->config->get('oidcAuthUrl', '');
Expand Down Expand Up @@ -153,7 +157,7 @@ public function callback(string $code, string $state): Response
if (isset($tokens['id_token'])) {
$userInfo = $this->decodeJWT($tokens['id_token']);
} elseif (isset($tokens['access_token'])) {
//falback to OAuth userinfo endpoint
//fallback to OAuth userinfo endpoint
$userInfo = $this->pollUserInfo($tokens['access_token']);
} else {
$this->displayError("oidc.error.unsupportedToken");
Expand Down Expand Up @@ -373,10 +377,9 @@ private function getPublicKey(string $kid): OpenSSLAsymmetricKey|false
return openssl_pkey_get_public(file_get_contents($this->certificateFile));
}



$httpClient = new Client();
$response = $httpClient->get($this->getJwksUrl());
// AUTH HEADER?
$response = $httpClient->get($this->getJwksUrl()); // https://cloud.lukas-sieper.de/apps/oidc/jwks
$keys = json_decode($response->getBody()->getContents(), true);
if (isset($keys['keys'])) {
$keys = $keys['keys'];
Expand All @@ -394,7 +397,12 @@ private function getPublicKey(string $kid): OpenSSLAsymmetricKey|false
$keySource = '';
if (isset($key['x5c'])) {
$keySource = '-----BEGIN CERTIFICATE-----' . PHP_EOL . chunk_split($key['x5c'][0], 64, PHP_EOL) . '-----END CERTIFICATE-----';
} elseif (isset($key['n'])) {
} elseif (isset($key['n']) && isset($key['e'])) {
// Parse the public key from n and e
$modulus = $this->base64UrlDecode($key['n']);
$exponent = $this->base64UrlDecode($key['e']);
$keySource = $this->createPublicKey($modulus, exponent: $exponent);
} else {
$this->displayError('oidc.error.unsupportedKeyFormat');
}
}
Expand All @@ -407,6 +415,29 @@ private function getPublicKey(string $kid): OpenSSLAsymmetricKey|false
return false;
}

private function base64UrlDecode(string $input): string
{
$remainder = strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}

//key to PEM
private function createPublicKey(string $modulus, string $exponent): string
{

$rsa = PublicKeyLoader::load([
'e' => new BigInteger($exponent, 256),
'n' => new BigInteger($modulus, 256),
]);

return $rsa->__toString();

}

/**
* @return string
* @throws GuzzleException
Expand Down Expand Up @@ -444,7 +475,9 @@ private function loadEndpoints(): bool

$httpClient = new Client();
try {
$response = $httpClient->get($this->providerUrl . '/.well-known/openid-configuration');
// $uri = strlen() ? $this->autoDiscoverUrl : $this->providerUrl;
$uri = empty($this->autoDiscoverUrl) ? $this->providerUrl : $this->autoDiscoverUrl;
$response = $httpClient->get($uri . '/.well-known/openid-configuration');
$endpoints = json_decode($response->getBody()->getContents(), true);
}catch(\Exception $e) {
report($e);
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"ext-pdo": "*",
"ext-zip": "*",
"ext-fileinfo": "*",

"guzzlehttp/guzzle": "^7.9.2",
"aws/aws-sdk-php": "^3.314",
"phpmailer/phpmailer": "6.6.0",
Expand Down Expand Up @@ -83,7 +82,9 @@

"ext-fileinfo": "*",
"sentry/sdk": "^3.5",
"predis/predis": "^2.2"
"predis/predis": "^2.2",
"phpseclib/phpseclib": "~3.0"

},
"require-dev": {
"squizlabs/php_codesniffer": "^3.8",
Expand Down
231 changes: 229 additions & 2 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0f4fdb0

Please sign in to comment.