feat(client-certificates): allow passing certificates from memory (#32210)
This commit is contained in:
parent
74f5ce5489
commit
010778f6c5
|
|
@ -531,15 +531,18 @@ Does not enforce fixed viewport, allows resizing window in the headed mode.
|
||||||
- `clientCertificates` <[Array]<[Object]>>
|
- `clientCertificates` <[Array]<[Object]>>
|
||||||
- `origin` <[string]> Exact origin that the certificate is valid for. Origin includes `https` protocol, a hostname and optionally a port.
|
- `origin` <[string]> Exact origin that the certificate is valid for. Origin includes `https` protocol, a hostname and optionally a port.
|
||||||
- `certPath` ?<[path]> Path to the file with the certificate in PEM format.
|
- `certPath` ?<[path]> Path to the file with the certificate in PEM format.
|
||||||
|
- `cert` ?<[Buffer]> Direct value of the certificate in PEM format.
|
||||||
- `keyPath` ?<[path]> Path to the file with the private key in PEM format.
|
- `keyPath` ?<[path]> Path to the file with the private key in PEM format.
|
||||||
|
- `key` ?<[Buffer]> Direct value of the private key in PEM format.
|
||||||
- `pfxPath` ?<[path]> Path to the PFX or PKCS12 encoded private key and certificate chain.
|
- `pfxPath` ?<[path]> Path to the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
|
- `pfx` ?<[Buffer]> Direct value of the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
- `passphrase` ?<[string]> Passphrase for the private key (PEM or PFX).
|
- `passphrase` ?<[string]> Passphrase for the private key (PEM or PFX).
|
||||||
|
|
||||||
TLS Client Authentication allows the server to request a client certificate and verify it.
|
TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||||
|
|
||||||
**Details**
|
**Details**
|
||||||
|
|
||||||
An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the certficiate is encrypted. The `origin` property should be provided with an exact match to the request origin that the certificate is valid for.
|
An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`, a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally, `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
Using Client Certificates in combination with Proxy Servers is not supported.
|
Using Client Certificates in combination with Proxy Servers is not supported.
|
||||||
|
|
|
||||||
|
|
@ -552,13 +552,19 @@ function toAcceptDownloadsProtocol(acceptDownloads?: boolean) {
|
||||||
export async function toClientCertificatesProtocol(certs?: BrowserContextOptions['clientCertificates']): Promise<channels.PlaywrightNewRequestParams['clientCertificates']> {
|
export async function toClientCertificatesProtocol(certs?: BrowserContextOptions['clientCertificates']): Promise<channels.PlaywrightNewRequestParams['clientCertificates']> {
|
||||||
if (!certs)
|
if (!certs)
|
||||||
return undefined;
|
return undefined;
|
||||||
return await Promise.all(certs.map(async cert => {
|
|
||||||
return {
|
const bufferizeContent = async (value?: Buffer, path?: string): Promise<Buffer | undefined> => {
|
||||||
origin: cert.origin,
|
if (value)
|
||||||
cert: cert.certPath ? await fs.promises.readFile(cert.certPath) : undefined,
|
return value;
|
||||||
key: cert.keyPath ? await fs.promises.readFile(cert.keyPath) : undefined,
|
if (path)
|
||||||
pfx: cert.pfxPath ? await fs.promises.readFile(cert.pfxPath) : undefined,
|
return await fs.promises.readFile(path);
|
||||||
passphrase: cert.passphrase,
|
};
|
||||||
};
|
|
||||||
}));
|
return await Promise.all(certs.map(async cert => ({
|
||||||
|
origin: cert.origin,
|
||||||
|
cert: await bufferizeContent(cert.cert, cert.certPath),
|
||||||
|
key: await bufferizeContent(cert.key, cert.keyPath),
|
||||||
|
pfx: await bufferizeContent(cert.pfx, cert.pfxPath),
|
||||||
|
passphrase: cert.passphrase,
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,11 @@ export const kLifecycleEvents: Set<LifecycleEvent> = new Set(['load', 'domconten
|
||||||
|
|
||||||
export type ClientCertificate = {
|
export type ClientCertificate = {
|
||||||
origin: string;
|
origin: string;
|
||||||
|
cert?: Buffer;
|
||||||
certPath?: string;
|
certPath?: string;
|
||||||
|
key?: Buffer;
|
||||||
keyPath?: string;
|
keyPath?: string;
|
||||||
|
pfx?: Buffer;
|
||||||
pfxPath?: string;
|
pfxPath?: string;
|
||||||
passphrase?: string;
|
passphrase?: string;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
92
packages/playwright-core/types/types.d.ts
vendored
92
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -9138,10 +9138,10 @@ export interface Browser {
|
||||||
*
|
*
|
||||||
* **Details**
|
* **Details**
|
||||||
*
|
*
|
||||||
* An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a
|
* An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`,
|
||||||
* single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the
|
* a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally,
|
||||||
* certficiate is encrypted. The `origin` property should be provided with an exact match to the request origin that
|
* `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
|
||||||
* the certificate is valid for.
|
* with an exact match to the request origin that the certificate is valid for.
|
||||||
*
|
*
|
||||||
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
||||||
*
|
*
|
||||||
|
|
@ -9159,16 +9159,31 @@ export interface Browser {
|
||||||
*/
|
*/
|
||||||
certPath?: string;
|
certPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the certificate in PEM format.
|
||||||
|
*/
|
||||||
|
cert?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the file with the private key in PEM format.
|
* Path to the file with the private key in PEM format.
|
||||||
*/
|
*/
|
||||||
keyPath?: string;
|
keyPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the private key in PEM format.
|
||||||
|
*/
|
||||||
|
key?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
*/
|
*/
|
||||||
pfxPath?: string;
|
pfxPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
|
*/
|
||||||
|
pfx?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passphrase for the private key (PEM or PFX).
|
* Passphrase for the private key (PEM or PFX).
|
||||||
*/
|
*/
|
||||||
|
|
@ -13850,10 +13865,10 @@ export interface BrowserType<Unused = {}> {
|
||||||
*
|
*
|
||||||
* **Details**
|
* **Details**
|
||||||
*
|
*
|
||||||
* An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a
|
* An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`,
|
||||||
* single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the
|
* a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally,
|
||||||
* certficiate is encrypted. The `origin` property should be provided with an exact match to the request origin that
|
* `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
|
||||||
* the certificate is valid for.
|
* with an exact match to the request origin that the certificate is valid for.
|
||||||
*
|
*
|
||||||
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
||||||
*
|
*
|
||||||
|
|
@ -13871,16 +13886,31 @@ export interface BrowserType<Unused = {}> {
|
||||||
*/
|
*/
|
||||||
certPath?: string;
|
certPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the certificate in PEM format.
|
||||||
|
*/
|
||||||
|
cert?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the file with the private key in PEM format.
|
* Path to the file with the private key in PEM format.
|
||||||
*/
|
*/
|
||||||
keyPath?: string;
|
keyPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the private key in PEM format.
|
||||||
|
*/
|
||||||
|
key?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
*/
|
*/
|
||||||
pfxPath?: string;
|
pfxPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
|
*/
|
||||||
|
pfx?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passphrase for the private key (PEM or PFX).
|
* Passphrase for the private key (PEM or PFX).
|
||||||
*/
|
*/
|
||||||
|
|
@ -16259,10 +16289,10 @@ export interface APIRequest {
|
||||||
*
|
*
|
||||||
* **Details**
|
* **Details**
|
||||||
*
|
*
|
||||||
* An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a
|
* An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`,
|
||||||
* single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the
|
* a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally,
|
||||||
* certficiate is encrypted. The `origin` property should be provided with an exact match to the request origin that
|
* `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
|
||||||
* the certificate is valid for.
|
* with an exact match to the request origin that the certificate is valid for.
|
||||||
*
|
*
|
||||||
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
||||||
*
|
*
|
||||||
|
|
@ -16280,16 +16310,31 @@ export interface APIRequest {
|
||||||
*/
|
*/
|
||||||
certPath?: string;
|
certPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the certificate in PEM format.
|
||||||
|
*/
|
||||||
|
cert?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the file with the private key in PEM format.
|
* Path to the file with the private key in PEM format.
|
||||||
*/
|
*/
|
||||||
keyPath?: string;
|
keyPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the private key in PEM format.
|
||||||
|
*/
|
||||||
|
key?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
*/
|
*/
|
||||||
pfxPath?: string;
|
pfxPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
|
*/
|
||||||
|
pfx?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passphrase for the private key (PEM or PFX).
|
* Passphrase for the private key (PEM or PFX).
|
||||||
*/
|
*/
|
||||||
|
|
@ -20600,10 +20645,10 @@ export interface BrowserContextOptions {
|
||||||
*
|
*
|
||||||
* **Details**
|
* **Details**
|
||||||
*
|
*
|
||||||
* An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a
|
* An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`,
|
||||||
* single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the
|
* a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally,
|
||||||
* certficiate is encrypted. The `origin` property should be provided with an exact match to the request origin that
|
* `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
|
||||||
* the certificate is valid for.
|
* with an exact match to the request origin that the certificate is valid for.
|
||||||
*
|
*
|
||||||
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
||||||
*
|
*
|
||||||
|
|
@ -20621,16 +20666,31 @@ export interface BrowserContextOptions {
|
||||||
*/
|
*/
|
||||||
certPath?: string;
|
certPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the certificate in PEM format.
|
||||||
|
*/
|
||||||
|
cert?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the file with the private key in PEM format.
|
* Path to the file with the private key in PEM format.
|
||||||
*/
|
*/
|
||||||
keyPath?: string;
|
keyPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the private key in PEM format.
|
||||||
|
*/
|
||||||
|
key?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
*/
|
*/
|
||||||
pfxPath?: string;
|
pfxPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct value of the PFX or PKCS12 encoded private key and certificate chain.
|
||||||
|
*/
|
||||||
|
pfx?: Buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passphrase for the private key (PEM or PFX).
|
* Passphrase for the private key (PEM or PFX).
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
8
packages/playwright/types/test.d.ts
vendored
8
packages/playwright/types/test.d.ts
vendored
|
|
@ -5206,10 +5206,10 @@ export interface PlaywrightTestOptions {
|
||||||
*
|
*
|
||||||
* **Details**
|
* **Details**
|
||||||
*
|
*
|
||||||
* An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a
|
* An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`,
|
||||||
* single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the
|
* a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally,
|
||||||
* certficiate is encrypted. The `origin` property should be provided with an exact match to the request origin that
|
* `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
|
||||||
* the certificate is valid for.
|
* with an exact match to the request origin that the certificate is valid for.
|
||||||
*
|
*
|
||||||
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
* **NOTE** Using Client Certificates in combination with Proxy Servers is not supported.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -303,6 +303,21 @@ test.describe('browser', () => {
|
||||||
await page.close();
|
await page.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should pass with matching certificates when passing as content', async ({ browser, startCCServer, asset, browserName }) => {
|
||||||
|
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
|
||||||
|
const page = await browser.newPage({
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
clientCertificates: [{
|
||||||
|
origin: new URL(serverURL).origin,
|
||||||
|
cert: await fs.promises.readFile(asset('client-certificates/client/trusted/cert.pem')),
|
||||||
|
key: await fs.promises.readFile(asset('client-certificates/client/trusted/key.pem')),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
await page.goto(serverURL);
|
||||||
|
await expect(page.getByTestId('message')).toHaveText('Hello Alice, your certificate was issued by localhost!');
|
||||||
|
await page.close();
|
||||||
|
});
|
||||||
|
|
||||||
test('should not hang on tls errors during TLS 1.2 handshake', async ({ browser, asset, platform, browserName }) => {
|
test('should not hang on tls errors during TLS 1.2 handshake', async ({ browser, asset, platform, browserName }) => {
|
||||||
for (const tlsVersion of ['TLSv1.3', 'TLSv1.2'] as const) {
|
for (const tlsVersion of ['TLSv1.3', 'TLSv1.2'] as const) {
|
||||||
await test.step(`TLS version: ${tlsVersion}`, async () => {
|
await test.step(`TLS version: ${tlsVersion}`, async () => {
|
||||||
|
|
@ -360,6 +375,21 @@ test.describe('browser', () => {
|
||||||
await page.close();
|
await page.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should pass with matching certificates in pfx format when passing as content', async ({ browser, startCCServer, asset, browserName }) => {
|
||||||
|
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
|
||||||
|
const page = await browser.newPage({
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
clientCertificates: [{
|
||||||
|
origin: new URL(serverURL).origin,
|
||||||
|
pfx: await fs.promises.readFile(asset('client-certificates/client/trusted/cert.pfx')),
|
||||||
|
passphrase: 'secure'
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
await page.goto(serverURL);
|
||||||
|
await expect(page.getByTestId('message')).toHaveText('Hello Alice, your certificate was issued by localhost!');
|
||||||
|
await page.close();
|
||||||
|
});
|
||||||
|
|
||||||
test('should fail with matching certificates in legacy pfx format', async ({ browser, startCCServer, asset, browserName }) => {
|
test('should fail with matching certificates in legacy pfx format', async ({ browser, startCCServer, asset, browserName }) => {
|
||||||
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
|
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
|
||||||
await expect(browser.newPage({
|
await expect(browser.newPage({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue