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

feat(oauth2): simple userinfo endpoint #43684

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0b9253b
feat(oauth2): simple userinfo endpoint
hardviper Feb 20, 2024
bbbfe42
feat(oauth2): fix check null value, added more user_info field
hardviper Feb 21, 2024
21a1825
feat(oauth2): fix lint
hardviper Feb 21, 2024
fb8b061
feat(oauth2): fix deprecated method
hardviper Feb 22, 2024
4a645fc
Update apps/oauth2/lib/Controller/OauthApiController.php
hardviper Feb 26, 2024
fecc3ef
Update apps/oauth2/lib/Controller/OauthApiController.php
hardviper Feb 26, 2024
a54d0cd
Update apps/oauth2/lib/Controller/OauthApiController.php
hardviper Feb 26, 2024
c6efbee
feat(oauth2): user not found exception
hardviper Feb 26, 2024
3407a92
feat(oauth2): replace getAvatar with a named route
hardviper Feb 26, 2024
6405b27
feat(oauth2): parted name for ru locale
hardviper Feb 26, 2024
d6e0ddf
feat(oauth2): fix avatar absolute url
hardviper Feb 26, 2024
1ee8a1a
feat(oauth2): fix early return
hardviper Feb 28, 2024
81a92b8
Merge branch 'master' into feat/oauth2/userinfo
hardviper Mar 11, 2024
03cf5d9
feat(oauth2): separation name feature config
hardviper Mar 11, 2024
1e264ac
feat(oauth2): optional separate name
hardviper Mar 11, 2024
bf42920
feat(oauth2): add unit-test for GetUserInfo
hardviper Mar 13, 2024
b6f6651
feat(oauth2): add unit-test for GetUserInfo separate mode
hardviper Mar 13, 2024
a424e96
Update apps/oauth2/lib/Controller/OauthApiController.php
hardviper Mar 13, 2024
1c1fa9e
Update apps/oauth2/lib/Controller/OauthApiController.php
hardviper Mar 13, 2024
dd9edb8
Update apps/oauth2/tests/Controller/OauthApiControllerTest.php
hardviper Mar 13, 2024
16edc40
Update apps/oauth2/tests/Controller/OauthApiControllerTest.php
hardviper Mar 13, 2024
b077248
Update config/config.sample.php
hardviper Mar 13, 2024
540eb16
feat(oauth2): fix var name
hardviper Mar 13, 2024
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
5 changes: 5 additions & 0 deletions apps/oauth2/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,10 @@
'url' => '/api/v1/token',
'verb' => 'POST'
],
[
'name' => 'OauthApi#getUserInfo',
'url' => '/api/v1/userinfo',
'verb' => 'GET'
],
],
];
47 changes: 47 additions & 0 deletions apps/oauth2/lib/Controller/OauthApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
use OCP\Authentication\Exceptions\InvalidTokenException;
use OCP\DB\Exception;
use OCP\IRequest;
use OCP\IUserSession;
use OCP\IURLGenerator;
use OCP\IConfig;
use OCP\Security\Bruteforce\IThrottler;
use OCP\Security\ICrypto;
use OCP\Security\ISecureRandom;
Expand All @@ -62,6 +65,9 @@ public function __construct(
private LoggerInterface $logger,
private IThrottler $throttler,
private ITimeFactory $timeFactory,
private IUserSession $userSession,
private IURLGenerator $urlGenerator,
private IConfig $config,
) {
parent::__construct($appName, $request);
}
Expand Down Expand Up @@ -226,4 +232,45 @@ public function getToken(
]
);
}

/**
* @PublicPage
* @NoCSRFRequired
*
* @return JSONResponse
*/
public function getUserInfo(): JSONResponse {
$user = $this->userSession->getUser();
if ($user === null) {
return new JSONResponse([
'error' => 'user_not_found',
], Http::STATUS_NOT_FOUND);
}
$displayName = $user->getDisplayName();
$userId = $user->getUID();

$userInfo = [
'sub' => $userId,
'name' => $displayName,
'email' => $user->getEMailAddress(),
'picture' => $this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->linkToRoute('core.avatar.getAvatar', [
'userId' => $userId,
'size' => 512
]))
];

