Files
metabase/e2e/support/helpers/embedding-sdk-testing/embedding-sdk-helpers.ts

167 lines
4.2 KiB
TypeScript

import * as jose from "jose";
import { loginCache } from "e2e/support/commands/user/authentication";
import { USERS } from "e2e/support/cypress_data";
import {
AUTH_PROVIDER_URL,
JWT_SHARED_SECRET,
METABASE_INSTANCE_URL,
activateToken,
restore,
updateSetting,
} from "e2e/support/helpers";
import { enableJwtAuth } from "e2e/support/helpers/e2e-jwt-helpers";
export const getSignedJwtForUser = async ({
user = USERS.admin,
expiredInSeconds = 60 * 10, // 10 minutes expiration,
}: {
user?: { email: string; first_name: string; last_name: string };
expiredInSeconds?: number;
}) => {
const secret = new TextEncoder().encode(JWT_SHARED_SECRET);
return new jose.SignJWT({
email: user.email,
first_name: user.first_name,
last_name: user.last_name,
exp: Math.round(Date.now() / 1000) + expiredInSeconds,
})
.setProtectedHeader({ alg: "HS256" })
.sign(secret);
};
export const mockAuthProviderAndJwtSignIn = (
user = USERS.admin,
{ jwt }: { jwt?: string } = {},
) => {
cy.intercept("GET", `${AUTH_PROVIDER_URL}**`, async (req) => {
try {
const url = new URL(req.url);
const responseParam = url.searchParams.get("response");
// Return error if response is not json
if (responseParam !== "json") {
req.reply({
statusCode: 400,
body: { error: "Invalid response parameter. Expected response=json" },
});
return;
}
jwt = jwt || (await getSignedJwtForUser({ user }));
req.reply({
statusCode: 200,
body: { jwt },
});
} catch (error: any) {
console.warn("SDK auth error:", error);
req.reply({
statusCode: 500,
body: error.message,
});
}
}).as("jwtProvider");
};
export function signInAsAdminAndEnableEmbeddingSdk() {
Cypress.config("baseUrl", METABASE_INSTANCE_URL);
restore();
cy.signInAsAdmin();
activateToken("bleeding-edge");
enableJwtAuth();
cy.request("PUT", "/api/setting", {
"enable-embedding-sdk": true,
});
}
export function signInAsAdminAndSetupGuestEmbedding({
token,
}: {
token: "starter" | "pro-cloud";
}) {
Cypress.config("baseUrl", METABASE_INSTANCE_URL);
restore();
cy.signInAsAdmin();
activateToken(token);
updateSetting("embedding-secret-key", JWT_SHARED_SECRET);
}
const MOCK_SAML_IDP_URI = "https://example.test/saml";
export function enableSamlAuth() {
cy.readFile<string>("test_resources/sso/auth0-public-idp.cert", "utf8").then(
(certificate) => {
cy.request("PUT", "/api/setting", {
"saml-enabled": true,
"saml-identity-provider-uri": MOCK_SAML_IDP_URI,
"saml-identity-provider-certificate": certificate,
"saml-identity-provider-issuer": "https://example.test/issuer",
});
},
);
}
export function mockAuthSsoEndpointForSamlAuthProvider() {
cy.intercept("GET", "/auth/sso", (req) => {
req.reply({
statusCode: 200,
body: {
method: "saml",
url: MOCK_SAML_IDP_URI,
hash: "test-hash",
},
});
});
}
export function stubWindowOpenForSamlPopup({
isUserValid = true,
}: {
isUserValid?: boolean;
} = {}) {
cy.window().then((win) => {
const popup = {
closed: false,
close: () => {
popup.closed = true;
},
};
// stub `window.open(IDP_URI, ...)` for the SAML popup
cy.stub(win, "open")
.withArgs(MOCK_SAML_IDP_URI)
.callsFake(() => {
setTimeout(() => {
// Simulate the SAML_AUTH_COMPLETE message
win.dispatchEvent(
new MessageEvent("message", {
data: {
type: "SAML_AUTH_COMPLETE",
// The snapshot creator populates the cache with a real session token.
// Without this, we get an "invalid user" error as we need a valid session.
authData: {
id: isUserValid
? loginCache.normal?.sessionId
: "invalid-session-token",
exp: Math.floor(Date.now() / 1000) + 600, // 10 minutes
},
},
origin: "*",
}),
);
popup.close();
}, 100); // simulate async delay
return popup;
});
});
}