mirror of
https://github.com/wekan/wekan.git
synced 2026-03-01 19:30:15 +01:00
updating teams from oidc possible, fixed undefined error, no need for extra login to assign/create teams/orgs
This commit is contained in:
parent
263b405fc8
commit
f90875d8ef
5 changed files with 143 additions and 61 deletions
|
|
@ -209,7 +209,31 @@ if (Meteor.isServer) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setOrgAllFieldsFromOidc(
|
||||||
|
org,
|
||||||
|
orgDisplayName,
|
||||||
|
orgDesc,
|
||||||
|
orgShortName,
|
||||||
|
orgWebsite,
|
||||||
|
orgIsActive,
|
||||||
|
) {
|
||||||
|
check(org, Object);
|
||||||
|
check(orgDisplayName, String);
|
||||||
|
check(orgDesc, String);
|
||||||
|
check(orgShortName, String);
|
||||||
|
check(orgWebsite, String);
|
||||||
|
check(orgIsActive, Boolean);
|
||||||
|
Org.update(org, {
|
||||||
|
$set: {
|
||||||
|
orgDisplayName: orgDisplayName,
|
||||||
|
orgDesc: orgDesc,
|
||||||
|
orgShortName: orgShortName,
|
||||||
|
orgWebsite: orgWebsite,
|
||||||
|
orgIsActive: orgIsActive,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Meteor.call('setUsersOrgsOrgDisplayName', org._id, orgDisplayName);
|
||||||
|
},
|
||||||
setOrgAllFields(
|
setOrgAllFields(
|
||||||
org,
|
org,
|
||||||
orgDisplayName,
|
orgDisplayName,
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,31 @@ if (Meteor.isServer) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setTeamAllFieldsFromOidc(
|
||||||
|
team,
|
||||||
|
teamDisplayName,
|
||||||
|
teamDesc,
|
||||||
|
teamShortName,
|
||||||
|
teamWebsite,
|
||||||
|
teamIsActive,
|
||||||
|
) {
|
||||||
|
check(team, Object);
|
||||||
|
check(teamDisplayName, String);
|
||||||
|
check(teamDesc, String);
|
||||||
|
check(teamShortName, String);
|
||||||
|
check(teamWebsite, String);
|
||||||
|
check(teamIsActive, Boolean);
|
||||||
|
Team.update(team, {
|
||||||
|
$set: {
|
||||||
|
teamDisplayName: teamDisplayName,
|
||||||
|
teamDesc: teamDesc,
|
||||||
|
teamShortName: teamShortName,
|
||||||
|
teamWebsite: teamWebsite,
|
||||||
|
teamIsActive: teamIsActive,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Meteor.call('setUsersTeamsTeamDisplayName', team._id, teamDisplayName);
|
||||||
|
},
|
||||||
setTeamAllFields(
|
setTeamAllFields(
|
||||||
team,
|
team,
|
||||||
teamDisplayName,
|
teamDisplayName,
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,11 @@ class KnownUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
static onLogin(loginInfo) {
|
static onLogin(loginInfo) {
|
||||||
|
//get the data from oidc login and remove again?
|
||||||
|
if(loginInfo.type ==='oidc'){
|
||||||
|
Meteor.call('groupRoutineOnLogin', loginInfo.user.services.oidc, loginInfo.user._id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (loginInfo.type !== 'password') {
|
if (loginInfo.type !== 'password') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,18 @@ function createObject(initArr, objString)
|
||||||
initArr[4]//xxxisActive
|
initArr[4]//xxxisActive
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
function updateObject(initArr, objString)
|
||||||
|
{
|
||||||
|
functionName = objString === "Org" ? 'setOrgAllFieldsFromOidc' : 'setTeamAllFieldsFromOidc';
|
||||||
|
return Meteor.call(functionName,
|
||||||
|
initArr[0],//team || org Object
|
||||||
|
initArr[1],//displayName
|
||||||
|
initArr[2],//desc
|
||||||
|
initArr[3],//shortName
|
||||||
|
initArr[4],//website
|
||||||
|
initArr[5]//xxxisActive
|
||||||
|
);
|
||||||
|
}
|
||||||
//checks whether obj is in collection of userObjs
|
//checks whether obj is in collection of userObjs
|
||||||
//params
|
//params
|
||||||
//e.g. userObjs = user.teams
|
//e.g. userObjs = user.teams
|
||||||
|
|
@ -22,7 +34,7 @@ function contains(userObjs, obj, collection)
|
||||||
{
|
{
|
||||||
id = collection+'Id';
|
id = collection+'Id';
|
||||||
|
|
||||||
if(!userObjs.length)
|
if(typeof userObjs == "undefined" || !userObjs.length)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -36,30 +48,6 @@ function contains(userObjs, obj, collection)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// Soft version of adding teams to user via Oidc
|
|
||||||
// teams won't be created if nonexistent
|
|
||||||
// groups are treated as teams in the general case
|
|
||||||
addGroups: function (user, groups){
|
|
||||||
teamArray=[];
|
|
||||||
teams = user.teams;
|
|
||||||
orgArray=[];
|
|
||||||
for (group of groups){
|
|
||||||
team = Team.findOne({"teamDisplayName": group});
|
|
||||||
if(team)
|
|
||||||
{
|
|
||||||
if (contains(teams,team,"team"))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
teamArray.push({'teamId': Team.findOne({'teamDisplayName': group})._id, 'teamDisplayName': group});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
teams = {'teams': { '$each': teamArray}};
|
|
||||||
users.update({ _id: user._id }, { $push: teams});
|
|
||||||
},
|
|
||||||
|
|
||||||
// This function adds groups as organizations or teams to users and
|
// This function adds groups as organizations or teams to users and
|
||||||
// creates them if not already existing
|
// creates them if not already existing
|
||||||
|
|
@ -72,12 +60,20 @@ module.exports = {
|
||||||
addGroupsWithAttributes: function (user, groups){
|
addGroupsWithAttributes: function (user, groups){
|
||||||
teamArray=[];
|
teamArray=[];
|
||||||
orgArray=[];
|
orgArray=[];
|
||||||
|
isAdmin = [];
|
||||||
teams = user.teams;
|
teams = user.teams;
|
||||||
orgs = user.orgs;
|
orgs = user.orgs;
|
||||||
for (group of groups)
|
for (group of groups)
|
||||||
{
|
{
|
||||||
|
initAttributes = [
|
||||||
|
group.displayName,
|
||||||
|
group.desc || group.displayName,
|
||||||
|
group.shortName ||group.displayName,
|
||||||
|
group.website || group.displayName, group.isActive || false];
|
||||||
|
|
||||||
isOrg = group.isOrganisation || false;
|
isOrg = group.isOrganisation || false;
|
||||||
forceCreate = group.forceCreate|| false;
|
forceCreate = group.forceCreate|| false;
|
||||||
|
isAdmin.push(group.isAdmin || false);
|
||||||
if (isOrg)
|
if (isOrg)
|
||||||
{
|
{
|
||||||
org = Org.findOne({"orgDisplayName": group.displayName});
|
org = Org.findOne({"orgDisplayName": group.displayName});
|
||||||
|
|
@ -85,16 +81,13 @@ addGroupsWithAttributes: function (user, groups){
|
||||||
{
|
{
|
||||||
if(contains(orgs, org, "org"))
|
if(contains(orgs, org, "org"))
|
||||||
{
|
{
|
||||||
|
initAttributes.unshift(org);
|
||||||
|
updateObject(initAttributes, "Org");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(forceCreate)
|
else if(forceCreate)
|
||||||
{
|
{
|
||||||
initAttributes = [
|
|
||||||
group.displayName,
|
|
||||||
group.desc || group.displayName,
|
|
||||||
group.shortName ||group.displayName,
|
|
||||||
group.website || group.displayName, group.isActive || false]
|
|
||||||
createObject(initAttributes, "Org");
|
createObject(initAttributes, "Org");
|
||||||
org = Org.findOne({'orgDisplayName': group.displayName});
|
org = Org.findOne({'orgDisplayName': group.displayName});
|
||||||
}
|
}
|
||||||
|
|
@ -114,17 +107,13 @@ addGroupsWithAttributes: function (user, groups){
|
||||||
{
|
{
|
||||||
if(contains(teams, team, "team"))
|
if(contains(teams, team, "team"))
|
||||||
{
|
{
|
||||||
|
initAttributes.unshift(team);
|
||||||
|
updateObject(initAttributes, "Team");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(forceCreate)
|
else if(forceCreate)
|
||||||
{
|
{
|
||||||
initAttributes = [
|
|
||||||
group.displayName,
|
|
||||||
group.desc || group.displayName,
|
|
||||||
group.shortName ||group.displayName,
|
|
||||||
group.website || group.displayName,
|
|
||||||
group.isActive || false]
|
|
||||||
createObject(initAttributes, "Team");
|
createObject(initAttributes, "Team");
|
||||||
team = Team.findOne({'teamDisplayName': group.displayName});
|
team = Team.findOne({'teamDisplayName': group.displayName});
|
||||||
}
|
}
|
||||||
|
|
@ -135,16 +124,19 @@ addGroupsWithAttributes: function (user, groups){
|
||||||
teamHash = {'teamId': team._id, 'teamDisplayName': group.displayName};
|
teamHash = {'teamId': team._id, 'teamDisplayName': group.displayName};
|
||||||
teamArray.push(teamHash);
|
teamArray.push(teamHash);
|
||||||
}
|
}
|
||||||
// user is assigned to group which has set isAdmin: true in oidc data
|
|
||||||
// hence user will get admin privileges in wekan
|
|
||||||
if(group.isAdmin){
|
|
||||||
users.update({ _id: user._id }, { $set: {isAdmin: true}});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// user is assigned to team/org which has set isAdmin: true in oidc data
|
||||||
|
// hence user will get admin privileges in wekan
|
||||||
|
// E.g. Admin rights will be withdrawn if no group in oidc provider has isAdmin set to true
|
||||||
|
|
||||||
|
users.update({ _id: user._id }, { $set: {isAdmin: isAdmin.some(i => (i === true))}});
|
||||||
teams = {'teams': {'$each': teamArray}};
|
teams = {'teams': {'$each': teamArray}};
|
||||||
orgs = {'orgs': {'$each': orgArray}};
|
orgs = {'orgs': {'$each': orgArray}};
|
||||||
users.update({ _id: user._id }, { $push: teams});
|
users.update({ _id: user._id }, { $push: teams});
|
||||||
users.update({ _id: user._id }, { $push: orgs});
|
users.update({ _id: user._id }, { $push: orgs});
|
||||||
|
// remove temporary oidc data from user collection
|
||||||
|
users.update({ _id: user._id }, { $unset: {"services.oidc.groups": []}});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import {addGroups, addGroupsWithAttributes, addEmail, changeFullname, changeUsername} from './loginHandler';
|
import {addGroupsWithAttributes, addEmail, changeFullname, changeUsername} from './loginHandler';
|
||||||
|
|
||||||
Oidc = {};
|
Oidc = {};
|
||||||
httpCa = false;
|
httpCa = false;
|
||||||
|
|
@ -14,11 +14,13 @@ if (process.env.OAUTH2_CA_CERT !== undefined) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var profile = {};
|
||||||
|
var serviceData = {};
|
||||||
|
var userinfo = {};
|
||||||
|
|
||||||
OAuth.registerService('oidc', 2, null, function (query) {
|
OAuth.registerService('oidc', 2, null, function (query) {
|
||||||
|
|
||||||
var debug = process.env.DEBUG || false;
|
var debug = process.env.DEBUG || false;
|
||||||
var propagateOidcData = process.env.PROPAGATE_OIDC_DATA || false;
|
|
||||||
|
|
||||||
var token = getToken(query);
|
var token = getToken(query);
|
||||||
if (debug) console.log('XXX: register token:', token);
|
if (debug) console.log('XXX: register token:', token);
|
||||||
|
|
@ -28,7 +30,6 @@ OAuth.registerService('oidc', 2, null, function (query) {
|
||||||
|
|
||||||
var claimsInAccessToken = (process.env.OAUTH2_ADFS_ENABLED === 'true' || process.env.OAUTH2_ADFS_ENABLED === true) || false;
|
var claimsInAccessToken = (process.env.OAUTH2_ADFS_ENABLED === 'true' || process.env.OAUTH2_ADFS_ENABLED === true) || false;
|
||||||
|
|
||||||
var userinfo;
|
|
||||||
if(claimsInAccessToken)
|
if(claimsInAccessToken)
|
||||||
{
|
{
|
||||||
// hack when using custom claims in the accessToken. On premise ADFS
|
// hack when using custom claims in the accessToken. On premise ADFS
|
||||||
|
|
@ -44,13 +45,13 @@ OAuth.registerService('oidc', 2, null, function (query) {
|
||||||
if (userinfo.metadata) userinfo = userinfo.metadata // Openshift hack
|
if (userinfo.metadata) userinfo = userinfo.metadata // Openshift hack
|
||||||
if (debug) console.log('XXX: userinfo:', userinfo);
|
if (debug) console.log('XXX: userinfo:', userinfo);
|
||||||
|
|
||||||
var serviceData = {};
|
|
||||||
serviceData.id = userinfo[process.env.OAUTH2_ID_MAP]; // || userinfo["id"];
|
serviceData.id = userinfo[process.env.OAUTH2_ID_MAP]; // || userinfo["id"];
|
||||||
serviceData.username = userinfo[process.env.OAUTH2_USERNAME_MAP]; // || userinfo["uid"];
|
serviceData.username = userinfo[process.env.OAUTH2_USERNAME_MAP]; // || userinfo["uid"];
|
||||||
serviceData.fullname = userinfo[process.env.OAUTH2_FULLNAME_MAP]; // || userinfo["displayName"];
|
serviceData.fullname = userinfo[process.env.OAUTH2_FULLNAME_MAP]; // || userinfo["displayName"];
|
||||||
serviceData.accessToken = accessToken;
|
serviceData.accessToken = accessToken;
|
||||||
serviceData.expiresAt = expiresAt;
|
serviceData.expiresAt = expiresAt;
|
||||||
|
|
||||||
|
|
||||||
// If on Oracle OIM email is empty or null, get info from username
|
// If on Oracle OIM email is empty or null, get info from username
|
||||||
if (process.env.ORACLE_OIM_ENABLED === 'true' || process.env.ORACLE_OIM_ENABLED === true) {
|
if (process.env.ORACLE_OIM_ENABLED === 'true' || process.env.ORACLE_OIM_ENABLED === true) {
|
||||||
if (userinfo[process.env.OAUTH2_EMAIL_MAP]) {
|
if (userinfo[process.env.OAUTH2_EMAIL_MAP]) {
|
||||||
|
|
@ -74,24 +75,37 @@ OAuth.registerService('oidc', 2, null, function (query) {
|
||||||
serviceData.refreshToken = token.refresh_token;
|
serviceData.refreshToken = token.refresh_token;
|
||||||
if (debug) console.log('XXX: serviceData:', serviceData);
|
if (debug) console.log('XXX: serviceData:', serviceData);
|
||||||
|
|
||||||
var profile = {};
|
|
||||||
profile.name = userinfo[process.env.OAUTH2_FULLNAME_MAP]; // || userinfo["displayName"];
|
profile.name = userinfo[process.env.OAUTH2_FULLNAME_MAP]; // || userinfo["displayName"];
|
||||||
profile.email = userinfo[process.env.OAUTH2_EMAIL_MAP]; // || userinfo["email"];
|
profile.email = userinfo[process.env.OAUTH2_EMAIL_MAP]; // || userinfo["email"];
|
||||||
if (propagateOidcData)
|
|
||||||
{
|
|
||||||
|
|
||||||
users= Meteor.users;
|
|
||||||
user = users.findOne({'services.oidc.id': serviceData.id});
|
|
||||||
if(user)
|
|
||||||
{
|
|
||||||
(!userinfo?.["wekanGroups"]?.length) ? addGroups(user, userinfo["groups"]): addGroupsWithAttributes(user, userinfo["wekanGroups"]);
|
|
||||||
if(profile.email) addEmail(user, profile.email);
|
|
||||||
if(profile.name) changeFullname(user, profile.name);
|
|
||||||
if(profile.username) changeUsername(user, profile.username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug) console.log('XXX: profile:', profile);
|
if (debug) console.log('XXX: profile:', profile);
|
||||||
|
|
||||||
|
|
||||||
|
//temporarily store data from oidc in user.services.oidc.groups to update groups
|
||||||
|
serviceData.groups = (userinfo["groups"] && userinfo["wekanGroups"]) ? userinfo["wekanGroups"] : userinfo["groups"];
|
||||||
|
|
||||||
|
// groups arriving as array of strings indicate there is no scope set in oidc privider
|
||||||
|
// to assign teams and keep admin privileges
|
||||||
|
// data needs to be treated differently.
|
||||||
|
// use case: in oidc provider no scope is set, hence no group attributes.
|
||||||
|
// therefore: keep admin privileges for wekan as before
|
||||||
|
if(typeof serviceData.groups[0] === "string" )
|
||||||
|
{
|
||||||
|
user = Meteor.users.findOne({'_id': serviceData.id});
|
||||||
|
|
||||||
|
serviceData.groups.forEach(function(groupName, i)
|
||||||
|
{
|
||||||
|
if(user?.isAdmin && i == 0)
|
||||||
|
{
|
||||||
|
// keep information of user.isAdmin since in loginHandler the user will // be updated regarding group admin privileges provided via oidc
|
||||||
|
serviceData.groups[i] = {"isAdmin": true};
|
||||||
|
serviceData.groups[i]["displayName"]= groupName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serviceData.groups[i] = {"displayName": groupName};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
serviceData: serviceData,
|
serviceData: serviceData,
|
||||||
options: { profile: profile }
|
options: { profile: profile }
|
||||||
|
|
@ -208,6 +222,7 @@ if (process.env.ORACLE_OIM_ENABLED === 'true' || process.env.ORACLE_OIM_ENABLED
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var getUserInfo = function (accessToken) {
|
var getUserInfo = function (accessToken) {
|
||||||
var debug = process.env.DEBUG || false;
|
var debug = process.env.DEBUG || false;
|
||||||
var config = getConfiguration();
|
var config = getConfiguration();
|
||||||
|
|
@ -263,6 +278,28 @@ var getTokenContent = function (token) {
|
||||||
}
|
}
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
Meteor.methods({
|
||||||
|
'groupRoutineOnLogin': function(info, userId)
|
||||||
|
{
|
||||||
|
check(info, Object);
|
||||||
|
check(userId, String);
|
||||||
|
var propagateOidcData = process.env.PROPAGATE_OIDC_DATA || false;
|
||||||
|
if (propagateOidcData)
|
||||||
|
{
|
||||||
|
|
||||||
|
users= Meteor.users;
|
||||||
|
user = users.findOne({'_id': userId});
|
||||||
|
if(user)
|
||||||
|
{
|
||||||
|
//updates/creates Groups and user admin privileges accordingly
|
||||||
|
addGroupsWithAttributes(user, info.groups);
|
||||||
|
if(info.email) addEmail(user, info.email);
|
||||||
|
if(info.fullname) changeFullname(user, info.fullname);
|
||||||
|
if(info.username) changeUsername(user, info.username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Oidc.retrieveCredential = function (credentialToken, credentialSecret) {
|
Oidc.retrieveCredential = function (credentialToken, credentialSecret) {
|
||||||
return OAuth.retrieveCredential(credentialToken, credentialSecret);
|
return OAuth.retrieveCredential(credentialToken, credentialSecret);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue