From 38d7a1ee607d3c360bd8737072b03d2f2ad2b633 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Mon, 6 Oct 2025 13:29:51 +0100 Subject: [PATCH 1/3] Convert Users.SSOGroups to TEXT from STRING fixes #6102 This allows for unlimited SSO groups list length rather than limiting to 255 characters --- .../20251006-01-fix-sso-group-type.js | 44 +++++++++++++++++++ forge/db/models/User.js | 2 +- forge/ee/routes/sso/auth.js | 18 +++++--- 3 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 forge/db/migrations/20251006-01-fix-sso-group-type.js diff --git a/forge/db/migrations/20251006-01-fix-sso-group-type.js b/forge/db/migrations/20251006-01-fix-sso-group-type.js new file mode 100644 index 0000000000..14cb1eb31d --- /dev/null +++ b/forge/db/migrations/20251006-01-fix-sso-group-type.js @@ -0,0 +1,44 @@ +/** + * Change column type + */ + +const { DataTypes } = require('sequelize') + +module.exports = { + up: async (context, Sequelize) => { + const dialect = context.sequelize.options.dialect + if (dialect === 'sqlite') { + const sqlFind = "select sql from SQLITE_MASTER where name = 'Users' and type = 'table';" + const [results] = await context.sequelize.query(sqlFind) + if (results.length === 0) { + return // Nothing to do + } + + //Check if the DDL is as expected already + const ddl = results[0].sql + const re = /(`SSOGroups`[^,]+?VARCHAR\(255\))/.exec(ddl) + if (!re || re.length < 2) { + return // Nothing to do + } + + // create new column definition + const currentColDef = re[1] + const newColDef = currentColDef.replace('VARCHAR(255)', 'TEXT') + + // update the table with the new column definition + await context.sequelize.query('pragma writable_schema=1;') + const sqlUpdate = `update SQLITE_MASTER set sql = replace(sql, '${currentColDef}', '${newColDef}') where name = 'Users' and type = 'table';` + context.sequelize.query(sqlUpdate) + await context.sequelize.query('pragma writable_schema=0;') + } else { + // This will trigger the User delete actions on SQLITE + await context.changeColumn('Users', 'SSOGroups', { + type: DataTypes.TEXT, + allowNull: true + }) + } + + }, + down: async (useContext, Sequelize) => { + } +} \ No newline at end of file diff --git a/forge/db/models/User.js b/forge/db/models/User.js index 5b6ab4a20d..a5ed3bd6f3 100644 --- a/forge/db/models/User.js +++ b/forge/db/models/User.js @@ -44,7 +44,7 @@ module.exports = { defaultValue: false }, SSOGroups: { - type: DataTypes.STRING, + type: DataTypes.TEXT, allowNull: true, get () { const rawValue = this.getDataValue('SSOGroups') diff --git a/forge/ee/routes/sso/auth.js b/forge/ee/routes/sso/auth.js index 4e13c9a92f..ba75eec1ef 100644 --- a/forge/ee/routes/sso/auth.js +++ b/forge/ee/routes/sso/auth.js @@ -100,13 +100,17 @@ module.exports = fp(async function (app, opts) { return } } - if (providerOpts.exposeGroups) { - // get SAML groups - user.SSOGroups = app.sso.getUserGroups(samlUser, user, providerOpts) - await user.save() - } else { - user.SSOGroups = null - await user.save() + try { + if (providerOpts.exposeGroups) { + // get SAML groups + user.SSOGroups = app.sso.getUserGroups(samlUser, user, providerOpts) + await user.save() + } else { + user.SSOGroups = null + await user.save() + } + } catch (err) { + app.log.error(`SAML SSOGroups error: ${err.toString()} ${err.stack}`) } done(null, user) } else { From 2fc14c43ef174aa2082578dc55d65eff3402efc1 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Mon, 6 Oct 2025 13:52:32 +0100 Subject: [PATCH 2/3] Fix lint --- forge/db/migrations/20251006-01-fix-sso-group-type.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/forge/db/migrations/20251006-01-fix-sso-group-type.js b/forge/db/migrations/20251006-01-fix-sso-group-type.js index 14cb1eb31d..5f795a6589 100644 --- a/forge/db/migrations/20251006-01-fix-sso-group-type.js +++ b/forge/db/migrations/20251006-01-fix-sso-group-type.js @@ -14,7 +14,7 @@ module.exports = { return // Nothing to do } - //Check if the DDL is as expected already + // Check if the DDL is as expected already const ddl = results[0].sql const re = /(`SSOGroups`[^,]+?VARCHAR\(255\))/.exec(ddl) if (!re || re.length < 2) { @@ -37,8 +37,7 @@ module.exports = { allowNull: true }) } - }, down: async (useContext, Sequelize) => { } -} \ No newline at end of file +} From a91a8e12956785a0917d14b547567244572ceaae Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Tue, 7 Oct 2025 17:50:57 +0100 Subject: [PATCH 3/3] Apply suggestions from code review --- forge/db/migrations/20251006-01-fix-sso-group-type.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/forge/db/migrations/20251006-01-fix-sso-group-type.js b/forge/db/migrations/20251006-01-fix-sso-group-type.js index 5f795a6589..313c5e0a92 100644 --- a/forge/db/migrations/20251006-01-fix-sso-group-type.js +++ b/forge/db/migrations/20251006-01-fix-sso-group-type.js @@ -8,6 +8,7 @@ module.exports = { up: async (context, Sequelize) => { const dialect = context.sequelize.options.dialect if (dialect === 'sqlite') { + // For SQLITE, we need to avoid triggering cascading deletes due to the way it does column changes const sqlFind = "select sql from SQLITE_MASTER where name = 'Users' and type = 'table';" const [results] = await context.sequelize.query(sqlFind) if (results.length === 0) { @@ -31,7 +32,7 @@ module.exports = { context.sequelize.query(sqlUpdate) await context.sequelize.query('pragma writable_schema=0;') } else { - // This will trigger the User delete actions on SQLITE + // For Postgres, we can use changeColumn directly. await context.changeColumn('Users', 'SSOGroups', { type: DataTypes.TEXT, allowNull: true