OAuth: Allow nested info attributes
This commit is contained in:
parent
8256b9d6bd
commit
26ab0619f5
|
@ -101,6 +101,9 @@ return [
|
||||||
'last_name' => 'last-name',
|
'last_name' => 'last-name',
|
||||||
// User URL to provider, linked on provider settings page (optional)
|
// User URL to provider, linked on provider settings page (optional)
|
||||||
'url' => '[provider page]',
|
'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)
|
// Only show after clicking the page title (optional)
|
||||||
'hidden' => false,
|
'hidden' => false,
|
||||||
// Mark user as arrived when using this provider (optional)
|
// Mark user as arrived when using this provider (optional)
|
||||||
|
|
|
@ -11,6 +11,7 @@ use Engelsystem\Http\Request;
|
||||||
use Engelsystem\Http\Response;
|
use Engelsystem\Http\Response;
|
||||||
use Engelsystem\Http\UrlGenerator;
|
use Engelsystem\Http\UrlGenerator;
|
||||||
use Engelsystem\Models\OAuth;
|
use Engelsystem\Models\OAuth;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use League\OAuth2\Client\Provider\AbstractProvider;
|
use League\OAuth2\Client\Provider\AbstractProvider;
|
||||||
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
|
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
|
||||||
|
@ -124,7 +125,7 @@ class OAuthController extends BaseController
|
||||||
} catch (IdentityProviderException $e) {
|
} catch (IdentityProviderException $e) {
|
||||||
$this->handleOAuthError($e, $providerName);
|
$this->handleOAuthError($e, $providerName);
|
||||||
}
|
}
|
||||||
$resourceId = $resourceOwner->getId();
|
$resourceId = $this->getId($providerName, $resourceOwner);
|
||||||
|
|
||||||
/** @var OAuth|null $oauth */
|
/** @var OAuth|null $oauth */
|
||||||
$oauth = $this->oauth
|
$oauth = $this->oauth
|
||||||
|
@ -156,7 +157,7 @@ class OAuthController extends BaseController
|
||||||
if (!$oauth && $user && $connectProvider && $connectProvider == $providerName) {
|
if (!$oauth && $user && $connectProvider && $connectProvider == $providerName) {
|
||||||
$oauth = new OAuth([
|
$oauth = new OAuth([
|
||||||
'provider' => $providerName,
|
'provider' => $providerName,
|
||||||
'identifier' => $resourceOwner->getId(),
|
'identifier' => $resourceId,
|
||||||
'access_token' => $accessToken->getToken(),
|
'access_token' => $accessToken->getToken(),
|
||||||
'refresh_token' => $accessToken->getRefreshToken(),
|
'refresh_token' => $accessToken->getRefreshToken(),
|
||||||
'expires_at' => $expirationTime,
|
'expires_at' => $expirationTime,
|
||||||
|
@ -167,17 +168,22 @@ class OAuthController extends BaseController
|
||||||
|
|
||||||
$this->log->info(
|
$this->log->info(
|
||||||
'Connected OAuth user {user} using {provider}',
|
'Connected OAuth user {user} using {provider}',
|
||||||
['provider' => $providerName, 'user' => $resourceOwner->getId()]
|
['provider' => $providerName, 'user' => $resourceId]
|
||||||
);
|
);
|
||||||
$this->addNotification('oauth.connected');
|
$this->addNotification('oauth.connected');
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = $this->config->get('oauth')[$providerName];
|
$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) {
|
if (!$oauth) {
|
||||||
return $this->redirectRegister(
|
return $this->redirectRegister(
|
||||||
$providerName,
|
$providerName,
|
||||||
$resourceOwner->getId(),
|
$resourceId,
|
||||||
$accessToken,
|
$accessToken,
|
||||||
$config,
|
$config,
|
||||||
$userdata
|
$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
|
* @param string $provider
|
||||||
*/
|
*/
|
||||||
|
@ -299,7 +321,7 @@ class OAuthController extends BaseController
|
||||||
'Set user {name} ({id}) as arrived via {provider} user {user}',
|
'Set user {name} ({id}) as arrived via {provider} user {user}',
|
||||||
[
|
[
|
||||||
'provider' => $providerName,
|
'provider' => $providerName,
|
||||||
'user' => $resourceOwner->getId(),
|
'user' => $this->getId($providerName, $resourceOwner),
|
||||||
'name' => $user->name,
|
'name' => $user->name,
|
||||||
'id' => $user->id
|
'id' => $user->id
|
||||||
]
|
]
|
||||||
|
|
|
@ -83,6 +83,7 @@ class OAuthControllerTest extends TestCase
|
||||||
* @covers \Engelsystem\Controllers\OAuthController::__construct
|
* @covers \Engelsystem\Controllers\OAuthController::__construct
|
||||||
* @covers \Engelsystem\Controllers\OAuthController::index
|
* @covers \Engelsystem\Controllers\OAuthController::index
|
||||||
* @covers \Engelsystem\Controllers\OAuthController::handleArrive
|
* @covers \Engelsystem\Controllers\OAuthController::handleArrive
|
||||||
|
* @covers \Engelsystem\Controllers\OAuthController::getId
|
||||||
*/
|
*/
|
||||||
public function testIndexArrive()
|
public function testIndexArrive()
|
||||||
{
|
{
|
||||||
|
@ -102,11 +103,9 @@ class OAuthControllerTest extends TestCase
|
||||||
/** @var ResourceOwnerInterface|MockObject $resourceOwner */
|
/** @var ResourceOwnerInterface|MockObject $resourceOwner */
|
||||||
$resourceOwner = $this->createMock(ResourceOwnerInterface::class);
|
$resourceOwner = $this->createMock(ResourceOwnerInterface::class);
|
||||||
$this->setExpects($resourceOwner, 'toArray', null, [], $this->atLeastOnce());
|
$this->setExpects($resourceOwner, 'toArray', null, [], $this->atLeastOnce());
|
||||||
$resourceOwner->expects($this->exactly(7))
|
$resourceOwner->expects($this->exactly(5))
|
||||||
->method('getId')
|
->method('getId')
|
||||||
->willReturnOnConsecutiveCalls(
|
->willReturnOnConsecutiveCalls(
|
||||||
'other-provider-user-identifier',
|
|
||||||
'other-provider-user-identifier',
|
|
||||||
'other-provider-user-identifier',
|
'other-provider-user-identifier',
|
||||||
'other-provider-user-identifier',
|
'other-provider-user-identifier',
|
||||||
'provider-user-identifier',
|
'provider-user-identifier',
|
||||||
|
@ -444,6 +443,84 @@ class OAuthControllerTest extends TestCase
|
||||||
$controller->index($request);
|
$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
|
* @covers \Engelsystem\Controllers\OAuthController::connect
|
||||||
|
|
Loading…
Reference in New Issue