cypress/integration/authentication.js (250 lines of code) (raw):
/// <reference types="cypress" />
Cypress.Screenshot.defaults({
screenshotOnRunFailure: false,
});
Cypress.Cookies.defaults({
domain: "0.0.0.0",
});
Cypress.Cookies.debug(true);
// we are not including AAD in this list because it has a special rule (see staticwebapp.config.json)
const PROVIDERS_AVAILABLE = ["google", "github", "twitter", "facebook"];
const SWA_AUTH_COOKIE_NAME = "StaticWebAppsAuthCookie";
const clientPrincipal = {
identityProvider: "facebook",
userId: "d75b260a64504067bfc5b2905e3b8182",
userDetails: "user@example.com",
userRoles: ["authenticated"],
claims: [
{
typ: "name",
val: "Azure Static Web Apps",
},
],
};
context("Authentication", () => {
beforeEach(() => {
cy.visit("http://0.0.0.0:1234");
});
describe("when user is not logged in", () => {
it("should have clientPrincipal to null", () => {
cy.clearCookie(SWA_AUTH_COOKIE_NAME);
cy.request("/.auth/me").should((response) => {
expect(response.status).to.eq(200);
expect(response.body).to.have.property("clientPrincipal").to.eq(null);
expect(response).to.have.property("headers");
});
});
});
describe("when user is logged in", () => {
it("should have clientPrincipal to be populated", () => {
cy.setCookie(SWA_AUTH_COOKIE_NAME, window.btoa(JSON.stringify(clientPrincipal)));
cy.request("/.auth/me").should((response) => {
expect(response.status).to.eq(200);
expect(response.body.clientPrincipal.identityProvider).to.deep.eq(clientPrincipal.identityProvider);
expect(response.body.clientPrincipal.userId).to.deep.eq(clientPrincipal.userId);
expect(response.body.clientPrincipal.userDetails).to.deep.eq(clientPrincipal.userDetails);
expect(response.body.clientPrincipal.userRoles).to.deep.eq(clientPrincipal.userRoles);
expect(response.body.clientPrincipal.claims).to.deep.eq(clientPrincipal.claims);
});
});
it("should have authenticated role", () => {
clientPrincipal.userRoles = ["foo"];
cy.setCookie(SWA_AUTH_COOKIE_NAME, window.btoa(JSON.stringify(clientPrincipal)));
cy.request("/.auth/me").should((response) => {
expect(response.status).to.eq(200);
expect(response.body.clientPrincipal.userRoles).to.deep.eq(["foo", "anonymous", "authenticated"]);
});
});
});
});
context(`/.auth/login/<provider>`, () => {
for (let index = 0; index < PROVIDERS_AVAILABLE.length; index++) {
const provider = PROVIDERS_AVAILABLE[index];
describe(`when using provider: ${provider}`, () => {
it(`provider should be ${provider}`, () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/${provider}`);
cy.get("#identityProvider").should("be.disabled");
cy.get("#identityProvider").should("have.value", provider);
});
it("username should be empty", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/${provider}`);
cy.get("#userDetails").should("be.empty");
});
it("userId should be empty", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/${provider}`);
cy.get("#userId").should("be.empty");
});
it("userRoles should contains authenticated and anonymous roles", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/${provider}`);
cy.get("#userRoles").should("have.value", "anonymous\nauthenticated");
});
it("claims should contains an empty array", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/${provider}`);
cy.get("#claims").should("have.value", "[]");
});
});
}
});
context("/.auth/logout", () => {
beforeEach(() => {
cy.visit("http://0.0.0.0:1234");
});
describe("when using accessing /.auth/logout", () => {
it("should redirect to / with code=302", () => {
cy.request({
url: "/.auth/logout",
followRedirect: false,
}).as("response");
cy.get("@response")
.its("headers")
.then((headers) => {
expect(headers).to.deep.include({
status: "302",
location: "http://0.0.0.0:1234/",
"set-cookie": ["StaticWebAppsAuthCookie=deleted; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT"],
});
});
});
});
});
context("custom routes for login/logout", () => {
describe("when using custom route /login-github", () => {
beforeEach(() => {
cy.visit("http://0.0.0.0:1234/login-github");
});
it("provider should be 'github'", () => {
cy.get("#identityProvider").should("be.disabled");
cy.get("#identityProvider").should("have.value", "github");
});
it("should have meta tag", () => {
cy.get("meta[name='swa:originalPath']").should("have.attr", "content", "http://0.0.0.0:1234/.auth/login/github");
});
});
describe("when using custom /logout route", () => {
beforeEach(() => {
cy.visit("http://0.0.0.0:1234/");
});
it("should redirect to / with code=302", () => {
cy.request({
url: "/logout",
followRedirect: false,
}).as("response");
cy.get("@response")
.its("headers")
.then((headers) => {
expect(headers).to.deep.include({
status: "302",
location: "http://0.0.0.0:1234/",
"set-cookie": ["StaticWebAppsAuthCookie=deleted; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT"],
});
});
});
});
});
context("checking localStorage", () => {
beforeEach(() => {
cy.clearLocalStorage();
});
describe("caching auth info in localStorage", () => {
for (let index = 0; index < PROVIDERS_AVAILABLE.length; index++) {
const provider = PROVIDERS_AVAILABLE[index];
it(`should cache auth: ${provider}`, () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/${provider}`);
cy.get("#userDetails")
.type(`foobar-${provider}`)
.trigger("keyup")
.should(() => {
const authInfo = localStorage.getItem(`auth@${provider}`);
expect(authInfo).not.to.be.null;
const json = JSON.parse(authInfo);
expect(json.userId.length).to.eq(32);
expect(json.identityProvider).to.eq(provider);
expect(json.userDetails).to.eq(`foobar-${provider}`);
expect(json.userRoles).to.deep.eq(["anonymous", "authenticated"]);
expect(json.claims).to.deep.eq([]);
});
});
}
});
});
context("UI buttons", () => {
describe("Login button", () => {
it("should not submit if missing userId ", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/github`);
cy.get("#userId").clear();
cy.get("#submit").click();
cy.get("#userId:invalid").should("exist");
});
it("should not submit if missing userDetails ", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/github`);
cy.get("#userDetails").clear();
cy.get("#submit").click();
cy.get("#userDetails:invalid").should("exist");
});
it("should not submit if invalid claims JSON value", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/github`);
cy.get("#claims").type("*&^%$#@!");
cy.get("#userClaimsHelpBlockError").should("be.visible");
cy.get("#submit").should("be.disabled");
});
it("should submit and redirect to /", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/github`);
cy.get("#userDetails").type("foo");
cy.get("#submit")
.click()
.then(() => {
cy.url().should("eq", "http://0.0.0.0:1234/");
});
});
it("should submit and redirect to /home", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/github?post_login_redirect_uri=/home`);
cy.get("#userDetails").type("foo");
cy.get("#submit")
.click()
.then(() => {
cy.url().should("eq", "http://0.0.0.0:1234/home");
});
});
});
describe("Clear button", () => {
it("should reset form", () => {
cy.visit(`http://0.0.0.0:1234/.auth/login/github`);
cy.get("#clear")
.click()
.then(() => {
cy.get("#identityProvider").should("have.value", "github");
cy.get("#userDetails").should("have.value", "");
cy.get("#userRoles").should((element) => {
expect(element.val()).to.eq("anonymous\nauthenticated");
});
cy.get("#userId").should((element) => {
expect(element.val().length).to.eq(32);
});
expect(localStorage.getItem("auth@github")).not.to.be.null;
});
});
});
});
context("Route authorization", () => {
describe("accessing /only-authenticated", () => {
it("should return 401 if no roles provided in client principal", () => {
clientPrincipal.userRoles = [];
cy.setCookie(SWA_AUTH_COOKIE_NAME, window.btoa(JSON.stringify(clientPrincipal)));
cy.request({ url: "http://0.0.0.0:1234/only-authenticated", failOnStatusCode: false }).should((response) => {
expect(response.status).to.eq(401);
});
});
it("should return 401 for non 'authenticated' roles", () => {
clientPrincipal.userRoles = ["admin"];
cy.setCookie(SWA_AUTH_COOKIE_NAME, window.btoa(JSON.stringify(clientPrincipal)));
cy.request({ url: "http://0.0.0.0:1234/only-authenticated", failOnStatusCode: false }).then((response) => {
expect(response.status).to.eq(401);
});
});
it("should return 200 for 'authenticated' roles", () => {
clientPrincipal.userRoles = ["authenticated"];
cy.setCookie(SWA_AUTH_COOKIE_NAME, window.btoa(JSON.stringify(clientPrincipal)));
cy.request({ url: "http://0.0.0.0:1234/only-authenticated", failOnStatusCode: false }).then((response) => {
expect(response.status).to.eq(200);
});
});
});
});