Skip to content

Commit

Permalink
feat(grpc): skip TLS when verification disabled + mTLS capability [IN…
Browse files Browse the repository at this point in the history
…S-4536] (#8235)

* fix cert passing

* feat: mtls for ssl-enabled grpc requests

* add user-friendly tls-related error messages to a modal

---------

Co-authored-by: jackkav <[email protected]>
  • Loading branch information
ryan-willis and jackkav authored Dec 9, 2024
1 parent 10f1486 commit d6a6bcb
Show file tree
Hide file tree
Showing 14 changed files with 386 additions and 28 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ packages/insomnia-smoke-test/traces
dist
.history
*.node
rootCA2.*
27 changes: 27 additions & 0 deletions packages/insomnia-smoke-test/fixtures/certificates/client.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEmzCCAwOgAwIBAgIUYaCYPYGdDPU5uHxEyNgDBFGvkPAwDQYJKoZIhvcNAQEL
BQAwgbUxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTFFMEMGA1UECww8
amFjay5rYXZhbmFnaEBKYWNrcy1NYWNCb29rLVByby0xNi1pbmNoLTIwMTkgKEph
Y2sgS2F2YW5hZ2gpMUwwSgYDVQQDDENta2NlcnQgamFjay5rYXZhbmFnaEBKYWNr
cy1NYWNCb29rLVByby0xNi1pbmNoLTIwMTkgKEphY2sgS2F2YW5hZ2gpMB4XDTI0
MTIwNTIwMTMyM1oXDTM0MTIwMzIwMTMyM1owgZQxCzAJBgNVBAYTAlVTMRMwEQYD
VQQIDApTb21lLVdoZXJlMQ0wCwYDVQQHDARFbHNlMREwDwYDVQQKDAhJbnNvbW5p
YTENMAsGA1UECwwEVGVhbTEWMBQGA1UEAwwNSW5zb21uaWEgVGVhbTEnMCUGCSqG
SIb3DQEJARYYdGVhbS1pbnNvbW5pYUBrb25naHEuY29tMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAkdevG8sMbwflVGtkW8mUHYI5Vdl6g7dlV2XVYW5S
WYRAlof7oEn62k5+9DimykZZwiYz2uNyuZRcNTwFvbnkNoAza3t1oEFnieFDWBXw
Ta7gEh2BF9PTtON3S7+ZXLleSXVs/vbY2dXSChe2kPWKukOA0SZO047wYV+NZc/A
pyURQFLNa2RrrpdCutpmj5vvdhNTTHCCdIaDdVkUcw6+o7G3KGYggH/8ODuSiKpV
sPVdlwqEcEHHYGHpHBRr2CLtZmmjvqL85Qv8iT+mJwaucVM3u6Lh5cPxtTgezUtr
gqEW5waAb6QyFGlhInGHy1wkdA+KQusN5sy/5J1dMYs/YwIDAQABo0IwQDAdBgNV
HQ4EFgQUkWmd2DMJ9mUTHMh9I8L2VnyVYEIwHwYDVR0jBBgwFoAUPFHjYSvgmQ5l
NZBrC4e6lJedguwwDQYJKoZIhvcNAQELBQADggGBAJC2q/HsCBti6eJGsx1Sa8bA
lLg86nVwxk03Xzl/slkamgMrqRAbJxZHv4VtzblwiIQsGNOSMeM9Er6XvpKm7Yll
bh5DLWa6h7Tp7vE+GufE4PK6rJCL3p7PwtlJyrrOmUnvHyiGKW5lG3VVeWaizqj+
1teN//Y13538n0qyyk6t+KSRsEmR3x4shvdC8j7kqvaWe/beRbgb4KUvRkGPV/nN
dVoXiLnarqqwfUo1KWU210vULF/AA//DnMMt3KG1IaL74iDM+BbWbDff+6SRbRtf
y7RT2Tukv42F5b9bLww1EnysF7DKh9kbMj4E+YgP0bHuQFd6pateJWjZPXxAlmEv
eBPwupjW6co1otXoDvuHOtf14nMDjWx6am1Qhfw0ag0jkQ2KB54Lzhi6TJUhwFJr
lTK3t4I0TGpL+OIp9MrDVYaGLMOVyFky7WMAZJ+QHbWaPBZC0wFdY7FZXGBWbY/I
cMCTDebmifkHZSVD8c+KU3rtdUMsG2NtTLi7ZFJolw==
-----END CERTIFICATE-----
18 changes: 18 additions & 0 deletions packages/insomnia-smoke-test/fixtures/certificates/client.csr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIC9DCCAdwCAQAwgZQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTb21lLVdoZXJl
MQ0wCwYDVQQHDARFbHNlMREwDwYDVQQKDAhJbnNvbW5pYTENMAsGA1UECwwEVGVh
bTEWMBQGA1UEAwwNSW5zb21uaWEgVGVhbTEnMCUGCSqGSIb3DQEJARYYdGVhbS1p
bnNvbW5pYUBrb25naHEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAkdevG8sMbwflVGtkW8mUHYI5Vdl6g7dlV2XVYW5SWYRAlof7oEn62k5+9Dim
ykZZwiYz2uNyuZRcNTwFvbnkNoAza3t1oEFnieFDWBXwTa7gEh2BF9PTtON3S7+Z
XLleSXVs/vbY2dXSChe2kPWKukOA0SZO047wYV+NZc/ApyURQFLNa2RrrpdCutpm
j5vvdhNTTHCCdIaDdVkUcw6+o7G3KGYggH/8ODuSiKpVsPVdlwqEcEHHYGHpHBRr
2CLtZmmjvqL85Qv8iT+mJwaucVM3u6Lh5cPxtTgezUtrgqEW5waAb6QyFGlhInGH
y1wkdA+KQusN5sy/5J1dMYs/YwIDAQABoBowGAYJKoZIhvcNAQkCMQsMCUtvbmcs
IEluYzANBgkqhkiG9w0BAQsFAAOCAQEAiXALDfLmzi7qj4K837dZeP961G90a7Nk
m7VeBb8RpphM7hQ/2ZhnRfGU5TOo/QskN0Bddhnc6EYrzpo5iH+upmdz/jCpUaOR
k7i/RhC3NOemxCJJ64KR8bNfYJ1q4C9NEBTRfZns73nIE9wuu0Ue/j5KebnkfWz/
anY4bFJfJNZVdpWDRV0dRlgJBlsIHyDlSZ0v/K+3/gh+K3X5z/jOsF7uwFvyzd+j
3DXhgtJESsdqHMeD17wtUX9UytqHX8H0f0JNiZr/BURDUoH9z4zJxeCBHPBQ7Wd2
lvY04vVHKMlI2C52yNUyYtZsXlRCwK5MO9oBt3j8XAga1VHypPdpHA==
-----END CERTIFICATE REQUEST-----
28 changes: 28 additions & 0 deletions packages/insomnia-smoke-test/fixtures/certificates/client.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCR168bywxvB+VU
a2RbyZQdgjlV2XqDt2VXZdVhblJZhECWh/ugSfraTn70OKbKRlnCJjPa43K5lFw1
PAW9ueQ2gDNre3WgQWeJ4UNYFfBNruASHYEX09O043dLv5lcuV5JdWz+9tjZ1dIK
F7aQ9Yq6Q4DRJk7TjvBhX41lz8CnJRFAUs1rZGuul0K62maPm+92E1NMcIJ0hoN1
WRRzDr6jsbcoZiCAf/w4O5KIqlWw9V2XCoRwQcdgYekcFGvYIu1maaO+ovzlC/yJ
P6YnBq5xUze7ouHlw/G1OB7NS2uCoRbnBoBvpDIUaWEicYfLXCR0D4pC6w3mzL/k
nV0xiz9jAgMBAAECggEACv6pH13GSrD1y4PEtZzAebcH21G0oeBxSrTzik+J9GCu
VwraX+7XDNH7hS4OLCENaQyxpRaEX1Q9du/wknYrEibF4AKXNaUooph+ZLiGr+/E
MByhG+qmwuc3gHKDcJ3/uACa+BLw+mWOjgWhCFQFvBDhuCLJfe6Ab1huRv1YdBR2
QDV2/xY7/w6NgU1QtXMETcJcTh9BMQI3dkfBpyZmDAbED2dSZL8uKw9kkG3useIS
bgE8Bs1gMjAtXqK/OlzZg6fazxeTI+K5uiqnCxSS7cMly2nKGBt6bRThapr5/G+E
AfFJHtogZTj+aU9o+tjhnavRVPZYOK6Tvh4tbJfE4QKBgQDIwqtfvX1ezvSxsTWu
XaCDjzLmzBnpXAaWw6r/98MQrgSEAGUkpswm+XIBVu09umZI6VnGheQEToSIMpgl
MPdx/10ewvCuS9DOaNBSnUNVg399vEB/wWtpwvgMumVdl+jy8MZMw4w2UYv4t0wf
a/KpuZDG7qS8JxeyqFJtQ5LfoQKBgQC5+KkvRsJLP5PSdgXXECAL4rfBp3nSIpEc
7FVEqI7gwIzrijF7efNaBJNmJUhZW4AgXnkYu+y+hwtwTOANSeT+qKcixYJ9rJH0
CwQLOV3k4iI890wBGUZFFkArTZQ2ubE7OpLiWkK1DXPS3GQNTkNwaNVwLFEJETd7
ra1p6bDQgwKBgQCIEoodhk3naNapabc8y/DzuqeBj20wolNE9LJ+c+we7hPZdHsZ
cISHFiOTjNuYLzMM0D0tNarq0F08Ay7kZmARQEhZhT+ko3aPsLMii70LxOkwy9vb
u7mWIbQGzH/QBBq8Lz344cGzP2pj1bkewwfiyge7Dh1R+h0x1qynqllugQKBgQCc
oIz9QD8LWTSKoNQyWWZkHEJfW0oCbRKCpZj7BmuvZvxItE8Qi5klS41JDkVs3N+A
Y5DiAARYQyyjHFvnVUEEKc76Pha0+c7DFzQEsAAgcUQczLq6girorODGl8QogyR9
mctz0Ek2a2oNQYkSm8O4vNJmcyyc0l9ETvYqqaM9OQKBgQCTy+yC7PcCSO3+pSW2
uIFizSh8MK4fSAi/A9/qMQObuD64lLkgKAamBRrwj7kgrMY750F60xrHz6hMnFOY
NcKDzR6KSAcZiqFp/s/RL4ZLIRNl+axiNfymIxzFEl3bolpEvkIkKOmbSaq3ZH2P
6Vq+ac3PcUGaZx3Pcml2o8vX3w==
-----END PRIVATE KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
61A0983D819D0CF539B87C44C8D8030451AF90F0
64 changes: 64 additions & 0 deletions packages/insomnia-smoke-test/fixtures/grpc-mtls.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
_type: export
__export_format: 4
__export_date: 2024-12-05T20:16:41.919Z
__export_source: insomnia.desktop.app:v10.2.0
resources:
- _id: greq_7ef089deea314ab88dd86aa434838efd
parentId: wrk_5dac47ec0e6144c694f21b29740e9267
modified: 1733429659428
created: 1732118004917
url: grpcs://localhost:50052
name: grpcs
description: ""
protoFileId: ""
protoMethodName: /routeguide.RouteGuide/GetFeature
metadata: []
body:
text: |-
{
"lo": {
"latitude": "400000000",
"longitude": "-750000000"
},
"hi": {
"latitude": "420000000",
"longitude": "-730000000"
},
"latitude": "409146138",
"longitude": "-746188906"
}
metaSortKey: -1732118004917
isPrivate: false
reflectionApi:
enabled: false
url: https://buf.build
apiKey: ""
module: buf.build/connectrpc/eliza
_type: grpc_request
- _id: wrk_5dac47ec0e6144c694f21b29740e9267
parentId: null
modified: 1732118001110
created: 1732118001110
name: grpc
description: ""
scope: collection
_type: workspace
- _id: env_d8277fde45580529bdde2cee008f33ba3e3a8873
parentId: wrk_5dac47ec0e6144c694f21b29740e9267
modified: 1732118001112
created: 1732118001112
name: Base Environment
data: {}
dataPropertyOrder: null
color: null
isPrivate: false
metaSortKey: 1732118001112
environmentType: kv
_type: environment
- _id: jar_d8277fde45580529bdde2cee008f33ba3e3a8873
parentId: wrk_5dac47ec0e6144c694f21b29740e9267
modified: 1732118001113
created: 1732118001113
name: Default Jar
cookies: []
_type: cookie_jar
49 changes: 44 additions & 5 deletions packages/insomnia-smoke-test/server/grpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,16 +167,13 @@ const routeChat: HandleCall<any, any> = (call: any) => {
/* For each note sent, respond with all previous notes that correspond to
* the same point */
if (routeNotes.hasOwnProperty(key)) {
// @ts-expect-error typescript
routeNotes[key].forEach(function(note: any) {
call.write(note);
});
} else {
// @ts-expect-error typescript
routeNotes[key] = [];
}
// Then add the new note to the list
// @ts-expect-error typescript
routeNotes[key].push(JSON.parse(JSON.stringify(note)));
});
call.on('end', function() {
Expand All @@ -192,8 +189,7 @@ export const startGRPCServer = (port: number) => {
const server = new grpc.Server();

// Enable reflection
const descriptorSet = '../../packages/insomnia-smoke-test/fixtures/route_guide.bin';
addReflection(server, descriptorSet);
addReflection(server, '../../packages/insomnia-smoke-test/fixtures/route_guide.bin');

// @ts-expect-error generated from proto file
server.addService(routeguide.RouteGuide.service, {
Expand All @@ -218,5 +214,48 @@ export const startGRPCServer = (port: number) => {
resolve();
});
});

const serverWithTLS = new grpc.Server();

// Enable reflection
addReflection(serverWithTLS, '../../packages/insomnia-smoke-test/fixtures/route_guide.bin');

// @ts-expect-error generated from proto file
serverWithTLS.addService(routeguide.RouteGuide.service, {
getFeature: getFeature,
listFeatures: listFeatures,
recordRoute: recordRoute,
routeChat: routeChat,
});
const rootCert = fs.readFileSync(path.join(__dirname, '../fixtures/certificates/rootCA.pem'));
const serverCert = fs.readFileSync(path.join(__dirname, '../fixtures/certificates/localhost.pem'));
const serverKey = fs.readFileSync(path.join(__dirname, '../fixtures/certificates/localhost-key.pem'));
const serverCredentials = grpc.ServerCredentials.createSsl(
rootCert,
[
{
cert_chain: serverCert,
private_key: serverKey,
},
],
true // mTLS enabled, temporarily change to false for local testing if needed
);
serverWithTLS.bindAsync('localhost:50052', serverCredentials, error => {
if (error) {
console.error(error);
return reject(error);
}

const dbPath = '../../packages/insomnia/src/network/grpc/__fixtures__/library/route_guide_db.json';
fs.readFile(path.resolve(dbPath), (err, data) => {
if (err) {
throw err;
}
featureList = JSON.parse(data.toString());
console.log('Listening at grpcs://localhost:50052 for route_guide.proto');
serverWithTLS.start();
resolve();
});
});
});
};
62 changes: 62 additions & 0 deletions packages/insomnia-smoke-test/tests/smoke/grpc-mtls.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import path from 'node:path';

