-
-
Save jkosters/63726a89f8e2be396c4c1675eca90837 to your computer and use it in GitHub Desktop.
Automated Azure AD login and session token capture to json file for reading by Cypress commands. Heavily inspired by https://gist.github.com/saschwarz/b7f115ab6a7765ff5e45b9b9461cf895
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const api = Cypress.env("API"); | |
const headers = { | |
Authorization: "" | |
}; | |
Cypress.Commands.add("loginUser", () => { | |
return cy.readFile("aad-tokens.json") | |
.then(credentials => { | |
// set auth headers so test setup calls are authorized | |
headers.Authorization = `Bearer ${credentials["msal.idtoken"]}`; | |
// put MS Azure AD creds in session storage | |
// so application under test will be logged in. | |
for (let key in credentials) { | |
if (credentials.hasOwnProperty(key)) { | |
if ( | |
key.startsWith("msal.") || | |
key.startsWith('{"authority":') | |
) { | |
sessionStorage[key] = credentials[key]; | |
} | |
} | |
} | |
}); | |
}); | |
// example of custom command using headers configured via loginUser | |
Cypress.Commands.add("APICreate", (url, instance) => { | |
window.Cypress.log({ | |
name: "APICreate", | |
message: url + " | " + JSON.stringify(instance) | |
}); | |
return cy.request({ | |
method: "POST", | |
headers: headers, | |
url: `${api}/${url}`, | |
body: instance | |
}).then(data => data.body); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require("fs"); | |
const puppeteer = require("puppeteer"); | |
const commander = require("commander"); | |
const inquirer = require("inquirer"); | |
const util = require("util"); | |
const readFile = util.promisify(fs.readFile); | |
const aadToken = { | |
filename: "aad-tokens.json", | |
filepath: `./aad-tokens.json`, | |
encoding: "utf8", | |
defaultValues: { | |
appURI: "http://localhost:4200/app/", | |
email: "", | |
password: "" | |
}, | |
selectors: { | |
usernameInput: "input[name=loginfmt]", | |
passwordInput: "input[name=Password]", | |
submitInput: "input[type=submit]", | |
submitButton: "#submitButton", | |
domainPage: '#appId' | |
} | |
}; | |
const onWriteFileError = (error) => { | |
if (error) { | |
console.log(error); | |
} | |
}; | |
const writeAadTokenFile = function (aadTokenValues) { | |
return fs.writeFile(aadToken.filename, | |
JSON.stringify(aadTokenValues), | |
{ encoding: aadToken.encoding }, | |
onWriteFileError); | |
}; | |
const collectAadValuesFromSessionStorage = (conf) => { | |
for (let i = 0, len = sessionStorage.length; i < len; ++i) { | |
if ( | |
sessionStorage.key(i).startsWith("msal.") || | |
sessionStorage.key(i).startsWith('{"authority":') | |
) { | |
conf[sessionStorage.key(i)] = sessionStorage.getItem( | |
sessionStorage.key(i) | |
); | |
} | |
} | |
return conf; | |
}; | |
const createWaitOptions = function (delayInMs = 3000) { | |
return { visible: true, delay: delayInMs }; | |
}; | |
const getAdToken = function (config) { | |
console.log(`Logging in ${config.email} at ${config.appURI}`); | |
return puppeteer.launch({ headless: false }).then(async browser => { | |
try { | |
const page = await browser.newPage(); | |
await page.goto(config.appURI); | |
await page.waitForSelector(aadToken.selectors.usernameInput, createWaitOptions(3000)); | |
await page.type(aadToken.selectors.usernameInput, config.email, { | |
delay: 50 | |
}); | |
await page.click(aadToken.selectors.submitInput); | |
console.log(`Username submitted`); | |
await page.waitForSelector(aadToken.selectors.passwordInput, createWaitOptions(10000)); | |
await page.type(aadToken.selectors.passwordInput, config.password, { | |
delay: 50 | |
}); | |
await page.click(aadToken.selectors.submitButton); | |
console.log(`password submitted`); | |
await page.waitForSelector(aadToken.selectors.submitInput, createWaitOptions(1000)); | |
await page.click(aadToken.selectors.submitInput); | |
console.log(`Do save credentials submitted`); | |
page.waitForNavigation(); | |
await page.waitForXPath(aadToken.xpath.domainPage, createWaitOptions(10000)); | |
const aadValues = await page.evaluate(collectAadValuesFromSessionStorage, config); | |
browser.close(); | |
console.log(`aad values collected`); | |
fs.readFile(aadToken.filename, aadToken.encoding, () => writeAadTokenFile(aadValues)); | |
console.log(`${aadToken.filename} updated`); | |
} catch (error) { | |
console.log(error); | |
browser.close(); | |
} | |
}); | |
}; | |
const promptUser = async function (defaults) { | |
const config = await inquirer.prompt([{ | |
name: "appURI", | |
message: "App URI:", | |
default: defaults.appURI | |
}, | |
{ | |
name: "email", | |
message: "Email:", | |
default: defaults.email | |
}, | |
{ | |
name: "password", | |
message: "Password:", | |
default: defaults.password, | |
type: "password" | |
} | |
]); | |
await writeAadTokenFile(config); | |
return config; | |
}; | |
const loginUser = function (prompt = false) { | |
Promise.resolve().then(async () => { | |
let config = await readFile(aadToken.filepath, aadToken.encoding) | |
.then(file => JSON.parse(file)) | |
.catch(() => aadToken.defaultValues); | |
if (prompt) { | |
config = await promptUser(config); | |
} | |
getAdToken(config); | |
}); | |
}; | |
const main = () => { | |
commander | |
.option("--no-prompt", "Do not prompt for input and accept values from aad-tokens.json", false) | |
.parse(process.argv); | |
loginUser(commander.prompt); | |
}; | |
module.exports = { | |
getAdToken: getAdToken, | |
loginUser: loginUser | |
}; | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment