|
@@ -1,260 +1,349 @@
|
|
|
-import { addGroupsWithAttributes, addEmail, changeFullname, changeUsername } from './loginHandler';
|
|
|
-const fs = Npm.require('fs'); // For file handling
|
|
|
+import {addGroupsWithAttributes, addEmail, changeFullname, changeUsername} from './loginHandler';
|
|
|
|
|
|
Oidc = {};
|
|
|
httpCa = false;
|
|
|
|
|
|
-// Load CA certificate if specified in the environment variable
|
|
|
if (process.env.OAUTH2_CA_CERT !== undefined) {
|
|
|
try {
|
|
|
+ const fs = Npm.require('fs');
|
|
|
if (fs.existsSync(process.env.OAUTH2_CA_CERT)) {
|
|
|
- httpCa = fs.readFileSync(process.env.OAUTH2_CA_CERT);
|
|
|
+ httpCa = fs.readFileSync(process.env.OAUTH2_CA_CERT);
|
|
|
}
|
|
|
- } catch (e) {
|
|
|
- console.log('WARNING: failed loading: ' + process.env.OAUTH2_CA_CERT);
|
|
|
- console.log(e);
|
|
|
+ } catch(e) {
|
|
|
+ console.log('WARNING: failed loading: ' + process.env.OAUTH2_CA_CERT);
|
|
|
+ console.log(e);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
var profile = {};
|
|
|
var serviceData = {};
|
|
|
var userinfo = {};
|
|
|
|
|
|
-// Function to read the allowed emails from a local file specified in the environment variable
|
|
|
-var getAllowedEmailsFromFile = function() {
|
|
|
- var allowedEmails = [];
|
|
|
- const filePath = process.env.OAUTH2_ALLOWEDEMAILS_FILEPATH; // Get the file path from environment variable
|
|
|
-
|
|
|
- if (!filePath) {
|
|
|
- throw new Error("OAUTH2_ALLOWEDEMAILS_FILEPATH environment variable is not set.");
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- // Read the allowed emails file
|
|
|
- const data = fs.readFileSync(filePath, 'utf-8');
|
|
|
- allowedEmails = data.split('\n').map(email => email.trim());
|
|
|
- } catch (error) {
|
|
|
- console.error("Error reading allowed emails file:", error);
|
|
|
- }
|
|
|
- return allowedEmails;
|
|
|
-};
|
|
|
-
|
|
|
-// OAuth service registration
|
|
|
OAuth.registerService('oidc', 2, null, function (query) {
|
|
|
- var debug = process.env.DEBUG === 'true';
|
|
|
-
|
|
|
- var token = getToken(query);
|
|
|
- if (debug) console.log('XXX: register token:', token);
|
|
|
-
|
|
|
- var accessToken = token.access_token || token.id_token;
|
|
|
- var expiresAt = (+new Date) + (1000 * parseInt(token.expires_in, 10));
|
|
|
-
|
|
|
- var claimsInAccessToken = (process.env.OAUTH2_ADFS_ENABLED === 'true' ||
|
|
|
- process.env.OAUTH2_ADFS_ENABLED === true ||
|
|
|
- process.env.OAUTH2_B2C_ENABLED === 'true' ||
|
|
|
- process.env.OAUTH2_B2C_ENABLED === true) || false;
|
|
|
-
|
|
|
- if (claimsInAccessToken) {
|
|
|
- userinfo = getTokenContent(accessToken);
|
|
|
+ var debug = process.env.DEBUG === 'true';
|
|
|
+
|
|
|
+ var token = getToken(query);
|
|
|
+ if (debug) console.log('XXX: register token:', token);
|
|
|
+
|
|
|
+ var accessToken = token.access_token || token.id_token;
|
|
|
+ var expiresAt = (+new Date) + (1000 * parseInt(token.expires_in, 10));
|
|
|
+
|
|
|
+ var claimsInAccessToken = (process.env.OAUTH2_ADFS_ENABLED === 'true' ||
|
|
|
+ process.env.OAUTH2_ADFS_ENABLED === true ||
|
|
|
+ process.env.OAUTH2_B2C_ENABLED === 'true' ||
|
|
|
+ process.env.OAUTH2_B2C_ENABLED === true) || false;
|
|
|
+
|
|
|
+ if(claimsInAccessToken)
|
|
|
+ {
|
|
|
+ // hack when using custom claims in the accessToken. On premise ADFS. And Azure AD B2C.
|
|
|
+ userinfo = getTokenContent(accessToken);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // normal behaviour, getting the claims from UserInfo endpoint.
|
|
|
+ userinfo = getUserInfo(accessToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (userinfo.ocs) userinfo = userinfo.ocs.data; // Nextcloud hack
|
|
|
+ if (userinfo.metadata) userinfo = userinfo.metadata // Openshift hack
|
|
|
+ if (debug) console.log('XXX: userinfo:', userinfo);
|
|
|
+
|
|
|
+ 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]) {
|
|
|
+ serviceData.email = userinfo[process.env.OAUTH2_EMAIL_MAP];
|
|
|
} else {
|
|
|
- userinfo = getUserInfo(accessToken);
|
|
|
- }
|
|
|
-
|
|
|
- if (userinfo.ocs) userinfo = userinfo.ocs.data;
|
|
|
- if (userinfo.metadata) userinfo = userinfo.metadata;
|
|
|
- if (debug) console.log('XXX: userinfo:', userinfo);
|
|
|
-
|
|
|
- serviceData.id = userinfo[process.env.OAUTH2_ID_MAP];
|
|
|
- serviceData.username = userinfo[process.env.OAUTH2_USERNAME_MAP];
|
|
|
- serviceData.fullname = userinfo[process.env.OAUTH2_FULLNAME_MAP];
|
|
|
- serviceData.accessToken = accessToken;
|
|
|
- serviceData.expiresAt = expiresAt;
|
|
|
-
|
|
|
- // Oracle OIM and B2C checks remain the same
|
|
|
- if (process.env.ORACLE_OIM_ENABLED === 'true' || process.env.ORACLE_OIM_ENABLED === true) {
|
|
|
- if (userinfo[process.env.OAUTH2_EMAIL_MAP]) {
|
|
|
- serviceData.email = userinfo[process.env.OAUTH2_EMAIL_MAP];
|
|
|
- } else {
|
|
|
- serviceData.email = userinfo[process.env.OAUTH2_USERNAME_MAP];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (process.env.ORACLE_OIM_ENABLED !== 'true' && process.env.ORACLE_OIM_ENABLED !== true) {
|
|
|
- serviceData.email = userinfo[process.env.OAUTH2_EMAIL_MAP];
|
|
|
+ serviceData.email = userinfo[process.env.OAUTH2_USERNAME_MAP];
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ if (process.env.ORACLE_OIM_ENABLED !== 'true' && process.env.ORACLE_OIM_ENABLED !== true) {
|
|
|
+ serviceData.email = userinfo[process.env.OAUTH2_EMAIL_MAP]; // || userinfo["email"];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (process.env.OAUTH2_B2C_ENABLED === 'true' || process.env.OAUTH2_B2C_ENABLED === true) {
|
|
|
+ serviceData.email = userinfo["emails"][0];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (accessToken) {
|
|
|
+ var tokenContent = getTokenContent(accessToken);
|
|
|
+ var fields = _.pick(tokenContent, getConfiguration().idTokenWhitelistFields);
|
|
|
+ _.extend(serviceData, fields);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (token.refresh_token)
|
|
|
+ serviceData.refreshToken = token.refresh_token;
|
|
|
+ if (debug) console.log('XXX: serviceData:', serviceData);
|
|
|
+
|
|
|
+ profile.name = userinfo[process.env.OAUTH2_FULLNAME_MAP]; // || userinfo["displayName"];
|
|
|
+ profile.email = userinfo[process.env.OAUTH2_EMAIL_MAP]; // || userinfo["email"];
|
|
|
+
|
|
|
+ if (process.env.OAUTH2_B2C_ENABLED === 'true' || process.env.OAUTH2_B2C_ENABLED === true) {
|
|
|
+ profile.email = userinfo["emails"][0];
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(Array.isArray(serviceData.groups) && serviceData.groups.length && 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};
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // Fix OIDC login loop for integer user ID. Thanks to danielkaiser.
|
|
|
+ // https://github.com/wekan/wekan/issues/4795
|
|
|
+ Meteor.call('groupRoutineOnLogin',serviceData, ""+serviceData.id);
|
|
|
+ Meteor.call('boardRoutineOnLogin',serviceData, ""+serviceData.id);
|
|
|
+
|
|
|
+ return {
|
|
|
+ serviceData: serviceData,
|
|
|
+ options: { profile: profile }
|
|
|
+ };
|
|
|
+});
|
|
|
|
|
|
- if (process.env.OAUTH2_B2C_ENABLED === 'true' || process.env.OAUTH2_B2C_ENABLED === true) {
|
|
|
- serviceData.email = userinfo["emails"][0];
|
|
|
- }
|
|
|
+var userAgent = "Meteor";
|
|
|
+if (Meteor.release) {
|
|
|
+ userAgent += "/" + Meteor.release;
|
|
|
+}
|
|
|
|
|
|
- if (accessToken) {
|
|
|
- var tokenContent = getTokenContent(accessToken);
|
|
|
- var fields = _.pick(tokenContent, getConfiguration().idTokenWhitelistFields);
|
|
|
- _.extend(serviceData, fields);
|
|
|
+if (process.env.ORACLE_OIM_ENABLED !== 'true' && process.env.ORACLE_OIM_ENABLED !== true) {
|
|
|
+ var getToken = function (query) {
|
|
|
+ var debug = process.env.DEBUG === 'true';
|
|
|
+ var config = getConfiguration();
|
|
|
+ if(config.tokenEndpoint.includes('https://')){
|
|
|
+ var serverTokenEndpoint = config.tokenEndpoint;
|
|
|
+ }else{
|
|
|
+ var serverTokenEndpoint = config.serverUrl + config.tokenEndpoint;
|
|
|
}
|
|
|
+ var requestPermissions = config.requestPermissions;
|
|
|
+ var response;
|
|
|
|
|
|
- if (token.refresh_token)
|
|
|
- serviceData.refreshToken = token.refresh_token;
|
|
|
- if (debug) console.log('XXX: serviceData:', serviceData);
|
|
|
-
|
|
|
- profile.name = userinfo[process.env.OAUTH2_FULLNAME_MAP];
|
|
|
- profile.email = userinfo[process.env.OAUTH2_EMAIL_MAP];
|
|
|
-
|
|
|
- if (process.env.OAUTH2_B2C_ENABLED === 'true' || process.env.OAUTH2_B2C_ENABLED === true) {
|
|
|
- profile.email = userinfo["emails"][0];
|
|
|
+ try {
|
|
|
+ var postOptions = {
|
|
|
+ headers: {
|
|
|
+ Accept: 'application/json',
|
|
|
+ "User-Agent": userAgent
|
|
|
+ },
|
|
|
+ params: {
|
|
|
+ code: query.code,
|
|
|
+ client_id: config.clientId,
|
|
|
+ client_secret: OAuth.openSecret(config.secret),
|
|
|
+ redirect_uri: OAuth._redirectUri('oidc', config),
|
|
|
+ grant_type: 'authorization_code',
|
|
|
+ state: query.state
|
|
|
+ }
|
|
|
+ };
|
|
|
+ if (httpCa) {
|
|
|
+ postOptions['npmRequestOptions'] = { ca: httpCa };
|
|
|
+ }
|
|
|
+ response = HTTP.post(serverTokenEndpoint, postOptions);
|
|
|
+ } catch (err) {
|
|
|
+ throw _.extend(new Error("Failed to get token from OIDC " + serverTokenEndpoint + ": " + err.message),
|
|
|
+ { response: err.response });
|
|
|
}
|
|
|
-
|
|
|
- if (debug) console.log('XXX: profile:', profile);
|
|
|
-
|
|
|
- // New code: Check if the user's email is in the allowed emails list (only if oauth2-checkemails is true)
|
|
|
- if (process.env.OAUTH2_CHECKEMAILS === 'true') {
|
|
|
- const allowedEmails = getAllowedEmailsFromFile();
|
|
|
- if (!allowedEmails.includes(profile.email)) {
|
|
|
- throw new Error("Email not allowed: " + profile.email);
|
|
|
- }
|
|
|
+ if (response.data.error) {
|
|
|
+ // if the http response was a json object with an error attribute
|
|
|
+ throw new Error("Failed to complete handshake with OIDC " + serverTokenEndpoint + ": " + response.data.error);
|
|
|
+ } else {
|
|
|
+ if (debug) console.log('XXX: getToken response: ', response.data);
|
|
|
+ return response.data;
|
|
|
}
|
|
|
+ };
|
|
|
+}
|
|
|
|
|
|
- // Temporarily store data from oidc in user.services.oidc.groups to update groups
|
|
|
- serviceData.groups = (userinfo["groups"] && userinfo["wekanGroups"]) ? userinfo["wekanGroups"] : userinfo["groups"];
|
|
|
-
|
|
|
- if (Array.isArray(serviceData.groups) && serviceData.groups.length && typeof serviceData.groups[0] === "string") {
|
|
|
- user = Meteor.users.findOne({'_id': serviceData.id});
|
|
|
+if (process.env.ORACLE_OIM_ENABLED === 'true' || process.env.ORACLE_OIM_ENABLED === true) {
|
|
|
|
|
|
- serviceData.groups.forEach(function (groupName, i) {
|
|
|
- if (user?.isAdmin && i == 0) {
|
|
|
- serviceData.groups[i] = {"isAdmin": true};
|
|
|
- serviceData.groups[i]["displayName"] = groupName;
|
|
|
- } else {
|
|
|
- serviceData.groups[i] = {"displayName": groupName};
|
|
|
- }
|
|
|
- });
|
|
|
+ var getToken = function (query) {
|
|
|
+ var debug = process.env.DEBUG === 'true';
|
|
|
+ var config = getConfiguration();
|
|
|
+ if(config.tokenEndpoint.includes('https://')){
|
|
|
+ var serverTokenEndpoint = config.tokenEndpoint;
|
|
|
+ }else{
|
|
|
+ var serverTokenEndpoint = config.serverUrl + config.tokenEndpoint;
|
|
|
}
|
|
|
+ var requestPermissions = config.requestPermissions;
|
|
|
+ var response;
|
|
|
|
|
|
- // Fix OIDC login loop for integer user ID. Thanks to danielkaiser.
|
|
|
- Meteor.call('groupRoutineOnLogin', serviceData, "" + serviceData.id);
|
|
|
- Meteor.call('boardRoutineOnLogin', serviceData, "" + serviceData.id);
|
|
|
+ // OIM needs basic Authentication token in the header - ClientID + SECRET in base64
|
|
|
+ var dataToken=null;
|
|
|
+ var strBasicToken=null;
|
|
|
+ var strBasicToken64=null;
|
|
|
|
|
|
- return {
|
|
|
- serviceData: serviceData,
|
|
|
- options: { profile: profile }
|
|
|
- };
|
|
|
-});
|
|
|
+ dataToken = process.env.OAUTH2_CLIENT_ID + ':' + process.env.OAUTH2_SECRET;
|
|
|
+ strBasicToken = new Buffer(dataToken);
|
|
|
+ strBasicToken64 = strBasicToken.toString('base64');
|
|
|
|
|
|
-// Function to retrieve token based on environment
|
|
|
-var getToken = function (query) {
|
|
|
- var debug = process.env.DEBUG === 'true';
|
|
|
- var config = getConfiguration();
|
|
|
- var serverTokenEndpoint = config.tokenEndpoint.includes('https://') ?
|
|
|
- config.tokenEndpoint : config.serverUrl + config.tokenEndpoint;
|
|
|
- var response;
|
|
|
+ // eslint-disable-next-line no-console
|
|
|
+ if (debug) console.log('Basic Token: ', strBasicToken64);
|
|
|
|
|
|
try {
|
|
|
- var postOptions = {
|
|
|
- headers: {
|
|
|
- Accept: 'application/json',
|
|
|
- "User-Agent": "Meteor"
|
|
|
- },
|
|
|
- params: {
|
|
|
- code: query.code,
|
|
|
- client_id: config.clientId,
|
|
|
- client_secret: OAuth.openSecret(config.secret),
|
|
|
- redirect_uri: OAuth._redirectUri('oidc', config),
|
|
|
- grant_type: 'authorization_code',
|
|
|
- state: query.state
|
|
|
- }
|
|
|
+ var postOptions = {
|
|
|
+ headers: {
|
|
|
+ Accept: 'application/json',
|
|
|
+ "User-Agent": userAgent,
|
|
|
+ "Authorization": "Basic " + strBasicToken64
|
|
|
+ },
|
|
|
+ params: {
|
|
|
+ code: query.code,
|
|
|
+ client_id: config.clientId,
|
|
|
+ client_secret: OAuth.openSecret(config.secret),
|
|
|
+ redirect_uri: OAuth._redirectUri('oidc', config),
|
|
|
+ grant_type: 'authorization_code',
|
|
|
+ state: query.state
|
|
|
+ }
|
|
|
};
|
|
|
- if (httpCa) {
|
|
|
- postOptions['npmRequestOptions'] = { ca: httpCa };
|
|
|
- }
|
|
|
- response = HTTP.post(serverTokenEndpoint, postOptions);
|
|
|
+ if (httpCa) {
|
|
|
+ postOptions['npmRequestOptions'] = { ca: httpCa };
|
|
|
+ }
|
|
|
+ response = HTTP.post(serverTokenEndpoint, postOptions);
|
|
|
} catch (err) {
|
|
|
- throw _.extend(new Error("Failed to get token from OIDC " + serverTokenEndpoint + ": " + err.message),
|
|
|
- { response: err.response });
|
|
|
+ throw _.extend(new Error("Failed to get token from OIDC " + serverTokenEndpoint + ": " + err.message),
|
|
|
+ { response: err.response });
|
|
|
}
|
|
|
if (response.data.error) {
|
|
|
- throw new Error("Failed to complete handshake with OIDC " + serverTokenEndpoint + ": " + response.data.error);
|
|
|
+ // if the http response was a json object with an error attribute
|
|
|
+ throw new Error("Failed to complete handshake with OIDC " + serverTokenEndpoint + ": " + response.data.error);
|
|
|
} else {
|
|
|
- return response.data;
|
|
|
+ // eslint-disable-next-line no-console
|
|
|
+ if (debug) console.log('XXX: getToken response: ', response.data);
|
|
|
+ return response.data;
|
|
|
}
|
|
|
-};
|
|
|
+ };
|
|
|
+}
|
|
|
|
|
|
-// Function to fetch user information from the OIDC service
|
|
|
-var getUserInfo = function (accessToken) {
|
|
|
- var debug = process.env.DEBUG === 'true';
|
|
|
- var config = getConfiguration();
|
|
|
- var serverUserinfoEndpoint = config.userinfoEndpoint.includes("https://") ?
|
|
|
- config.userinfoEndpoint : config.serverUrl + config.userinfoEndpoint;
|
|
|
|
|
|
- var response;
|
|
|
- try {
|
|
|
- var getOptions = {
|
|
|
- headers: {
|
|
|
- "User-Agent": "Meteor",
|
|
|
- "Authorization": "Bearer " + accessToken
|
|
|
- }
|
|
|
- };
|
|
|
- if (httpCa) {
|
|
|
- getOptions['npmRequestOptions'] = { ca: httpCa };
|
|
|
+var getUserInfo = function (accessToken) {
|
|
|
+ var debug = process.env.DEBUG === 'true';
|
|
|
+ var config = getConfiguration();
|
|
|
+ // Some userinfo endpoints use a different base URL than the authorization or token endpoints.
|
|
|
+ // This logic allows the end user to override the setting by providing the full URL to userinfo in their config.
|
|
|
+ if (config.userinfoEndpoint.includes("https://")) {
|
|
|
+ var serverUserinfoEndpoint = config.userinfoEndpoint;
|
|
|
+ } else {
|
|
|
+ var serverUserinfoEndpoint = config.serverUrl + config.userinfoEndpoint;
|
|
|
+ }
|
|
|
+ var response;
|
|
|
+ try {
|
|
|
+ var getOptions = {
|
|
|
+ headers: {
|
|
|
+ "User-Agent": userAgent,
|
|
|
+ "Authorization": "Bearer " + accessToken
|
|
|
}
|
|
|
- response = HTTP.get(serverUserinfoEndpoint, getOptions);
|
|
|
- } catch (err) {
|
|
|
- throw _.extend(new Error("Failed to fetch userinfo from OIDC " + serverUserinfoEndpoint + ": " + err.message),
|
|
|
- {response: err.response});
|
|
|
+ };
|
|
|
+ if (httpCa) {
|
|
|
+ getOptions['npmRequestOptions'] = { ca: httpCa };
|
|
|
}
|
|
|
- return response.data;
|
|
|
+ response = HTTP.get(serverUserinfoEndpoint, getOptions);
|
|
|
+ } catch (err) {
|
|
|
+ throw _.extend(new Error("Failed to fetch userinfo from OIDC " + serverUserinfoEndpoint + ": " + err.message),
|
|
|
+ {response: err.response});
|
|
|
+ }
|
|
|
+ if (debug) console.log('XXX: getUserInfo response: ', response.data);
|
|
|
+ return response.data;
|
|
|
};
|
|
|
|
|
|
-// Function to get the configuration of the OIDC service
|
|
|
var getConfiguration = function () {
|
|
|
- var config = ServiceConfiguration.configurations.findOne({ service: 'oidc' });
|
|
|
- if (!config) {
|
|
|
- throw new ServiceConfiguration.ConfigError('Service oidc not configured.');
|
|
|
- }
|
|
|
- return config;
|
|
|
+ var config = ServiceConfiguration.configurations.findOne({ service: 'oidc' });
|
|
|
+ if (!config) {
|
|
|
+ throw new ServiceConfiguration.ConfigError('Service oidc not configured.');
|
|
|
+ }
|
|
|
+ return config;
|
|
|
};
|
|
|
|
|
|
-// Function to decode the token content (JWT)
|
|
|
var getTokenContent = function (token) {
|
|
|
- var content = null;
|
|
|
- if (token) {
|
|
|
- try {
|
|
|
- var parts = token.split('.');
|
|
|
- var header = JSON.parse(Buffer.from(parts[0], 'base64').toString());
|
|
|
- content = JSON.parse(Buffer.from(parts[1], 'base64').toString());
|
|
|
- } catch (err) {
|
|
|
- content = { exp: 0 };
|
|
|
- }
|
|
|
+ var content = null;
|
|
|
+ if (token) {
|
|
|
+ try {
|
|
|
+ var parts = token.split('.');
|
|
|
+ var header = JSON.parse(Buffer.from(parts[0], 'base64').toString());
|
|
|
+ content = JSON.parse(Buffer.from(parts[1], 'base64').toString());
|
|
|
+ var signature = Buffer.from(parts[2], 'base64');
|
|
|
+ var signed = parts[0] + '.' + parts[1];
|
|
|
+ } catch (err) {
|
|
|
+ this.content = {
|
|
|
+ exp: 0
|
|
|
+ };
|
|
|
}
|
|
|
- return content;
|
|
|
+ }
|
|
|
+ return content;
|
|
|
}
|
|
|
-
|
|
|
-// Meteor methods to update groups and boards on login
|
|
|
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({'services.oidc.id': userId});
|
|
|
-
|
|
|
- if (user) {
|
|
|
- if (info.groups) {
|
|
|
- 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);
|
|
|
- }
|
|
|
+ '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({'services.oidc.id': userId});
|
|
|
+
|
|
|
+ if(user) {
|
|
|
+ //updates/creates Groups and user admin privileges accordingly if not undefined
|
|
|
+ if (info.groups) {
|
|
|
+ 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);
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
Meteor.methods({
|
|
|
- 'boardRoutineOnLogin': function(info, userId) {
|
|
|
- check(info, Object);
|
|
|
- check(userId, String);
|
|
|
- // Add board updates here if needed
|
|
|
- }
|
|
|
-});
|
|
|
+ 'boardRoutineOnLogin': function(info, oidcUserId)
|
|
|
+ {
|
|
|
+ check(info, Object);
|
|
|
+ check(oidcUserId, String);
|
|
|
+
|
|
|
+ const defaultBoardParams = (process.env.DEFAULT_BOARD_ID || '').split(':');
|
|
|
+ const defaultBoardId = defaultBoardParams.shift()
|
|
|
+ if (!defaultBoardId) return
|
|
|
+
|
|
|
+ const board = Boards.findOne(defaultBoardId)
|
|
|
+ const userId = Users.findOne({ 'services.oidc.id': oidcUserId })?._id
|
|
|
+ const memberIndex = _.pluck(board?.members, 'userId').indexOf(userId);
|
|
|
+ if(!board || !userId || memberIndex > -1) return
|
|
|
+
|
|
|
+ board.addMember(userId)
|
|
|
+ board.setMemberPermission(
|
|
|
+ userId,
|
|
|
+ defaultBoardParams.contains("isAdmin"),
|
|
|
+ defaultBoardParams.contains("isNoComments"),
|
|
|
+ defaultBoardParams.contains("isCommentsOnly"),
|
|
|
+ defaultBoardParams.contains("isWorker")
|
|
|
+ )
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+Oidc.retrieveCredential = function (credentialToken, credentialSecret) {
|
|
|
+ return OAuth.retrieveCredential(credentialToken, credentialSecret);
|
|
|
+};
|