You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

209 lines
6.0 KiB

<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
namespace Tiki\Lib\OpenIdConnect;
use CoderCat\JWKToPEM\JWKConverter;
use OpenIDConnectClient\AccessToken;
use OpenIDConnectClient\OpenIDConnectProvider;
class OpenIdConnectLib
{
protected $clientSecret;
protected $clientId;
protected $issuer;
protected string $redirectUri;
protected $authUrl;
protected $accessTokenUrl;
protected $detailsUrl;
protected $pbKeyFiles;
protected $verifyMethod;
protected $connectCert;
protected $isAvailable;
protected OpenIDConnectProvider $provider;
protected $createUserTiki;
public function __construct()
{
global $prefs, $base_url;
$this->clientId = $prefs['openidconnect_client_id'];
$this->clientSecret = $prefs['openidconnect_client_secret'];
$this->issuer = $prefs['openidconnect_issuer'];
$this->redirectUri = $base_url . $prefs['login_url'];
$this->authUrl = $prefs['openidconnect_auth_url'];
$this->accessTokenUrl = $prefs['openidconnect_access_token_url'];
$this->detailsUrl = $prefs['openidconnect_details_url'];
$this->clientId = $prefs['openidconnect_client_id'];
$this->verifyMethod = $prefs['openidconnect_verify_method'];
$this->connectCert = $prefs['openidconnect_cert'];
$this->createUserTiki = $prefs['openidconnect_create_user_tiki'];
$this->jwksUrl = $prefs['openidconnect_jwks_url'];
$this->pbKeyFiles = $this->getPublicKeyFiles();
if (! empty($this->pbKeyFiles) && $this->validatePreferences()) {
$this->isAvailable = true;
}
$this->provider = $this->getProviderInstance();
}
protected function getProviderInstance()
{
$signer = new RSA256Signer();
return new OpenIDConnectProvider(
[
'clientId' => $this->clientId,
'clientSecret' => $this->clientSecret,
'idTokenIssuer' => $this->issuer,
'redirectUri' => $this->redirectUri,
'urlAuthorize' => $this->authUrl,
'urlAccessToken' => $this->accessTokenUrl,
'urlResourceOwnerDetails' => $this->detailsUrl,
'publicKey' => $this->pbKeyFiles,
],
[
'signer' => $signer,
]
);
}
/**
* @return string
*/
public function generateURL(): string
{
$provider = $this->getProviderInstance();
if (isset($_SESSION['open_id_state'])) {
$_SESSION['open_id_state'] = $provider->getState();
}
return $provider->getAuthorizationUrl(
['scope' => 'openid profile email',
'state' => $_SESSION['open_id_state']]
);
}
public function isAvailable(): bool
{
return $this->isAvailable ?: false;
}
public function validatePreferences(): bool
{
global $prefs;
$prefs_keys = [
'openidconnect_name',
'openidconnect_issuer',
'openidconnect_auth_url',
'openidconnect_access_token_url',
'openidconnect_client_id',
'openidconnect_client_secret',
'openidconnect_verify_method',
];
$valid = true;
foreach ($prefs_keys as $prefsKey) {
if (! isset($prefs[$prefsKey])) {
error_log(
'[OpenId Connect error] Field ' . $prefsKey
. ' is required.'
);
$valid = false;
}
}
return $valid;
}
protected function getPublicKeyFiles()
{
if ($this->verifyMethod === 'jwks') {
$pbKeys = $this->getPublicKeyFromJWKS();
} else {
$pbKeys[] = $this->connectCert;
}
return $pbKeys;
}
protected function getPublicKeyFromJWKS()
{
try {
$cachelib = \TikiLib::lib('cache');
$cacheName = 'oidc' . md5($this->jwksUrl);
$beginOfDay = new \DateTime();
$beginOfDay->modify('today'); //Get file one time per day
$cachedValue = $cachelib->getCached(
$cacheName,
'',
$beginOfDay->getTimestamp()
);
if ($cachedValue) {
$jwkArr = unserialize($cachedValue);
} else {
$jwkArr = json_decode(file_get_contents($this->jwksUrl), true);
$cachelib->cacheItem(
$cacheName,
serialize(
$jwkArr
)
);
}
} catch (\Throwable $e) {
error_log(
sprintf(
'[OpenId Connect error] Error getting JWKS from %s: $s',
$this->jwksUrl,
$e->getMessage()
)
);
return false;
}
try {
$jwkConverter = new JWKConverter();
return $jwkConverter->multipleToPEM($jwkArr['keys']);
} catch (\Throwable $e) {
error_log(
sprintf(
'[OpenId Connect error] Error converting JWKS to PEM %s: $s',
$this->jwksUrl,
$e->getMessage()
)
);
return false;
}
}
public function getAccessToken($code): AccessToken
{
return $this->provider->getAccessToken(
'authorization_code',
[
'code' => $code,
]
);
}
/**
* @return boolean
*/
public function canCreateUserTiki(): bool
{
return $this->createUserTiki == 'y';
}
}