playwright-ms-auth 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +525 -0
- package/bin/ms-auth +2 -0
- package/lib/authenticate.d.ts +10 -0
- package/lib/authenticate.d.ts.map +1 -0
- package/lib/authenticate.js +213 -0
- package/lib/authenticate.js.map +1 -0
- package/lib/certAuth.d.ts +21 -0
- package/lib/certAuth.d.ts.map +1 -0
- package/lib/certAuth.js +82 -0
- package/lib/certAuth.js.map +1 -0
- package/lib/cli.d.ts +3 -0
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +109 -0
- package/lib/cli.js.map +1 -0
- package/lib/config.d.ts +10 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +115 -0
- package/lib/config.js.map +1 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +17 -0
- package/lib/index.js.map +1 -0
- package/lib/providers/AzureKeyVaultProvider.d.ts +17 -0
- package/lib/providers/AzureKeyVaultProvider.d.ts.map +1 -0
- package/lib/providers/AzureKeyVaultProvider.js +105 -0
- package/lib/providers/AzureKeyVaultProvider.js.map +1 -0
- package/lib/providers/CredentialProvider.d.ts +24 -0
- package/lib/providers/CredentialProvider.d.ts.map +1 -0
- package/lib/providers/CredentialProvider.js +10 -0
- package/lib/providers/CredentialProvider.js.map +1 -0
- package/lib/providers/CredentialProviderFactory.d.ts +20 -0
- package/lib/providers/CredentialProviderFactory.d.ts.map +1 -0
- package/lib/providers/CredentialProviderFactory.js +37 -0
- package/lib/providers/CredentialProviderFactory.js.map +1 -0
- package/lib/providers/EnvironmentProvider.d.ts +13 -0
- package/lib/providers/EnvironmentProvider.d.ts.map +1 -0
- package/lib/providers/EnvironmentProvider.js +52 -0
- package/lib/providers/EnvironmentProvider.js.map +1 -0
- package/lib/providers/GitHubSecretsProvider.d.ts +13 -0
- package/lib/providers/GitHubSecretsProvider.d.ts.map +1 -0
- package/lib/providers/GitHubSecretsProvider.js +59 -0
- package/lib/providers/GitHubSecretsProvider.js.map +1 -0
- package/lib/providers/LocalFileProvider.d.ts +13 -0
- package/lib/providers/LocalFileProvider.d.ts.map +1 -0
- package/lib/providers/LocalFileProvider.js +77 -0
- package/lib/providers/LocalFileProvider.js.map +1 -0
- package/lib/providers/index.d.ts +7 -0
- package/lib/providers/index.d.ts.map +1 -0
- package/lib/providers/index.js +7 -0
- package/lib/providers/index.js.map +1 -0
- package/lib/types.d.ts +111 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +37 -0
- package/lib/types.js.map +1 -0
- package/lib/utils.d.ts +30 -0
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +75 -0
- package/lib/utils.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { expect, chromium } from "@playwright/test";
|
|
2
|
+
import { CredentialProviderFactory } from "./providers";
|
|
3
|
+
import { addCertAuthRoute, waitForCertAuthResponse } from "./certAuth";
|
|
4
|
+
import { log, getStorageStatePath, getAuthScreenshotPath, ensureDirExists, isStorageStateValid, } from "./utils";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
const DEFAULT_LOGIN_ENDPOINT = "login.microsoftonline.com";
|
|
7
|
+
/**
|
|
8
|
+
* Perform Microsoft Entra authentication and save storage state
|
|
9
|
+
*/
|
|
10
|
+
export async function authenticate(config, targetUrl) {
|
|
11
|
+
const storagePath = getStorageStatePath(config.email);
|
|
12
|
+
// Check if existing storage state is still valid
|
|
13
|
+
const isValid = await isStorageStateValid(storagePath, config.storageStateExpiration);
|
|
14
|
+
if (isValid) {
|
|
15
|
+
log(`[MsAuth] Storage state for '${config.email}' is still valid, skipping authentication`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
log(`[MsAuth] Starting authentication for '${config.email}'`);
|
|
19
|
+
log(`[MsAuth] Credential provider: ${config.credentialProvider}`);
|
|
20
|
+
log(`[MsAuth] Credential type: ${config.credentialType}`);
|
|
21
|
+
// Create credential provider and retrieve credential
|
|
22
|
+
const provider = CredentialProviderFactory.createProvider(config.credentialProvider, config.providerConfig);
|
|
23
|
+
const credential = await provider.getCredential();
|
|
24
|
+
// Validate credential type matches configuration
|
|
25
|
+
if (credential.type !== config.credentialType) {
|
|
26
|
+
log(`[MsAuth] ##[warning]Credential type mismatch: expected '${config.credentialType}' but got '${credential.type}'`);
|
|
27
|
+
}
|
|
28
|
+
// Launch browser and perform authentication
|
|
29
|
+
const browser = await chromium.launch({
|
|
30
|
+
headless: process.env.HEADLESS !== "false",
|
|
31
|
+
args: ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
32
|
+
});
|
|
33
|
+
try {
|
|
34
|
+
await performAuthenticationFlow(browser, config, targetUrl, credential, storagePath);
|
|
35
|
+
log(`[MsAuth] ##[section]Authentication completed successfully for '${config.email}'`);
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await browser.close();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Perform the actual authentication flow in the browser
|
|
43
|
+
*/
|
|
44
|
+
async function performAuthenticationFlow(browser, config, targetUrl, credential, storagePath) {
|
|
45
|
+
const context = await browser.newContext({
|
|
46
|
+
storageState: undefined, // Start with fresh state
|
|
47
|
+
});
|
|
48
|
+
const page = await context.newPage();
|
|
49
|
+
try {
|
|
50
|
+
// Navigate to target URL which will redirect to login
|
|
51
|
+
log(`[MsAuth] Navigating to ${targetUrl}`);
|
|
52
|
+
await page.goto(targetUrl, { waitUntil: "domcontentloaded" });
|
|
53
|
+
// Verify we're on the Entra login page
|
|
54
|
+
const loginEndpoint = config.loginEndpoint || DEFAULT_LOGIN_ENDPOINT;
|
|
55
|
+
const loginUrlPattern = new RegExp(`https:\\/\\/${loginEndpoint.replace(/\./g, "\\.")}\\\/`);
|
|
56
|
+
await expect(page, "Expected Entra sign-in page").toHaveURL(loginUrlPattern, { timeout: 30000 });
|
|
57
|
+
const actualEndpoint = new URL(page.url()).hostname;
|
|
58
|
+
log(`[MsAuth] On Entra login page: ${actualEndpoint}`);
|
|
59
|
+
// Enter email address
|
|
60
|
+
log(`[MsAuth] Entering email: ${config.email}`);
|
|
61
|
+
await page.getByRole("textbox", { name: "email" }).fill(config.email);
|
|
62
|
+
await page.getByRole("button", { name: "next" }).click();
|
|
63
|
+
// Handle authentication based on credential type
|
|
64
|
+
if (credential.type === "certificate") {
|
|
65
|
+
await handleCertificateAuth(page, credential.value, actualEndpoint, config.email);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
await handlePasswordAuth(page, credential.value, config.email);
|
|
69
|
+
}
|
|
70
|
+
// Handle "Stay signed in?" prompt
|
|
71
|
+
await handleStaySignedIn(page);
|
|
72
|
+
// Wait for redirect to target URL
|
|
73
|
+
log(`[MsAuth] Waiting for redirect to target URL`);
|
|
74
|
+
await page.waitForURL(targetUrl, { timeout: 30000 });
|
|
75
|
+
// Give it a bit more time for cookies to settle
|
|
76
|
+
await page.waitForTimeout(2000);
|
|
77
|
+
// Save storage state
|
|
78
|
+
await ensureDirExists(getStorageStatePath(config.email).replace(/[^/\\\\]+$/, ""));
|
|
79
|
+
await context.storageState({ path: storagePath });
|
|
80
|
+
log(`[MsAuth] Saved storage state to ${storagePath}`);
|
|
81
|
+
// Take success screenshot
|
|
82
|
+
const screenshotPath = getAuthScreenshotPath(config.email, "success");
|
|
83
|
+
await ensureDirExists(screenshotPath.replace(/[^/\\\\]+$/, ""));
|
|
84
|
+
await page
|
|
85
|
+
.screenshot({ path: screenshotPath, fullPage: true })
|
|
86
|
+
.catch(() => { });
|
|
87
|
+
log(`[MsAuth] Screenshot saved to ${screenshotPath}`);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
// Take failure screenshot
|
|
91
|
+
const screenshotPath = getAuthScreenshotPath(config.email, "failed");
|
|
92
|
+
await ensureDirExists(screenshotPath.replace(/[^/\\\\]+$/, ""));
|
|
93
|
+
await page
|
|
94
|
+
.screenshot({ path: screenshotPath, fullPage: true })
|
|
95
|
+
.catch(() => { });
|
|
96
|
+
log(`[MsAuth] ##[error]Authentication failed. Screenshot: ${screenshotPath}`);
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
await context.close();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Handle certificate-based authentication
|
|
105
|
+
*/
|
|
106
|
+
async function handleCertificateAuth(page, certificate, endpoint, email) {
|
|
107
|
+
log(`[MsAuth] Using certificate authentication`);
|
|
108
|
+
// Log certificate fingerprint for debugging
|
|
109
|
+
const fingerprint = createHash("sha256")
|
|
110
|
+
.update(new Uint8Array(certificate))
|
|
111
|
+
.digest("hex");
|
|
112
|
+
log(`[MsAuth] Certificate fingerprint: ${fingerprint}`);
|
|
113
|
+
log(`[MsAuth] Certificate size: ${certificate.byteLength} bytes`);
|
|
114
|
+
// Add certificate authentication route
|
|
115
|
+
await addCertAuthRoute(page, { pfx: certificate, authEndpoint: endpoint });
|
|
116
|
+
// Handle account type selection if needed
|
|
117
|
+
const workOrSchoolButton = page.getByRole("button", {
|
|
118
|
+
name: "Work or school account",
|
|
119
|
+
});
|
|
120
|
+
if (await workOrSchoolButton.isVisible({ timeout: 5000 }).catch(() => false)) {
|
|
121
|
+
log(`[MsAuth] Selecting 'Work or school account'`);
|
|
122
|
+
await workOrSchoolButton.click();
|
|
123
|
+
}
|
|
124
|
+
// Handle certificate selection if needed
|
|
125
|
+
const certButton = page
|
|
126
|
+
.getByRole("link", { name: "certificate" })
|
|
127
|
+
.or(page.getByRole("button", { name: "certificate" }));
|
|
128
|
+
if (await certButton.isVisible({ timeout: 5000 }).catch(() => false)) {
|
|
129
|
+
log(`[MsAuth] Selecting certificate authentication`);
|
|
130
|
+
await certButton.click();
|
|
131
|
+
}
|
|
132
|
+
// Wait for certificate authentication to complete
|
|
133
|
+
log(`[MsAuth] Waiting for certificate authentication response`);
|
|
134
|
+
await waitForCertAuthResponse(page, endpoint);
|
|
135
|
+
// Check for certificate validation errors
|
|
136
|
+
const certFailure = page.getByRole("heading", {
|
|
137
|
+
name: /Certificate validation failed|We couldn't sign you in with a certificate/i,
|
|
138
|
+
});
|
|
139
|
+
if (await certFailure.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
140
|
+
const failureText = await certFailure.textContent();
|
|
141
|
+
log(`[MsAuth] ##[error]Certificate authentication failed: ${failureText}`);
|
|
142
|
+
// Try to get error details
|
|
143
|
+
const moreDetails = page.getByRole("button", { name: "More details" });
|
|
144
|
+
if (await moreDetails.isVisible({ timeout: 1000 }).catch(() => false)) {
|
|
145
|
+
await moreDetails.click();
|
|
146
|
+
await page
|
|
147
|
+
.context()
|
|
148
|
+
.grantPermissions(["clipboard-read"])
|
|
149
|
+
.catch(() => { });
|
|
150
|
+
const copyButton = page.getByRole("button", { name: "Copy" });
|
|
151
|
+
if (await copyButton.isVisible({ timeout: 1000 }).catch(() => false)) {
|
|
152
|
+
await copyButton.click();
|
|
153
|
+
const errorDetails = await page
|
|
154
|
+
.evaluate("navigator.clipboard.readText()")
|
|
155
|
+
.catch(() => "");
|
|
156
|
+
if (errorDetails) {
|
|
157
|
+
log(`[MsAuth] ##[error]Error details: ${errorDetails}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
throw new Error(`Certificate authentication failed for ${email}. Check Entra sign-in logs.`);
|
|
162
|
+
}
|
|
163
|
+
log(`[MsAuth] Certificate authentication successful`);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Handle password-based authentication
|
|
167
|
+
*/
|
|
168
|
+
async function handlePasswordAuth(page, password, email) {
|
|
169
|
+
log(`[MsAuth] Using password authentication`);
|
|
170
|
+
// Wait for password field
|
|
171
|
+
await page
|
|
172
|
+
.getByRole("textbox", { name: "password" })
|
|
173
|
+
.waitFor({ timeout: 10000 });
|
|
174
|
+
// Enter password
|
|
175
|
+
log(`[MsAuth] Entering password`);
|
|
176
|
+
await page.getByRole("textbox", { name: "password" }).fill(password);
|
|
177
|
+
await page
|
|
178
|
+
.getByRole("button", { name: "submit" })
|
|
179
|
+
.or(page.locator('input[type="submit"]'))
|
|
180
|
+
.click();
|
|
181
|
+
// Check for password errors
|
|
182
|
+
await page.waitForTimeout(1000);
|
|
183
|
+
const passwordError = page.locator("#passwordError, .has-error");
|
|
184
|
+
if (await passwordError.isVisible().catch(() => false)) {
|
|
185
|
+
const errorText = await passwordError.textContent().catch(() => "");
|
|
186
|
+
log(`[MsAuth] ##[error]Password authentication failed: ${errorText}`);
|
|
187
|
+
throw new Error(`Password authentication failed for ${email}. Please verify the password is correct.`);
|
|
188
|
+
}
|
|
189
|
+
log(`[MsAuth] Password authentication successful`);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Handle "Stay signed in?" prompt
|
|
193
|
+
*/
|
|
194
|
+
async function handleStaySignedIn(page) {
|
|
195
|
+
const staySignedIn = page.getByRole("heading", { name: "Stay signed in?" });
|
|
196
|
+
if (await staySignedIn.isVisible({ timeout: 5000 }).catch(() => false)) {
|
|
197
|
+
log(`[MsAuth] Handling 'Stay signed in?' prompt`);
|
|
198
|
+
await page.getByRole("button", { name: "Yes" }).click();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Load existing storage state into a browser context
|
|
203
|
+
*/
|
|
204
|
+
export async function loadStorageState(config) {
|
|
205
|
+
const storagePath = getStorageStatePath(config.email);
|
|
206
|
+
const isValid = await isStorageStateValid(storagePath, config.storageStateExpiration);
|
|
207
|
+
if (!isValid) {
|
|
208
|
+
throw new Error(`Storage state for '${config.email}' does not exist or has expired. ` +
|
|
209
|
+
`Please run authentication first.`);
|
|
210
|
+
}
|
|
211
|
+
return storagePath;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=authenticate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../src/authenticate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Page } from "@playwright/test";
|
|
2
|
+
export interface CertAuthOptions {
|
|
3
|
+
/** The certificate for the user as a pfx buffer or base64 string */
|
|
4
|
+
pfx: Buffer | string;
|
|
5
|
+
/** Optional passphrase for the certificate */
|
|
6
|
+
passphrase?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The authentication endpoint e.g. login.microsoftonline.com or login.microsoftonline.us
|
|
9
|
+
* @default 'login.microsoftonline.com'
|
|
10
|
+
*/
|
|
11
|
+
authEndpoint?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Add certificate authentication route handler to the page
|
|
15
|
+
*/
|
|
16
|
+
export declare function addCertAuthRoute(page: Page, options: CertAuthOptions): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Wait for certificate authentication response
|
|
19
|
+
*/
|
|
20
|
+
export declare function waitForCertAuthResponse(page: Page, endpoint?: string): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=certAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certAuth.d.ts","sourceRoot":"","sources":["../src/certAuth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAM7D,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAErB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CASf;AA0ED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,IAAI,EACV,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAIf"}
|
package/lib/certAuth.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Agent, request as https } from "node:https";
|
|
2
|
+
import { log } from "./utils";
|
|
3
|
+
const DEFAULT_AUTH_ENDPOINT = "login.microsoftonline.com";
|
|
4
|
+
/**
|
|
5
|
+
* Add certificate authentication route handler to the page
|
|
6
|
+
*/
|
|
7
|
+
export async function addCertAuthRoute(page, options) {
|
|
8
|
+
const endpoint = options.authEndpoint || DEFAULT_AUTH_ENDPOINT;
|
|
9
|
+
const uri = getCertAuthGlob(endpoint);
|
|
10
|
+
const { pfx, passphrase } = options;
|
|
11
|
+
log(`[CertAuth] Adding certificate authentication route for endpoint: ${endpoint}`);
|
|
12
|
+
await page.route(uri, certAuthHandler({ pfx, passphrase }));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create handler for certificate authentication requests
|
|
16
|
+
* See https://learn.microsoft.com/en-us/entra/identity/authentication/concept-certificate-based-authentication-technical-deep-dive
|
|
17
|
+
*/
|
|
18
|
+
function certAuthHandler(options) {
|
|
19
|
+
return async (route, request) => {
|
|
20
|
+
try {
|
|
21
|
+
log(`[CertAuth] Handling certificate authentication request to ${request.url()}`);
|
|
22
|
+
const resp = await doCertAuthPost(request, options);
|
|
23
|
+
await route.fulfill(resp);
|
|
24
|
+
log(`[CertAuth] Certificate authentication request completed with status ${resp.status}`);
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
28
|
+
log(`[CertAuth] ##[error]Failed to send cert auth request: ${message}`);
|
|
29
|
+
await route.abort("failed");
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Perform certificate authentication POST request
|
|
35
|
+
*/
|
|
36
|
+
function doCertAuthPost(request, options) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const agent = new Agent(options);
|
|
39
|
+
const req = https(request.url(), {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: request.headers(),
|
|
42
|
+
agent,
|
|
43
|
+
});
|
|
44
|
+
req.on("error", (err) => {
|
|
45
|
+
reject(err);
|
|
46
|
+
});
|
|
47
|
+
req.on("response", (res) => {
|
|
48
|
+
if (res.statusCode >= 400) {
|
|
49
|
+
reject(new Error(`Cert auth request failed: ${res.statusCode} ${res.statusMessage}`));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
let data = "";
|
|
53
|
+
res.on("data", (chunk) => {
|
|
54
|
+
data += Buffer.from(chunk).toString("utf-8");
|
|
55
|
+
});
|
|
56
|
+
res.on("end", () => {
|
|
57
|
+
resolve({
|
|
58
|
+
status: res.statusCode,
|
|
59
|
+
headers: res.headers,
|
|
60
|
+
body: data,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
req.write(request.postData());
|
|
65
|
+
req.end();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Wait for certificate authentication response
|
|
70
|
+
*/
|
|
71
|
+
export function waitForCertAuthResponse(page, endpoint) {
|
|
72
|
+
const authEndpoint = endpoint || DEFAULT_AUTH_ENDPOINT;
|
|
73
|
+
const glob = getCertAuthGlob(authEndpoint);
|
|
74
|
+
return page.waitForResponse(glob).then(() => { });
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get glob pattern for certificate authentication endpoint
|
|
78
|
+
*/
|
|
79
|
+
function getCertAuthGlob(endpoint) {
|
|
80
|
+
return `https://*certauth.${endpoint}/**`;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=certAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certAuth.js","sourceRoot":"","sources":["../src/certAuth.ts"],"names":[],"mappings":"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"}
|
package/lib/cli.d.ts
ADDED
package/lib/cli.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { authenticate } from "./authenticate";
|
|
4
|
+
import { loadConfigFromEnv, validateConfig } from "./config";
|
|
5
|
+
import { EnvVars } from "./types";
|
|
6
|
+
import { log } from "./utils";
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name("ms-auth")
|
|
10
|
+
.description("Microsoft Entra authentication CLI for Playwright")
|
|
11
|
+
.version("1.0.0");
|
|
12
|
+
program
|
|
13
|
+
.command("login")
|
|
14
|
+
.description("Perform Microsoft Entra authentication and save storage state")
|
|
15
|
+
.requiredOption("-u, --url <url>", "Target URL to authenticate against")
|
|
16
|
+
.option("-e, --email <email>", `User email (or set ${EnvVars.EMAIL})`)
|
|
17
|
+
.option("-t, --credential-type <type>", `Credential type: password|certificate (or set ${EnvVars.CREDENTIAL_TYPE})`, "password")
|
|
18
|
+
.option("-p, --credential-provider <provider>", `Credential provider: azure-keyvault|local-file|environment|github-secrets (or set ${EnvVars.CREDENTIAL_PROVIDER})`, "azure-keyvault")
|
|
19
|
+
.option("--keyvault-endpoint <endpoint>", `Azure KeyVault endpoint (or set ${EnvVars.KEYVAULT_ENDPOINT})`)
|
|
20
|
+
.option("--keyvault-secret <secret>", `Azure KeyVault secret name (or set ${EnvVars.KEYVAULT_SECRET_NAME})`)
|
|
21
|
+
.option("--local-file <path>", `Local file path for credential (or set ${EnvVars.LOCAL_FILE_PATH})`)
|
|
22
|
+
.option("--env-variable <name>", `Environment variable name (or set ${EnvVars.ENV_VARIABLE_NAME})`)
|
|
23
|
+
.option("--github-repo <repo>", `GitHub repository owner/repo (or set ${EnvVars.GITHUB_REPOSITORY})`)
|
|
24
|
+
.option("--github-secret <secret>", `GitHub secret name (or set ${EnvVars.GITHUB_SECRET_NAME})`)
|
|
25
|
+
.option("--output-dir <dir>", `Output directory for storage state (or set ${EnvVars.OUTPUT_DIR})`)
|
|
26
|
+
.option("--debug", "Enable debug logging")
|
|
27
|
+
.action(async (options) => {
|
|
28
|
+
try {
|
|
29
|
+
// Enable debug logging if requested
|
|
30
|
+
if (options.debug) {
|
|
31
|
+
process.env[EnvVars.SYSTEM_DEBUG] = "true";
|
|
32
|
+
}
|
|
33
|
+
log("[CLI] Starting authentication");
|
|
34
|
+
log(`[CLI] Target URL: ${options.url}`);
|
|
35
|
+
// Set environment variables from CLI options
|
|
36
|
+
if (options.email)
|
|
37
|
+
process.env[EnvVars.EMAIL] = options.email;
|
|
38
|
+
if (options.credentialType)
|
|
39
|
+
process.env[EnvVars.CREDENTIAL_TYPE] = options.credentialType;
|
|
40
|
+
if (options.credentialProvider)
|
|
41
|
+
process.env[EnvVars.CREDENTIAL_PROVIDER] = options.credentialProvider;
|
|
42
|
+
if (options.keyvaultEndpoint)
|
|
43
|
+
process.env[EnvVars.KEYVAULT_ENDPOINT] = options.keyvaultEndpoint;
|
|
44
|
+
if (options.keyvaultSecret)
|
|
45
|
+
process.env[EnvVars.KEYVAULT_SECRET_NAME] = options.keyvaultSecret;
|
|
46
|
+
if (options.localFile)
|
|
47
|
+
process.env[EnvVars.LOCAL_FILE_PATH] = options.localFile;
|
|
48
|
+
if (options.envVariable)
|
|
49
|
+
process.env[EnvVars.ENV_VARIABLE_NAME] = options.envVariable;
|
|
50
|
+
if (options.githubRepo)
|
|
51
|
+
process.env[EnvVars.GITHUB_REPOSITORY] = options.githubRepo;
|
|
52
|
+
if (options.githubSecret)
|
|
53
|
+
process.env[EnvVars.GITHUB_SECRET_NAME] = options.githubSecret;
|
|
54
|
+
if (options.outputDir)
|
|
55
|
+
process.env[EnvVars.OUTPUT_DIR] = options.outputDir;
|
|
56
|
+
// Load configuration from environment
|
|
57
|
+
const config = loadConfigFromEnv();
|
|
58
|
+
validateConfig(config);
|
|
59
|
+
log(`[CLI] Email: ${config.email}`);
|
|
60
|
+
log(`[CLI] Credential type: ${config.credentialType}`);
|
|
61
|
+
log(`[CLI] Credential provider: ${config.credentialProvider}`);
|
|
62
|
+
// Perform authentication
|
|
63
|
+
await authenticate(config, options.url);
|
|
64
|
+
console.log("✅ Authentication successful!");
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
69
|
+
console.error("❌ Authentication failed:", message);
|
|
70
|
+
if (options.debug && error instanceof Error && error.stack) {
|
|
71
|
+
console.error(error.stack);
|
|
72
|
+
}
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
program
|
|
77
|
+
.command("env-help")
|
|
78
|
+
.description("Show all supported environment variables")
|
|
79
|
+
.action(() => {
|
|
80
|
+
console.log("Supported Environment Variables:\n");
|
|
81
|
+
console.log("Core Configuration:");
|
|
82
|
+
console.log(` ${EnvVars.EMAIL} - User email address`);
|
|
83
|
+
console.log(` ${EnvVars.CREDENTIAL_TYPE} - Credential type (password|certificate)`);
|
|
84
|
+
console.log(` ${EnvVars.CREDENTIAL_PROVIDER} - Provider type (azure-keyvault|local-file|environment|github-secrets)`);
|
|
85
|
+
console.log(` ${EnvVars.OUTPUT_DIR} - Output directory for storage state`);
|
|
86
|
+
console.log(` ${EnvVars.LOGIN_ENDPOINT} - Entra login endpoint (default: login.microsoftonline.com)`);
|
|
87
|
+
console.log(` ${EnvVars.STORAGE_STATE_EXPIRATION} - Hours until storage state expires (default: 24)`);
|
|
88
|
+
console.log();
|
|
89
|
+
console.log("Azure KeyVault Provider:");
|
|
90
|
+
console.log(` ${EnvVars.KEYVAULT_ENDPOINT} - KeyVault endpoint URL`);
|
|
91
|
+
console.log(` ${EnvVars.KEYVAULT_SECRET_NAME}- Secret name in KeyVault`);
|
|
92
|
+
console.log();
|
|
93
|
+
console.log("Local File Provider:");
|
|
94
|
+
console.log(` ${EnvVars.LOCAL_FILE_PATH} - Path to credential file`);
|
|
95
|
+
console.log(` ${EnvVars.CERTIFICATE_PASSWORD}- Password for encrypted certificate`);
|
|
96
|
+
console.log();
|
|
97
|
+
console.log("Environment Variable Provider:");
|
|
98
|
+
console.log(` ${EnvVars.ENV_VARIABLE_NAME} - Name of environment variable containing credential`);
|
|
99
|
+
console.log();
|
|
100
|
+
console.log("GitHub Secrets Provider:");
|
|
101
|
+
console.log(` ${EnvVars.GITHUB_REPOSITORY} - GitHub repository (owner/repo)`);
|
|
102
|
+
console.log(` ${EnvVars.GITHUB_SECRET_NAME} - GitHub secret name`);
|
|
103
|
+
console.log(` ${EnvVars.GITHUB_TOKEN} - GitHub token (optional)`);
|
|
104
|
+
console.log();
|
|
105
|
+
console.log("Debug:");
|
|
106
|
+
console.log(` ${EnvVars.SYSTEM_DEBUG} - Enable debug logging (true|false)`);
|
|
107
|
+
});
|
|
108
|
+
program.parse();
|
|
109
|
+
//# sourceMappingURL=cli.js.map
|
package/lib/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MsAuthConfig } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Load configuration from environment variables
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadConfigFromEnv(): MsAuthConfig;
|
|
6
|
+
/**
|
|
7
|
+
* Validate configuration
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateConfig(config: MsAuthConfig): void;
|
|
10
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAQb,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,YAAY,CAwBhD;AA+FD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAsBzD"}
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { EnvVars } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Load configuration from environment variables
|
|
4
|
+
*/
|
|
5
|
+
export function loadConfigFromEnv() {
|
|
6
|
+
const email = process.env[EnvVars.EMAIL];
|
|
7
|
+
if (!email) {
|
|
8
|
+
throw new Error(`${EnvVars.EMAIL} environment variable is required`);
|
|
9
|
+
}
|
|
10
|
+
const credentialType = (process.env[EnvVars.CREDENTIAL_TYPE] ||
|
|
11
|
+
"password");
|
|
12
|
+
const credentialProvider = (process.env[EnvVars.CREDENTIAL_PROVIDER] ||
|
|
13
|
+
"azure-keyvault");
|
|
14
|
+
const providerConfig = loadProviderConfigFromEnv(credentialProvider);
|
|
15
|
+
return {
|
|
16
|
+
email,
|
|
17
|
+
credentialType,
|
|
18
|
+
credentialProvider,
|
|
19
|
+
providerConfig,
|
|
20
|
+
outputDir: process.env[EnvVars.OUTPUT_DIR],
|
|
21
|
+
storageStateExpiration: process.env[EnvVars.STORAGE_STATE_EXPIRATION]
|
|
22
|
+
? parseInt(process.env[EnvVars.STORAGE_STATE_EXPIRATION])
|
|
23
|
+
: 24,
|
|
24
|
+
loginEndpoint: process.env[EnvVars.LOGIN_ENDPOINT],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Load provider-specific configuration from environment variables
|
|
29
|
+
*/
|
|
30
|
+
function loadProviderConfigFromEnv(providerType) {
|
|
31
|
+
switch (providerType) {
|
|
32
|
+
case "azure-keyvault":
|
|
33
|
+
return loadAzureKeyVaultConfigFromEnv();
|
|
34
|
+
case "local-file":
|
|
35
|
+
return loadLocalFileConfigFromEnv();
|
|
36
|
+
case "environment":
|
|
37
|
+
return loadEnvironmentConfigFromEnv();
|
|
38
|
+
case "github-secrets":
|
|
39
|
+
return loadGitHubSecretsConfigFromEnv();
|
|
40
|
+
default:
|
|
41
|
+
throw new Error(`Unsupported credential provider: ${providerType}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function loadAzureKeyVaultConfigFromEnv() {
|
|
45
|
+
const keyVaultEndpoint = process.env[EnvVars.KEYVAULT_ENDPOINT];
|
|
46
|
+
const secretName = process.env[EnvVars.KEYVAULT_SECRET_NAME];
|
|
47
|
+
if (!keyVaultEndpoint) {
|
|
48
|
+
throw new Error(`${EnvVars.KEYVAULT_ENDPOINT} environment variable is required for Azure KeyVault provider`);
|
|
49
|
+
}
|
|
50
|
+
if (!secretName) {
|
|
51
|
+
throw new Error(`${EnvVars.KEYVAULT_SECRET_NAME} environment variable is required for Azure KeyVault provider`);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
keyVaultEndpoint,
|
|
55
|
+
secretName,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function loadLocalFileConfigFromEnv() {
|
|
59
|
+
const filePath = process.env[EnvVars.LOCAL_FILE_PATH];
|
|
60
|
+
if (!filePath) {
|
|
61
|
+
throw new Error(`${EnvVars.LOCAL_FILE_PATH} environment variable is required for local file provider`);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
filePath,
|
|
65
|
+
certificatePassword: process.env[EnvVars.CERTIFICATE_PASSWORD],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function loadEnvironmentConfigFromEnv() {
|
|
69
|
+
const variableName = process.env[EnvVars.ENV_VARIABLE_NAME];
|
|
70
|
+
if (!variableName) {
|
|
71
|
+
throw new Error(`${EnvVars.ENV_VARIABLE_NAME} environment variable is required for environment provider`);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
variableName,
|
|
75
|
+
passwordVariableName: process.env[EnvVars.CERTIFICATE_PASSWORD],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function loadGitHubSecretsConfigFromEnv() {
|
|
79
|
+
const repository = process.env[EnvVars.GITHUB_REPOSITORY];
|
|
80
|
+
const secretName = process.env[EnvVars.GITHUB_SECRET_NAME];
|
|
81
|
+
if (!repository) {
|
|
82
|
+
throw new Error(`${EnvVars.GITHUB_REPOSITORY} environment variable is required for GitHub Secrets provider`);
|
|
83
|
+
}
|
|
84
|
+
if (!secretName) {
|
|
85
|
+
throw new Error(`${EnvVars.GITHUB_SECRET_NAME} environment variable is required for GitHub Secrets provider`);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
repository,
|
|
89
|
+
secretName,
|
|
90
|
+
token: process.env[EnvVars.GITHUB_TOKEN],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Validate configuration
|
|
95
|
+
*/
|
|
96
|
+
export function validateConfig(config) {
|
|
97
|
+
if (!config.email) {
|
|
98
|
+
throw new Error("Email is required");
|
|
99
|
+
}
|
|
100
|
+
if (!config.credentialType) {
|
|
101
|
+
throw new Error("Credential type is required");
|
|
102
|
+
}
|
|
103
|
+
if (!config.credentialProvider) {
|
|
104
|
+
throw new Error("Credential provider is required");
|
|
105
|
+
}
|
|
106
|
+
if (!config.providerConfig) {
|
|
107
|
+
throw new Error("Provider configuration is required");
|
|
108
|
+
}
|
|
109
|
+
// Validate email format
|
|
110
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
111
|
+
if (!emailRegex.test(config.email)) {
|
|
112
|
+
throw new Error(`Invalid email format: ${config.email}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @paeng/playwright-ms-auth
|
|
3
|
+
*
|
|
4
|
+
* Flexible authentication framework for Playwright tests supporting
|
|
5
|
+
* password and certificate authentication with multiple credential providers.
|
|
6
|
+
*/
|
|
7
|
+
export * from "./types";
|
|
8
|
+
export * from "./config";
|
|
9
|
+
export * from "./authenticate";
|
|
10
|
+
export * from "./certAuth";
|
|
11
|
+
export * from "./utils";
|
|
12
|
+
export * from "./providers";
|
|
13
|
+
export { authenticate, loadStorageState } from "./authenticate";
|
|
14
|
+
export { loadConfigFromEnv, validateConfig } from "./config";
|
|
15
|
+
export { CredentialProviderFactory } from "./providers";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAG5B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC"}
|