Просмотр исходного кода

updating teams from oidc possible, fixed undefined error, no need for extra login to assign/create teams/orgs

viehlieb 3 лет назад
Родитель
Сommit
f90875d8ef

+ 25 - 1
models/org.js

@@ -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(
       org,
       orgDisplayName,

+ 25 - 1
models/team.js

@@ -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(
       team,
       teamDisplayName,

+ 5 - 0
packages/wekan-accounts-lockout/src/knownUser.js

@@ -214,6 +214,11 @@ class KnownUser {
   }
 
   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') {
       return;
     }

+ 33 - 41
packages/wekan-oidc/loginHandler.js

@@ -13,6 +13,18 @@ function createObject(initArr, objString)
     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
 //params
 //e.g. userObjs = user.teams
@@ -22,7 +34,7 @@ function contains(userObjs, obj, collection)
 {
   id = collection+'Id';
 
-  if(!userObjs.length)
+  if(typeof userObjs == "undefined" || !userObjs.length)
   {
     return false;
   }
@@ -36,30 +48,6 @@ function contains(userObjs, obj, collection)
   return false;
 }
 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
 // creates them if not already existing
@@ -72,12 +60,20 @@ module.exports = {
 addGroupsWithAttributes: function (user, groups){
   teamArray=[];
   orgArray=[];
+  isAdmin = [];
   teams = user.teams;
   orgs = user.orgs;
   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;
     forceCreate = group.forceCreate|| false;
+    isAdmin.push(group.isAdmin || false);
     if (isOrg)
     {
       org = Org.findOne({"orgDisplayName": group.displayName});
@@ -85,16 +81,13 @@ addGroupsWithAttributes: function (user, groups){
       {
         if(contains(orgs, org, "org"))
         {
+          initAttributes.unshift(org);
+          updateObject(initAttributes, "Org");
           continue;
         }
       }
       else if(forceCreate)
       {
-        initAttributes = [
-          group.displayName,
-          group.desc || group.displayName,
-          group.shortName ||group.displayName,
-          group.website || group.displayName, group.isActive || false]
         createObject(initAttributes, "Org");
         org = Org.findOne({'orgDisplayName': group.displayName});
       }
@@ -114,17 +107,13 @@ addGroupsWithAttributes: function (user, groups){
       {
         if(contains(teams, team, "team"))
         {
+          initAttributes.unshift(team);
+          updateObject(initAttributes, "Team");
           continue;
         }
       }
       else if(forceCreate)
       {
-        initAttributes = [
-          group.displayName,
-          group.desc || group.displayName,
-          group.shortName ||group.displayName,
-          group.website || group.displayName,
-          group.isActive || false]
         createObject(initAttributes, "Team");
         team = Team.findOne({'teamDisplayName': group.displayName});
       }
@@ -135,16 +124,19 @@ addGroupsWithAttributes: function (user, groups){
       teamHash = {'teamId': team._id, 'teamDisplayName': group.displayName};
       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}};
   orgs = {'orgs': {'$each': orgArray}};
   users.update({ _id: user._id }, { $push:  teams});
   users.update({ _id: user._id }, { $push:  orgs});
+  // remove temporary oidc data from user collection
+  users.update({ _id: user._id }, { $unset:  {"services.oidc.groups": []}});
+
   return;
 },
 

+ 53 - 16
packages/wekan-oidc/oidc_server.js

@@ -1,4 +1,4 @@
-import {addGroups, addGroupsWithAttributes, addEmail, changeFullname, changeUsername} from './loginHandler';
+import {addGroupsWithAttributes, addEmail, changeFullname, changeUsername} from './loginHandler';
 
 Oidc = {};
 httpCa = false;
@@ -14,11 +14,13 @@ if (process.env.OAUTH2_CA_CERT !== undefined) {
 	console.log(e);
     }
 }
+var profile = {};
+var serviceData = {};
+var userinfo = {};
 
 OAuth.registerService('oidc', 2, null, function (query) {
 
   var debug = process.env.DEBUG || false;
-  var propagateOidcData = process.env.PROPAGATE_OIDC_DATA || false;
 
   var token = getToken(query);
   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 userinfo;
   if(claimsInAccessToken)
   {
     // 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 (debug) console.log('XXX: userinfo:', userinfo);
 
-  var serviceData = {};
   serviceData.id = userinfo[process.env.OAUTH2_ID_MAP]; // || userinfo["id"];
   serviceData.username = userinfo[process.env.OAUTH2_USERNAME_MAP]; // || userinfo["uid"];
   serviceData.fullname = userinfo[process.env.OAUTH2_FULLNAME_MAP]; // || userinfo["displayName"];
   serviceData.accessToken = accessToken;
   serviceData.expiresAt = expiresAt;
 
+
   // 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 (userinfo[process.env.OAUTH2_EMAIL_MAP]) {
@@ -74,24 +75,37 @@ OAuth.registerService('oidc', 2, null, function (query) {
     serviceData.refreshToken = token.refresh_token;
   if (debug) console.log('XXX: serviceData:', serviceData);
 
-  var profile = {};
   profile.name = userinfo[process.env.OAUTH2_FULLNAME_MAP]; // || userinfo["displayName"];
   profile.email = userinfo[process.env.OAUTH2_EMAIL_MAP]; // || userinfo["email"];
-  if (propagateOidcData)
+  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});
 
-    users= Meteor.users;
-    user = users.findOne({'services.oidc.id':  serviceData.id});
-    if(user)
+    serviceData.groups.forEach(function(groupName, i)
     {
-      (!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(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};
+      }
+    });
   }
-  if (debug) console.log('XXX: profile:', profile);
-
   return {
     serviceData: serviceData,
     options: { profile: profile }
@@ -208,6 +222,7 @@ if (process.env.ORACLE_OIM_ENABLED === 'true' || process.env.ORACLE_OIM_ENABLED
   };
 }
 
+
 var getUserInfo = function (accessToken) {
   var debug = process.env.DEBUG || false;
   var config = getConfiguration();
@@ -263,6 +278,28 @@ var getTokenContent = function (token) {
   }
   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) {
   return OAuth.retrieveCredential(credentialToken, credentialSecret);