Skip to content

Commit

Permalink
Merge pull request #18951 from totten/5.32-ms-imap
Browse files Browse the repository at this point in the history
dev/mail#79 - Fix MS Exchange/IMAP. Use OpenID Connect.
  • Loading branch information
seamuslee001 authored Nov 10, 2020
2 parents 136df4e + d551e4c commit 4fdca40
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 5 deletions.
54 changes: 54 additions & 0 deletions ext/oauth-client/Civi/OAuth/CiviGenericProvider.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
<?php
namespace Civi\OAuth;

use League\OAuth2\Client\Token\AccessToken;

/**
* Class CiviGenericProvider
* @package Civi\OAuth
*
* This is a variant of "GenericProvider" which tries to support some newer
* conventions out-of-the-box.
*
* - By default, do not send "approval_prompt" for auth-code requests. Providers
* may prefer "prompt" nowadays.
* - Allow one to fetch claims about the resource-owner from the `id_token`
* supported by OpenID Connect. This reduces the need for extra round-trips
* and proprietary scopes+URLs. To use this, set the the option:
*
* "urlResourceOwnerDetails": "{{use_id_token}}",
*/
class CiviGenericProvider extends \League\OAuth2\Client\Provider\GenericProvider {

protected function getAuthorizationParameters(array $options) {
Expand All @@ -13,4 +30,41 @@ protected function getAuthorizationParameters(array $options) {
return $newOptions;
}

/**
* Requests resource owner details.
*
* @param \League\OAuth2\Client\Token\AccessToken $token
* @return mixed
*/
protected function fetchResourceOwnerDetails(AccessToken $token) {
$url = $this->getResourceOwnerDetailsUrl($token);

// If there is no resource-owner URL, and if there is an id_token, use it.
if ($url === '{{use_id_token}}') {
$tokenData = $token->jsonSerialize();
if (isset($tokenData['id_token'])) {
$idToken = $this->decodeUnauthenticatedJwt($tokenData['id_token']);

// As long as id_token comes from a secure source, we can skip signature check.
// Which is fortunate... because we don't what key to check against...
if (!preg_match(';^https:;', $this->getBaseAccessTokenUrl([]))) {
throw new \RuntimeException("Cannot decode ID token from insecure source.");
}

return $idToken['payload'];
}
}

return parent::fetchResourceOwnerDetails($token);
}

private function decodeUnauthenticatedJwt($t) {
list ($header, $payload) = explode('.', $t);

return [
'header' => json_decode(base64_decode($header), 1),
'payload' => json_decode(base64_decode($payload), 1),
];
}

}
11 changes: 6 additions & 5 deletions ext/oauth-client/providers/ms-exchange.dist.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,25 @@
"options": {
"urlAuthorize": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
"urlAccessToken": "https://login.microsoftonline.com/common/oauth2/v2.0/token",
"urlResourceOwnerDetails": "https://graph.microsoft.com/v1.0/me",
"urlResourceOwnerDetails": "{{use_id_token}}",
"scopeSeparator": " ",
"scopes": [
"User.Read",
"https://outlook.office.com/IMAP.AccessAsUser.All",
"https://outlook.office.com/POP.AccessAsUser.All",
"https://outlook.office.com/SMTP.Send",
"openid",
"email",
"offline_access"
]
},
"mailSettingsTemplate": {
"name": "{{token.resource_owner.mail}}",
"domain": "{{token.resource_owner.mail|getMailDomain}}",
"name": "{{token.resource_owner.email}}",
"domain": "{{token.resource_owner.email|getMailDomain}}",
"localpart": null,
"return_path": null,
"protocol:name": "IMAP",
"server": "outlook.office365.com",
"username": "{{token.resource_owner.mail}}",
"username": "{{token.resource_owner.email}}",
"password": null,
"is_ssl": true
}
Expand Down

0 comments on commit 4fdca40

Please sign in to comment.