OAuth: Allow nested info attributes
This commit is contained in:
parent
8256b9d6bd
commit
26ab0619f5
|
@ -101,6 +101,9 @@ return [
|
|||
'last_name' => 'last-name',
|
||||
// User URL to provider, linked on provider settings page (optional)
|
||||
'url' => '[provider page]',
|
||||
// Whether info attributes are nested arrays (optional)
|
||||
// For example {"user":{"name":"foo"}} can be accessed using user.name
|
||||
'nested_info' => false,
|
||||
// Only show after clicking the page title (optional)
|
||||
'hidden' => false,
|
||||
// Mark user as arrived when using this provider (optional)
|
||||
|
|
|
@ -11,6 +11,7 @@ use Engelsystem\Http\Request;
|
|||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Http\UrlGenerator;
|
||||
use Engelsystem\Models\OAuth;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use League\OAuth2\Client\Provider\AbstractProvider;
|
||||
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
|
||||
|
@ -124,7 +125,7 @@ class OAuthController extends BaseController
|
|||
} catch (IdentityProviderException $e) {
|
||||
$this->handleOAuthError($e, $providerName);
|
||||
}
|
||||
$resourceId = $resourceOwner->getId();
|
||||
$resourceId = $this->getId($providerName, $resourceOwner);
|
||||
|
||||
/** @var OAuth|null $oauth */
|
||||
$oauth = $this->oauth
|
||||
|
@ -156,7 +157,7 @@ class OAuthController extends BaseController
|
|||
if (!$oauth && $user && $connectProvider && $connectProvider == $providerName) {
|
||||
$oauth = new OAuth([
|
||||
'provider' => $providerName,
|
||||
'identifier' => $resourceOwner->getId(),
|
||||
'identifier' => $resourceId,
|
||||
'access_token' => $accessToken->getToken(),
|
||||
'refresh_token' => $accessToken->getRefreshToken(),
|
||||
'expires_at' => $expirationTime,
|
||||
|
@ -167,17 +168,22 @@ class OAuthController extends BaseController
|
|||
|
||||
$this->log->info(
|
||||
'Connected OAuth user {user} using {provider}',
|
||||
['provider' => $providerName, 'user' => $resourceOwner->getId()]
|
||||
['provider' => $providerName, 'user' => $resourceId]
|
||||
);
|
||||
$this->addNotification('oauth.connected');
|
||||
}
|
||||
|
||||
$config = $this->config->get('oauth')[$providerName];
|
||||
$userdata = new Collection($resourceOwner->toArray());
|
||||
$resourceData = $resourceOwner->toArray();
|
||||
if (!empty($config['nested_info'])) {
|
||||
$resourceData = Arr::dot($resourceData);
|
||||
}
|
||||
|
||||
$userdata = new Collection($resourceData);
|
||||
if (!$oauth) {
|
||||
return $this->redirectRegister(
|
||||
$providerName,
|
||||
$resourceOwner->getId(),
|
||||
$resourceId,
|
||||
$accessToken,
|
||||
$config,
|
||||
$userdata
|
||||
|
@ -252,6 +258,22 @@ class OAuthController extends BaseController
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $providerName
|
||||
* @param ResourceOwner $resourceOwner
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getId(string $providerName, ResourceOwner $resourceOwner)
|
||||
{
|
||||
$config = $this->config->get('oauth')[$providerName];
|
||||
if (empty($config['nested_info'])) {
|
||||
return $resourceOwner->getId();
|
||||
}
|
||||
|
||||
$data = Arr::dot($resourceOwner->toArray());
|
||||
return $data[$config['id']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $provider
|
||||
*/
|
||||
|
@ -299,7 +321,7 @@ class OAuthController extends BaseController
|
|||
'Set user {name} ({id}) as arrived via {provider} user {user}',
|
||||
[
|
||||
'provider' => $providerName,
|
||||
'user' => $resourceOwner->getId(),
|
||||
'user' => $this->getId($providerName, $resourceOwner),
|
||||
'name' => $user->name,
|
||||
'id' => $user->id
|
||||
]
|
||||
|
|
|
@ -83,6 +83,7 @@ class OAuthControllerTest extends TestCase
|
|||
* @covers \Engelsystem\Controllers\OAuthController::__construct
|
||||
* @covers \Engelsystem\Controllers\OAuthController::index
|
||||
* @covers \Engelsystem\Controllers\OAuthController::handleArrive
|
||||
* @covers \Engelsystem\Controllers\OAuthController::getId
|
||||
*/
|
||||
public function testIndexArrive()
|
||||
{
|
||||
|
@ -102,11 +103,9 @@ class OAuthControllerTest extends TestCase
|
|||
/** @var ResourceOwnerInterface|MockObject $resourceOwner */
|
||||
$resourceOwner = $this->createMock(ResourceOwnerInterface::class);
|
||||
$this->setExpects($resourceOwner, 'toArray', null, [], $this->atLeastOnce());
|
||||
$resourceOwner->expects($this->exactly(7))
|
||||
$resourceOwner->expects($this->exactly(5))
|
||||
->method('getId')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
'other-provider-user-identifier',
|
||||
'other-provider-user-identifier',
|
||||
'other-provider-user-identifier',
|
||||
'other-provider-user-identifier',
|
||||
'provider-user-identifier',
|
||||
|
@ -444,6 +443,84 @@ class OAuthControllerTest extends TestCase
|
|||
$controller->index($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\OAuthController::index
|
||||
* @covers \Engelsystem\Controllers\OAuthController::getId
|
||||
* @covers \Engelsystem\Controllers\OAuthController::redirectRegister
|
||||
*/
|
||||
public function testIndexRedirectRegisterNestedInfo()
|
||||
{
|
||||
$accessToken = $this->createMock(AccessToken::class);
|
||||
$this->setExpects($accessToken, 'getToken', null, 'test-token', $this->atLeastOnce());
|
||||
$this->setExpects($accessToken, 'getRefreshToken', null, 'test-refresh-token', $this->atLeastOnce());
|
||||
$this->setExpects($accessToken, 'getExpires', null, 4242424242, $this->atLeastOnce());
|
||||
|
||||
$config = $this->config->get('oauth');
|
||||
$config['testprovider'] = array_merge($config['testprovider'], [
|
||||
'nested_info' => true,
|
||||
'id' => 'nested.id',
|
||||
'email' => 'nested.email',
|
||||
'username' => 'nested.name',
|
||||
'first_name' => 'nested.first',
|
||||
'last_name' => 'nested.last',
|
||||
]);
|
||||
$this->config->set('oauth', $config);
|
||||
|
||||
$this->config->set('registration_enabled', true);
|
||||
|
||||
/** @var ResourceOwnerInterface|MockObject $resourceOwner */
|
||||
$resourceOwner = $this->createMock(ResourceOwnerInterface::class);
|
||||
$this->setExpects($resourceOwner, 'getId', null, null, $this->never());
|
||||
$this->setExpects(
|
||||
$resourceOwner,
|
||||
'toArray',
|
||||
null,
|
||||
[
|
||||
'nested' => [
|
||||
'id' => 'new-provider-user-identifier',
|
||||
'name' => 'testuser',
|
||||
'email' => 'foo.bar@localhost',
|
||||
'first' => 'Test',
|
||||
'last' => 'Tester',
|
||||
],
|
||||
],
|
||||
$this->atLeastOnce()
|
||||
);
|
||||
|
||||
/** @var GenericProvider|MockObject $provider */
|
||||
$provider = $this->createMock(GenericProvider::class);
|
||||
$this->setExpects(
|
||||
$provider,
|
||||
'getAccessToken',
|
||||
['authorization_code', ['code' => 'lorem-ipsum-code']],
|
||||
$accessToken,
|
||||
$this->atLeastOnce()
|
||||
);
|
||||
$this->setExpects($provider, 'getResourceOwner', [$accessToken], $resourceOwner, $this->atLeastOnce());
|
||||
|
||||
$this->session->set('oauth2_state', 'some-internal-state');
|
||||
|
||||
$this->setExpects($this->auth, 'user', null, null, $this->atLeastOnce());
|
||||
|
||||
$this->setExpects($this->redirect, 'to', ['/register']);
|
||||
|
||||
$request = new Request();
|
||||
$request = $request
|
||||
->withAttribute('provider', 'testprovider')
|
||||
->withQueryParams(['code' => 'lorem-ipsum-code', 'state' => 'some-internal-state']);
|
||||
|
||||
$controller = $this->getMock(['getProvider']);
|
||||
$this->setExpects($controller, 'getProvider', ['testprovider'], $provider, $this->atLeastOnce());
|
||||
|
||||
$controller->index($request);
|
||||
$this->assertEquals([
|
||||
'email' => 'foo.bar@localhost',
|
||||
'name' => 'testuser',
|
||||
'first_name' => 'Test',
|
||||
'last_name' => 'Tester',
|
||||
], $this->session->get('form_data'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\OAuthController::connect
|
||||
|
|
Loading…
Reference in New Issue