import { expect } from '@playwright/test';

import { getFixturePath, loadFixture } from '../../playwright/paths';
import { test } from '../../playwright/test';

test('can send gRPC requests using mTLS requests (with reflection)', async ({ app, page }) => {
test.slow(process.platform === 'darwin' || process.platform === 'win32', 'Slow app start on these platforms');
const statusTag = page.locator('[data-testid="response-status-tag"]:visible');
const responseBody = page.locator('[data-testid="response-pane"] >> [data-testid="CodeEditor"]:visible', {
has: page.locator('.CodeMirror-activeline'),
});

const text = await loadFixture('grpc-mtls.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);

await page.getByLabel('Import').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByLabel('grpc').click();

await page.getByLabel('Request Collection').getByTestId('grpcs').press('Enter');
await expect(page.getByRole('button', { name: 'Select Method' })).toBeDisabled();

// add root CA and client certificate
const fixturePath = getFixturePath('certificates');

await page.getByRole('button', { name: 'Add Certificates' }).click();
let fileChooserPromise = page.waitForEvent('filechooser');
await page.getByRole('button', { name: 'Add CA Certificate' }).click();
await (await fileChooserPromise).setFiles(path.join(fixturePath, 'rootCA.pem'));

await page.getByRole('button', { name: 'Add client certificate' }).click();
await page.locator('[name="host"]').fill('localhost');

fileChooserPromise = page.waitForEvent('filechooser');
await page.locator('[data-test-id="add-client-certificate-file-chooser"]').click();
await (await fileChooserPromise).setFiles(path.join(fixturePath, 'client.crt'));

fileChooserPromise = page.waitForEvent('filechooser');
await page.locator('[data-test-id="add-client-certificate-key-file-chooser"]').click();
await (await fileChooserPromise).setFiles(path.join(fixturePath, 'client.key'));

await page.getByRole('button', { name: 'Add certificate' }).click();
await page.getByRole('button', { name: 'Done' }).click();

// initiates an mtls connection with the given certificates
await page.getByTestId('button-server-reflection').click();

await page.getByRole('button', { name: 'Select Method' }).click();
await page.getByRole('option', { name: 'RouteGuide/GetFeature' }).click();

await page.getByRole('tab', { name: 'Unary' }).click();
await page.getByRole('button', { name: 'Send' }).click();

// Check for the single Unary response
await page.getByRole('tab', { name: 'Response 1' }).click();
await expect(statusTag).toContainText('0 OK');
await expect(responseBody).toContainText('Berkshire Valley Management Area Trail');
});
Loading

0 comments on commit d6a6bcb

Please sign in to comment.