$oauthConf = $this->config->getSystemValue('oauth2', ['process_name' => false]);
if ($oauthConf["process_name"] === true &&
key_exists("separator", $oauthConf) &&
key_exists("first_name_position", $oauthConf) &&
key_exists("family_name_position", $oauthConf) &&
$oauthConf["separator"] !== ""
) {
$partedName = explode($oauthConf["separator"], $displayName);
$userInfo['given_name'] = $partedName[$oauthConf["first_name_position"]];
$userInfo['family_name'] = $partedName[$oauthConf["family_name_position"]] ?? $partedName[0];
}
return new JSONResponse($userInfo);
}
}
50 changes: 50 additions & 0 deletions apps/oauth2/tests/Controller/OauthApiControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserSession;
use OCP\Security\Bruteforce\IThrottler;
use OCP\Security\ICrypto;
use OCP\Security\ISecureRandom;
Expand Down Expand Up @@ -88,6 +91,10 @@ protected function setUp(): void {
$this->throttler = $this->createMock(IThrottler::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->timeFactory = $this->createMock(ITimeFactory::class);
$this->user = $this->createMock(IUser::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->config = $this->createMock(IConfig::class);

$this->oauthApiController = new OauthApiController(
'oauth2',
Expand Down Expand Up @@ -616,4 +623,47 @@ public function testRefreshTokenExpiredAppToken() {

$this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', 'clientId', 'clientSecret'));
}

public function testGetUserInfo(): void {
$this->user->method('getDisplayName')->willReturn('Test User');
$this->user->method('getUID')->willReturn('testuser');
$this->user->method('getEMailAddress')->willReturn('testuser@example.com');

$this->userSession->method('getUser')->willReturn($this->user);
$this->urlGenerator->method('getAbsoluteURL')->willReturn('http://localhost/avatar.png');
$this->config->method('getSystemValue')->willReturn(['process_name' => false]);

$response = $this->oauthApiController->getUserInfo();

$this->assertInstanceOf(JSONResponse::class, $response);
$this->assertEquals('Test User', $response->getData()['name']);
$this->assertEquals('testuser', $response->getData()['sub']);
$this->assertEquals('testuser@example.com', $response->getData()['email']);
$this->assertEquals('http://localhost/avatar.png', $response->getData()['picture']);
}

public function testGetUserInfoWithSeparate(): void {
$this->user->method('getDisplayName')->willReturn('Test User');
$this->user->method('getUID')->willReturn('testuser');
$this->user->method('getEMailAddress')->willReturn('testuser@example.com');

$this->userSession->method('getUser')->willReturn($this->user);
$this->urlGenerator->method('getAbsoluteURL')->willReturn('http://localhost/avatar.png');

$this->config->method('getSystemValue')
->willReturn([
'process_name' => true,
'separator' => ' ',
'first_name_position' => 0,
'family_name_position' => 1
]);
$response = $this->oauthApiController->getUserInfo();

$this->assertInstanceOf(JSONResponse::class, $response);
$this->assertEquals('testuser', $response->getData()['sub']);
$this->assertEquals('testuser@example.com', $response->getData()['email']);
$this->assertEquals('http://localhost/avatar.png', $response->getData()['picture']);
$this->assertEquals('Test', $response->getData()['given_name']);
$this->assertEquals('User', $response->getData()['family_name']);
}
}
19 changes: 18 additions & 1 deletion config/config.sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -1962,7 +1962,7 @@
/**
* Blacklist characters from being used in filenames. This is useful if you
* have a filesystem or OS which does not support certain characters like windows.
*
*
* The '/' and '\' characters are always forbidden.
*
* Example for windows systems: ``array('?', '<', '>', ':', '*', '|', '"', chr(0), "\n", "\r")``
Expand Down Expand Up @@ -2420,4 +2420,21 @@
* Defaults to ``true``
*/
'enable_non-accessible_features' => true,

/**
* OAuth2 userinfo endpoint settings
*
* The 'process_name' key defines the need to separate the name into given_name and family_name. If false then given_name and family_name are not passed.
* Defaults to ``false``
* The 'separator' key is a symbol separating the first and last name.
* The key 'first_name_position' is the position of given_name in the name.
* The key 'family_name_position' is the position of family_name in the name.
*/
'oauth2' =>
[
'process_name' => false,
'separator' => ' ',
'first_name_position' => 0,
'family_name_position' => 1,
],
];
Loading