oath grpup fixes
This commit is contained in:
+41
-7
@@ -8,6 +8,7 @@ const conf = require('@simpleworkjs/conf');
|
||||
const { OAuthClient } = require('../models/oauth_client');
|
||||
const { OAuthCode, OAuthAccessToken, OAuthRefreshToken } = require('../models/oauth_code');
|
||||
const { User } = require('../models/user');
|
||||
const { Group } = require('../models/group_ldap');
|
||||
|
||||
const oauthConf = conf.oauth || {};
|
||||
const issuer = oauthConf.issuer || `http://localhost:${conf.port || 3000}`;
|
||||
@@ -56,7 +57,16 @@ function parseClientAuth(req) {
|
||||
};
|
||||
}
|
||||
|
||||
function buildIdToken(user, client, scope, now) {
|
||||
// The LDAP group CNs a user belongs to (empty on any lookup failure).
|
||||
async function userGroups(user) {
|
||||
try {
|
||||
return await Group.list(user.dn);
|
||||
} catch(_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function buildIdToken(user, client, scope, now) {
|
||||
const scopes = scope.split(' ');
|
||||
const claims = {
|
||||
iss: issuer,
|
||||
@@ -75,11 +85,14 @@ function buildIdToken(user, client, scope, now) {
|
||||
if (scopes.includes('email')) {
|
||||
claims.email = user.mail;
|
||||
}
|
||||
if (scopes.includes('groups')) {
|
||||
claims.groups = await userGroups(user);
|
||||
}
|
||||
|
||||
return jwt.sign(claims, jwtSecret, { algorithm: 'HS256' });
|
||||
}
|
||||
|
||||
function userClaims(user, scope) {
|
||||
async function userClaims(user, scope) {
|
||||
const scopes = scope.split(' ');
|
||||
const claims = { sub: user.uid };
|
||||
|
||||
@@ -92,6 +105,9 @@ function userClaims(user, scope) {
|
||||
if (scopes.includes('email')) {
|
||||
claims.email = user.mail;
|
||||
}
|
||||
if (scopes.includes('groups')) {
|
||||
claims.groups = await userGroups(user);
|
||||
}
|
||||
|
||||
return claims;
|
||||
}
|
||||
@@ -216,7 +232,7 @@ router.post('/token', express.urlencoded({ extended: false }), async function(re
|
||||
};
|
||||
|
||||
if (authCode.scope.split(' ').includes('openid')) {
|
||||
response.id_token = buildIdToken(user, client, authCode.scope, now);
|
||||
response.id_token = await buildIdToken(user, client, authCode.scope, now);
|
||||
}
|
||||
|
||||
return res.json(response);
|
||||
@@ -256,7 +272,7 @@ router.post('/token', express.urlencoded({ extended: false }), async function(re
|
||||
};
|
||||
|
||||
if (oldRefreshToken.scope.split(' ').includes('openid')) {
|
||||
response.id_token = buildIdToken(user, client, oldRefreshToken.scope, now);
|
||||
response.id_token = await buildIdToken(user, client, oldRefreshToken.scope, now);
|
||||
}
|
||||
|
||||
return res.json(response);
|
||||
@@ -294,7 +310,7 @@ router.get('/userinfo', async function(req, res, next) {
|
||||
}
|
||||
|
||||
const user = await User.get(accessToken.username);
|
||||
return res.json(userClaims(user, accessToken.scope));
|
||||
return res.json(await userClaims(user, accessToken.scope));
|
||||
} catch(error) {
|
||||
next(error);
|
||||
}
|
||||
@@ -365,11 +381,28 @@ authRouter.post('/authorize', async function(req, res, next) {
|
||||
return next(makeError('InvalidRedirectURI', 'redirect_uri is not registered for this client.', 400));
|
||||
}
|
||||
|
||||
// Group-based access control: if the client restricts to specific groups,
|
||||
// only members of at least one of them may obtain an authorization code.
|
||||
if (client.allowed_groups && client.allowed_groups.length) {
|
||||
const groups = await userGroups(req.user);
|
||||
if (!client.allowed_groups.some(g => groups.includes(g))) {
|
||||
return next(makeError('AccessDenied', 'You are not a member of a group permitted to use this application.', 403));
|
||||
}
|
||||
}
|
||||
|
||||
// Only grant scopes the client is actually registered for (a direct API
|
||||
// caller could otherwise request scopes the consent screen filtered out).
|
||||
const grantedScope = (scope || 'openid')
|
||||
.split(' ')
|
||||
.filter(Boolean)
|
||||
.filter(s => client.scopes.includes(s))
|
||||
.join(' ') || 'openid';
|
||||
|
||||
const authCode = await OAuthCode.add({
|
||||
username: req.user.uid,
|
||||
client_id,
|
||||
redirect_uri,
|
||||
scope: scope || 'openid',
|
||||
scope: grantedScope,
|
||||
code_challenge: code_challenge || '',
|
||||
code_challenge_method: code_challenge_method || 'S256',
|
||||
});
|
||||
@@ -394,7 +427,8 @@ function discovery(req, res) {
|
||||
token_endpoint: `${base}/oauth/token`,
|
||||
userinfo_endpoint: `${base}/oauth/userinfo`,
|
||||
end_session_endpoint: `${base}/oauth/logout`,
|
||||
scopes_supported: ['openid', 'profile', 'email'],
|
||||
scopes_supported: ['openid', 'profile', 'email', 'groups'],
|
||||
claims_supported: ['sub', 'preferred_username', 'name', 'given_name', 'family_name', 'email', 'groups'],
|
||||
response_types_supported: ['code'],
|
||||
grant_types_supported: ['authorization_code', 'refresh_token'],
|
||||
code_challenge_methods_supported: ['S256'],
|
||||
|
||||
@@ -29,6 +29,10 @@ router.post('/', async function(req, res, next) {
|
||||
if (typeof req.body.scopes === 'string') {
|
||||
req.body.scopes = req.body.scopes.split(' ').map(s => s.trim()).filter(Boolean);
|
||||
}
|
||||
// Parse allowed_groups if sent as newline-separated string
|
||||
if (typeof req.body.allowed_groups === 'string') {
|
||||
req.body.allowed_groups = req.body.allowed_groups.split('\n').map(s => s.trim()).filter(Boolean);
|
||||
}
|
||||
// jQuery serializeObject sends nested fields as "token_lifetime[access_token]"
|
||||
if (req.body['token_lifetime[access_token]'] || req.body['token_lifetime[refresh_token]']) {
|
||||
req.body.token_lifetime = {
|
||||
@@ -72,6 +76,9 @@ router.put('/:client_id', async function(req, res, next) {
|
||||
if (typeof req.body.scopes === 'string') {
|
||||
req.body.scopes = req.body.scopes.split(' ').map(s => s.trim()).filter(Boolean);
|
||||
}
|
||||
if (typeof req.body.allowed_groups === 'string') {
|
||||
req.body.allowed_groups = req.body.allowed_groups.split('\n').map(s => s.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
return res.json({
|
||||
results: await client.update(req.body),
|
||||
|
||||
Reference in New Issue
Block a user