Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for mTLS #420

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 123 additions & 14 deletions src/OpenIDConnectClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,41 @@ class OpenIDConnectClient
*/
private $token_endpoint_auth_methods_supported = ['client_secret_basic'];

/**
* @var bool used to enable mTLS for endpoint calls
*/
private $mtlsEnabled;

/**
* @var ?string if mTLS enabled, path to ssl cert
*/
private $mtlsCertPath;

/**
* @var ?string if needed, password for mTLS cert
*/
private $mtlsCertPassword;

/**
* @var ?string ssl cert type, default is "PEM", other options are "DER", "ENG" and "P12".
*/
private $mtlsCertType;

/**
* @var ?string ssl key path for mTLS
*/
private $mtlsKeyPath;

/**
* @var ?string password for ssl key
*/
private $mtlsKeyPassword;

/**
* @var ?string key type, default is "PEM", other options are "DER", "ENG".
*/
private $mtlsKeyType;

/**
* @param string|null $provider_url optional
* @param string|null $client_id optional
Expand Down Expand Up @@ -434,7 +469,7 @@ public function authenticate(): bool
* @throws OpenIDConnectClientException
*/
public function signOut(string $idToken, $redirect) {
$sign_out_endpoint = $this->getProviderConfigValue('end_session_endpoint');
$sign_out_endpoint = $this->getEndpoint('end_session_endpoint');

if($redirect === null){
$signout_params = ['id_token_hint' => $idToken];
Expand Down Expand Up @@ -739,7 +774,7 @@ protected function generateRandString(): string
*/
private function requestAuthorization() {

$auth_endpoint = $this->getProviderConfigValue('authorization_endpoint');
$auth_endpoint = $this->getEndpoint('authorization_endpoint');
$response_type = 'code';

// Generate and store a nonce in the session
Expand Down Expand Up @@ -796,7 +831,7 @@ private function requestAuthorization() {
* @throws OpenIDConnectClientException
*/
public function requestClientCredentialsToken() {
$token_endpoint = $this->getProviderConfigValue('token_endpoint');
$token_endpoint = $this->getEndpoint('token_endpoint');

$headers = [];

Expand Down Expand Up @@ -824,7 +859,7 @@ public function requestClientCredentialsToken() {
* @throws OpenIDConnectClientException
*/
public function requestResourceOwnerToken(bool $bClientAuth = false) {
$token_endpoint = $this->getProviderConfigValue('token_endpoint');
$token_endpoint = $this->getEndpoint('token_endpoint');

$headers = [];

Expand Down Expand Up @@ -864,7 +899,7 @@ public function requestResourceOwnerToken(bool $bClientAuth = false) {
* @throws OpenIDConnectClientException
*/
protected function requestTokens(string $code, array $headers = []) {
$token_endpoint = $this->getProviderConfigValue('token_endpoint');
$token_endpoint = $this->getEndpoint('token_endpoint');
$token_endpoint_auth_methods_supported = $this->getProviderConfigValue('token_endpoint_auth_methods_supported', ['client_secret_basic']);

$grant_type = 'authorization_code';
Expand Down Expand Up @@ -897,7 +932,7 @@ protected function requestTokens(string $code, array $headers = []) {
$client_assertion = $this->getProviderConfigValue('client_assertion');
}
else{
$client_assertion = $this->getJWTClientAssertion($this->getProviderConfigValue('token_endpoint'));
$client_assertion = $this->getJWTClientAssertion($token_endpoint);
}

$token_params['client_assertion_type'] = $client_assertion_type;
Expand Down Expand Up @@ -942,7 +977,7 @@ protected function requestTokens(string $code, array $headers = []) {
* @throws OpenIDConnectClientException
*/
public function requestTokenExchange(string $subjectToken, string $subjectTokenType, string $audience = '') {
$token_endpoint = $this->getProviderConfigValue('token_endpoint');
$token_endpoint = $this->getEndpoint('token_endpoint');
$token_endpoint_auth_methods_supported = $this->getProviderConfigValue('token_endpoint_auth_methods_supported', ['client_secret_basic']);
$headers = [];
$grant_type = 'urn:ietf:params:oauth:grant-type:token-exchange';
Expand Down Expand Up @@ -981,7 +1016,7 @@ public function requestTokenExchange(string $subjectToken, string $subjectTokenT
* @throws OpenIDConnectClientException
*/
public function refreshToken(string $refresh_token) {
$token_endpoint = $this->getProviderConfigValue('token_endpoint');
$token_endpoint = $this->getEndpoint('token_endpoint');
$token_endpoint_auth_methods_supported = $this->getProviderConfigValue('token_endpoint_auth_methods_supported', ['client_secret_basic']);

$headers = [];
Expand All @@ -1004,7 +1039,7 @@ public function refreshToken(string $refresh_token) {

if ($this->supportsAuthMethod('client_secret_jwt', $token_endpoint_auth_methods_supported)) {
$client_assertion_type = $this->getProviderConfigValue('client_assertion_type');
$client_assertion = $this->getJWTClientAssertion($this->getProviderConfigValue('token_endpoint'));
$client_assertion = $this->getJWTClientAssertion($token_endpoint);

$token_params["grant_type"] = "urn:ietf:params:oauth:grant-type:token-exchange";
$token_params["subject_token"] = $refresh_token;
Expand Down Expand Up @@ -1259,7 +1294,7 @@ protected function decodeJWT(string $jwt, int $section = 0): stdClass {
*/
public function requestUserInfo(string $attribute = null) {

$user_info_endpoint = $this->getProviderConfigValue('userinfo_endpoint');
$user_info_endpoint = $this->getEndpoint('userinfo_endpoint');
$schema = 'openid';

$user_info_endpoint .= '?schema=' . $schema;
Expand Down Expand Up @@ -1419,6 +1454,26 @@ protected function fetchURL(string $url, string $post_body = null, array $header
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
}

// Add mTLS configuration if enabled
if ($this->mtlsEnabled) {
curl_setopt($ch, CURLOPT_SSLCERT, $this->mtlsCertPath);
if ($this->mtlsCertType) {
curl_setopt($ch, CURLOPT_SSLCERTTYPE, $this->mtlsCertType);
}
if ($this->mtlsCertPassword) {
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $this->mtlsCertPassword);
}
if ($this->mtlsKeyPath) {
curl_setopt($ch, CURLOPT_SSLKEY, $this->mtlsKeyPath);
}
if ($this->mtlsKeyType) {
curl_setopt($ch, CURLOPT_SSLKEYTYPE, $this->mtlsKeyType);
}
if ($this->mtlsKeyPassword) {
curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $this->mtlsKeyPassword);
}
}

// Should cURL return or print out the data? (true = return, false = print)
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

Expand Down Expand Up @@ -1585,7 +1640,7 @@ public function setClientID(string $clientID) {
*/
public function register() {

$registration_endpoint = $this->getProviderConfigValue('registration_endpoint');
$registration_endpoint = $this->getEndpoint('registration_endpoint');

$send_object = (object ) array_merge($this->registrationParams, [
'redirect_uris' => [$this->getRedirectURL()],
Expand Down Expand Up @@ -1629,7 +1684,7 @@ public function register() {
* @throws Exception
*/
public function introspectToken(string $token, string $token_type_hint = '', string $clientId = null, string $clientSecret = null) {
$introspection_endpoint = $this->getProviderConfigValue('introspection_endpoint');
$introspection_endpoint = $this->getEndpoint('introspection_endpoint');
$token_endpoint_auth_methods_supported = $this->getProviderConfigValue('token_endpoint_auth_methods_supported', ['client_secret_basic']);

$post_data = ['token' => $token];
Expand All @@ -1646,7 +1701,7 @@ public function introspectToken(string $token, string $token_type_hint = '', str

if ($this->supportsAuthMethod('client_secret_jwt', $token_endpoint_auth_methods_supported)) {
$client_assertion_type = $this->getProviderConfigValue('client_assertion_type');
$client_assertion = $this->getJWTClientAssertion($this->getProviderConfigValue('introspection_endpoint'));
$client_assertion = $this->getJWTClientAssertion($introspection_endpoint);

$post_data['client_assertion_type']=$client_assertion_type;
$post_data['client_assertion'] = $client_assertion;
Expand All @@ -1670,7 +1725,7 @@ public function introspectToken(string $token, string $token_type_hint = '', str
* @throws OpenIDConnectClientException
*/
public function revokeToken(string $token, string $token_type_hint = '', string $clientId = null, string $clientSecret = null) {
$revocation_endpoint = $this->getProviderConfigValue('revocation_endpoint');
$revocation_endpoint = $this->getEndpoint('revocation_endpoint');

$post_data = ['token' => $token];

Expand Down Expand Up @@ -2022,6 +2077,42 @@ public function setCodeChallengeMethod(string $codeChallengeMethod) {
$this->codeChallengeMethod = $codeChallengeMethod;
}

public function getMtlsEnabled(): bool
{
return $this->mtlsEnabled;
}

public function setMtlsEnabled(bool $mtlsEnabled)
{
$this->mtlsEnabled = $mtlsEnabled;
}

/**
* @param ?string $certPath
* @param ?string $certType
* @param ?string $certPassword
* @return void
*/
public function setMtlsCert($certPath = null, $certType = null, $certPassword = null)
{
$this->mtlsCertPath = $certPath;
$this->mtlsCertType = $certType;
$this->mtlsCertPassword = $certPassword;
}

/**
* @param ?string $keyPath
* @param ?string $keyType
* @param ?string $keyPassword
* @return void
*/
public function setMtlsKey($keyPath = null, $keyType = null, $keyPassword = null)
{
$this->mtlsKeyPath = $keyPath;
$this->mtlsKeyType = $keyType;
$this->mtlsKeyPassword = $keyPassword;
}

/**
* @throws OpenIDConnectClientException
*/
Expand Down Expand Up @@ -2064,4 +2155,22 @@ protected function getUserAgent(): string
{
return "jumbojett/OpenID-Connect-PHP";
}

/**
* Get the endpoint from the provider config.
* If mTLS is enabled, it will look up the endpoint in the mTLS endpoint aliases.
*
* @throws OpenIDConnectClientException
*/
protected function getEndpoint(string $endpointName): string
{
$mtlsEndpointAliases = $this->getProviderConfigValue('mtls_endpoint_aliases');
$mtlsEndpoint = $mtlsEndpointAliases[$endpointName] ?? null;

if ($this->mtlsEnabled && !empty($mtlsEndpoint)) {
return $mtlsEndpoint;
}

return $this->getProviderConfigValue($endpointName);
}
}