Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 48 additions & 13 deletions services/cubejs/src/utils/checkSqlAuth.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,60 @@ const buildSqlSecurityContext = (sqlCredentials) => {
teamId
);

const dataSourceContext = buildSecurityContext(sqlCredentials?.datasource);
// Resolve team settings + per-member properties so queryRewrite rules can
// evaluate `property_source: team` / `property_source: member` lookups for
// SQL API logins. Without these, every rule blocks and queries get rewritten
// to the `__blocked_by_access_control__` sentinel.
const teamMember = Array.isArray(allMembers)
? allMembers.find((m) => m.team_id === teamId)
: null;
const teamSettings = teamMember?.team?.settings || {};
const memberProperties = teamMember?.properties || {};

const dataSourceContext = buildSecurityContext(
sqlCredentials?.datasource,
undefined,
undefined,
teamSettings
);

return {
dataSource: dataSourceContext,
...dataSourceAccessList,
teamProperties: teamSettings,
memberProperties,
};
};

/**
* Check SQL authentication for a user.
*
* Cube.js v1.6 invokes this callback as `checkSqlAuth(request, user, password)`
* (see @cubejs-backend/api-gateway/dist/src/sql-server.js — the callback is
* wrapped with three positional args). Earlier builds passed a single object
* `{ username, password }`; the defensive branches below keep backward-
* compatibility with that older shape.
*
* Supports two authentication methods:
* 1. WorkOS JWT as password (new): password is a JWT, username is datasource ID
* 2. Legacy sql_credentials lookup (existing): username/password from sql_credentials table
* 1. WorkOS / FraiOS JWT as password: password is a JWT, username is the datasource ID
* 2. Legacy sql_credentials lookup: username/password from the sql_credentials table
*
* @param {null} _ - Unused parameter.
* @param {Object} user - The user object with username and password.
* @returns {Promise} - Resolves to { password, securityContext }
* @param {Object} request - Cube.js SQL request metadata (protocol, method, apiType)
* @param {string|Object} userArg - Username string (v1.6+) or legacy { username, password } object
* @param {string} [passwordArg] - Password string (v1.6+); absent in legacy object-shape calls
* @returns {Promise<{ password: string, securityContext: Object }>}
*/
const checkSqlAuth = async (_, user) => {
const password = typeof user === "string" ? user : user?.password;
const username = typeof user === "string" ? _ : user?.username;

// Detect if password looks like a JWT (WorkOS RS256)
const checkSqlAuth = async (request, userArg, passwordArg) => {
// Resolve the two shapes Cube has used for this callback:
// new: (request, username: string, password: string)
// legacy: (_req, { username, password })
const username =
typeof userArg === "string" ? userArg : userArg?.username;
const password =
passwordArg ??
(typeof userArg === "string" ? undefined : userArg?.password);

// Detect if password looks like a JWT (WorkOS RS256 / FraiOS HS256)
if (password && password.includes(".") && password.split(".").length === 3) {
const tokenType = detectTokenType(password);

Expand Down Expand Up @@ -134,8 +165,12 @@ const checkSqlAuth = async (_, user) => {
}
}

// Legacy sql_credentials path (unchanged)
const sqlCredentials = await findSqlCredentials(username || user);
// Legacy sql_credentials path — lookup by the plaintext username.
// Cube.js compares the supplied password against `password` in the return value.
if (!username || typeof username !== "string") {
throw new Error("Incorrect user name or password");
}
const sqlCredentials = await findSqlCredentials(username);

return {
password: sqlCredentials?.password,
Expand Down
5 changes: 5 additions & 0 deletions services/cubejs/src/utils/dataSourceHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ const membersFragment = `
members {
id
team_id
properties
team {
id
settings
}
member_roles {
id
team_role
Expand Down
Loading