-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
OpenID Connect: Use group details from user_info endpoint #3873
Comments
Updated the description as at first I thought there is an issue with the groups claim parsing logic. But after going through the source it seems like the issue is we do not include groups in |
I'll re-label this as an auth feature request, since we currently don't currently support gaining extra claims from the |
As this issue was a showstopper for my organisation I hacked something together which works for my needs. I know next to nothing about lavarel or php; so I dont consider this PR worthy, but maybe it can be a starting point for someone else. I overhauled the get user details function to use the access token to query both name and groups form the userinfo endpoint as defined by the provider. As I didnt get it to work with the Psr\Http\Client\ClientInterface I just resorted to curl. OidcService.php: /**
* Query the user info endpoint for the user's details.
*
* @return array{name: string, email: string, external_id: string, groups: string[]}
*/
protected function getUserInfo(OidcAccessToken $accessToken): ?array
{
$settings = $this->getProviderSettings();
$user_info_endpoint = $settings->userInfoEndpoint;
$headers = [
'Authorization: Bearer ' . $accessToken,
'Content-Type: application/json',
];
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $user_info_endpoint,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
]);
$responseBody = curl_exec($curl);
curl_close($curl);
$userinfo = json_decode($responseBody, true);
return $userinfo ?? null;
}
/**
* Get the user's name using the access token.
*
* @return string
*/
protected function getUserName(OidcAccessToken $token): string
{
$nameAttr = $this->config()['display_name_claims'] ?? 'name';
// Get the user info from the endpoint
$userInfo = $this->getUserInfo($token);
if (is_array($nameAttr)) {
$name = '';
foreach ($nameAttr as $attr) {
if (isset($userInfo[$attr])) {
$name = $userInfo[$attr];
break;
}
}
} else {
$name = $userInfo[$nameAttr] ?? 'Anonymous';
}
return $name;
}
/**
* Get the user's groups using the access token.
*
* @return string[]
*/
protected function getUserGroups(OidcAccessToken $token): array
{
$groupsAttr = $this->config()['groups_claim'];
if (empty($groupsAttr)) {
return [];
}
// $groupsList = Arr::get($token->getAllClaims(), $groupsAttr);
// Instead we use the user info endpoint
$userInfo = $this->getUserInfo($token);
$groupsList = $userInfo[$groupsAttr];
if (!is_array($groupsList)) {
return [];
}
return array_values(array_filter($groupsList, function ($val) {
return is_string($val);
}));
}
/**
* Extract the details of a user from an ID token.
*
* @return array{name: string, email: string, external_id: string, groups: string[]}
*/
protected function getUserDetails(OidcIdToken $token, OidcAccessToken $accessToken): array
{
$idClaim = 'sub';
$id = $token->getClaim($idClaim);
return [
'external_id' => $id,
'email' => $token->getClaim('email'),
'name' => $this->getUserName($accessToken),
'groups' => $this->getUserGroups($accessToken),
];
} I also adjusted AppServiceProvider.php to include the userinfo endpoint: See gist. |
@ssddanbrown |
@107142 I would be willing to review a PR for this, ideally with the following in mind:
I'm happy to provide pointers/direction/general-help where needed. |
Just a note on this, v23.05 added a new logical theme event which I believe could be used to call the Details in #4200. |
With work done in #4726 and #4955 BookStack will now use the userinfo endpoint, where expected details are missing from the IDToken. This will be part of the next feature release and I'll therefore close off this request. Note: If the auth system still provides data for expected claims in the ID token then BookStack will just use ID Token data unless any expected claims are missing. If you need userinfo endpoint claims, but can't alter the ID token to stop that behaviour, it is possible to nullify ID token claims before the userinfo look using the logical theme event I shared above. Happy to provide an example of how that would look upon request. |
Describe the Bug
It seems the application only parses the
id_token
when enumerating group claims but not theuserinfo
endpoint resulting in missing groups whenuser_info
is in use.We have a large amount of custom claims containing lots of groups making usage of
id_token
impossible (as its size would be simply too much).Steps to Reproduce
user_info
to send claims with groupsExpected Behaviour
A list of groups should be returned.
Browser Details
Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Exact BookStack Version
v22.10.2
PHP Version
8.1.12
Hosting Environment
Rancher Kubernetes
Docker image: solidnerd/bookstack:latest
Clean install
The text was updated successfully, but these errors were encountered: