Skip to content

Commit

Permalink
Add support for 'amr' (AuthnMethodRef) field available when using the…
Browse files Browse the repository at this point in the history
… Member API. This code was previously in the cilogon/service repository.
  • Loading branch information
terrencegf committed Jan 7, 2021
1 parent 520bcf4 commit 191b26b
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 13 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ if (!empty($_GET['error'])) {
echo 'Email : ' . $user->getEmail() . "\n"; // 'Primary' preferred
echo 'Primary Email : ' . $user->getPrimaryEmail() . "\n";// 'Primary' ONLY
echo 'All Emails : ' . implode(',', $user->getEmails()) . "\n";
echo 'AuthnMethodRef : ' . $user->getAmr() . "\n"; // Only for Member API
echo '</xmp>';

} catch (Exception $e) {
Expand All @@ -106,7 +107,7 @@ if (!empty($_GET['error'])) {
### Sandbox vs Production

In order to authenticate ORCID users and read associated attributes, you would typically use the Production Registry. However, for special integrations, you may want to register for a [Sandbox application](https://orcid.org/content/register-client-application-sandbox). To use the Sandbox
environment, set a 'sandbox' parameter to 'true' when creating the provider.
environment, set a 'sandbox' parameter to `true` when creating the provider.

```php
$provider = new CILogon\OAuth2\Client\Provider\ORCID([
Expand All @@ -122,7 +123,7 @@ Note that you can use this in combination with the Member API (below).

### Public API vs Member API

If you are an [ORCID member](https://orcid.org/about/membership), you can use the Member API instead of the Public API. To use the Member API, set a 'member' parameter to 'true' when creating the provider.
If you are an [ORCID member](https://orcid.org/about/membership), you can use the Member API instead of the Public API. To use the Member API, set a 'member' parameter to `true` when creating the provider. The Member API provides an additional id\_token field 'amr' (AuthnMethodRef). The value is either 'mfa' for users who have enabled two-factor authentication on their ORCID account, or 'pwd' otherwise. When using the Public API, `getAmr()` returns `null`.

```php
$provider = new CILogon\OAuth2\Client\Provider\ORCID([
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
],
"require": {
"php": ">=5.6.0",
"league/oauth2-client": "~2.0"
"league/oauth2-client": "~2.0",
"lcobucci/jwt": "^3.4"
},
"require-dev": {
"phpunit/phpunit": "~4.0",
Expand Down
19 changes: 19 additions & 0 deletions src/Provider/ORCID.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use League\OAuth2\Client\Token\AccessToken;
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
use Psr\Http\Message\ResponseInterface;
use Lcobucci\JWT\Parser;

class ORCID extends AbstractProvider
{
Expand Down Expand Up @@ -164,6 +165,24 @@ protected function checkResponse(ResponseInterface $response, $data)
*/
protected function createResourceOwner(array $response, AccessToken $token)
{
// Attempt to extract'amr' (AuthnMethodRef) from the id_token
// and add it to the response. Note that 'amr' is available only
// when using the Member API.
$values = $token->getValues();
if (array_key_exists('id_token', $values)) {
$jwt = $values['id_token'];
try {
$read = (new Parser())->parse((string) $jwt);
if ($read->hasClaim('amr')) {
$amr = $read->getClaim('amr');
if (strlen($amr) > 0) {
$response['amr'] = $amr;
}
}
} catch (Exception $e) {
}
}

return new ORCIDResourceOwner($response);
}

Expand Down
30 changes: 21 additions & 9 deletions src/Provider/ORCIDResourceOwner.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ORCIDResourceOwner implements ResourceOwnerInterface
/**
* Creates new resource owner.
*
* @param array $response
* @param array $response
*/
public function __construct(array $response = array())
{
Expand All @@ -39,7 +39,7 @@ public function __construct(array $response = array())
* Get resource owner id. This corresponds to the "full" ORCID identifier (with
* the http://orcid.org/ prefix).
*
* @return string
* @return string|null
*/
public function getId()
{
Expand All @@ -50,7 +50,7 @@ public function getId()
* Get resource owner display name. This corresponds to the
* "Published Name", * a.k.a. "credit-name".
*
* @return string
* @return string|null
*/
public function getName()
{
Expand All @@ -60,7 +60,7 @@ public function getName()
/**
* Get resource owner given (first) name.
*
* @return string
* @return string|null
*/
public function getGivenName()
{
Expand All @@ -70,7 +70,7 @@ public function getGivenName()
/**
* Get resource owner given (first) name. Alias for getGivenName().
*
* @return string
* @return string|null
*/
public function getFirstName()
{
Expand All @@ -80,7 +80,7 @@ public function getFirstName()
/**
* Get resource owner family (last) name.
*
* @return string
* @return string|null
*/
public function getFamilyName()
{
Expand All @@ -90,7 +90,7 @@ public function getFamilyName()
/**
* Get resource owner family (last) name. Alias for getFamilyName();
*
* @return string
* @return string|null
*/
public function getLastName()
{
Expand Down Expand Up @@ -120,7 +120,7 @@ public function getOtherNames()
* one marked as 'primary'. If no primary email address exists, then use
* the last one listed.
*
* @return string
* @return string|null
*/
public function getEmail()
{
Expand All @@ -142,7 +142,7 @@ public function getEmail()
* addresses for a user, loop through all of them looking for the one
* marked as 'primary'.
*
* @return string
* @return string|null
*/
public function getPrimaryEmail()
{
Expand Down Expand Up @@ -174,6 +174,18 @@ public function getEmails()
return $retval;
}

/**
* Get AMR (AuthnMethodRef) used during authentication.
* This value is available only with the Member API.
* Can be one of 'mfa', 'pwd', or null.
*
* @return string|null
*/
public function getAmr()
{
return @$this->response['amr'] ?: null;
}

/**
* Return all of the owner details available as an array.
*
Expand Down
4 changes: 3 additions & 1 deletion test/src/Provider/ORCIDTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ public function testUserData()
$email1 = uniqid();
$email2 = uniqid();
$email3 = uniqid();
$amr = 'pwd';

$postResponse = m::mock('Psr\Http\Message\ResponseInterface');
$postResponse->shouldReceive('getBody')->andReturn(
Expand Down Expand Up @@ -205,7 +206,7 @@ public function testUserData()
'"path":"/' . $id . '/keywords"},"external-identifiers":{' .
'"last-modified-date":null,"external-identifier":[],"path":"/' .
$id . '/external-identifiers"},"path":"/' . $id . '/person"},"path":"/' .
$id . '"}'
$id . '","amr":"' . $amr . '"}'
);

$userResponse->shouldReceive('getHeader')->andReturn(['content-type' => 'json']);
Expand All @@ -231,6 +232,7 @@ public function testUserData()
$this->assertEquals($email2, $user->getEmail());
$this->assertEquals($email2, $user->getPrimaryEmail());
$this->assertEquals([$email1, $email2, $email3], $user->getEmails());
$this->assertEquals($amr, $user->getAmr());
}

/**
Expand Down

0 comments on commit 191b26b

Please sign in to comment.