From 37fc948aa7b21ed9885f1bfadd9d9fa0d90c0af8 Mon Sep 17 00:00:00 2001 From: Maurizio Pillitu Date: Fri, 10 May 2024 17:56:15 +0200 Subject: [PATCH 1/2] feat: add https support #546 --- certs/cert.pem | 33 ++++++++++++++++ certs/create-cert.sh | 6 +++ certs/key.pem | 52 +++++++++++++++++++++++++ src/config/env.js | 4 +- src/config/index.js | 24 ++++++++++++ src/proxy/index.js | 15 ++++++- website/docs/configuration/overview.mdx | 5 ++- website/docs/quickstart/intercept.mdx | 1 + 8 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 certs/cert.pem create mode 100755 certs/create-cert.sh create mode 100644 certs/key.pem diff --git a/certs/cert.pem b/certs/cert.pem new file mode 100644 index 00000000..88e32ffe --- /dev/null +++ b/certs/cert.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFnzCCA4egAwIBAgIUP3XfqkVZwn6ZnCf31tWzsbzFNM0wDQYJKoZIhvcNAQEL +BQAwXzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9y +azEOMAwGA1UECgwFRklOT1MxDDAKBgNVBAsMA0NUSTESMBAGA1UEAwwJbG9jYWxo +b3N0MB4XDTI0MDUxMDEyNTQ1NFoXDTM0MDUwODEyNTQ1NFowXzELMAkGA1UEBhMC +VVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9yazEOMAwGA1UECgwFRklO +T1MxDDAKBgNVBAsMA0NUSTESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAssWStMgVaIWJBgUH+bhjoIzbgDXBcxco4k0r +xEft+YXMtDv5wFWGBFfmbS8o7aOj7ENvJBgDy4OOy6r5zOJH/K4ZpJSwCAzEKsy6 +K8ymN/ZvcnF24HsYy8j6t3QM59T1RfdZAHN35VaLm0qzZwI/sE4JDybdHN1rkkrZ +8+EAgGjgO1vBm4p0tlWYFgA4MPC/eKo8sT+8lmlr5vHKeDjr7ojW74SV8YB1RPma +YiVIR82EBvKUaZnsYS6XZfa1B6WTqWENuMpTcandsYRBWvDITuGn2PgGyTmsEZpm +QtUuVGq9PGnOIAlvEKmgbSGOe3/+FMDF7aRkLmlOtPh4EL9+xBc7eLHHExxWh5lb +AIQO9gj3w56uhjqu5GK40qO5oD45u7Z9zAiboFGhXVk4tB0ncxVr3UdC5yDiadkl +8TNAsUhw8VK29+YHUZVshQ2U2sNOGgJ5RfKokgY/0DD3EknqepZlsgCqe/zxW1b3 +MaIwm+e9xQn7AF6NcZtYoEum396NpKuKdX5HbGU0JOWa+sJBEkIGYlOZaOqTlgaR +J5LwfrHdBuKGzlp/ti0ZZIR4iPwphrDAMEfsQf1+7bPR3mzPJBMaOqdDY6uSorpD +Y6/N30YRLoVi3I8tr6UIO3tWZMkUShF0ipIJmTzcJl9MZHdD5RYLhkNUD8w9SB4m +NyFvPWkCAwEAAaNTMFEwHQYDVR0OBBYEFHJZpw5gy81W7ndg8p7YkU9QGznZMB8G +A1UdIwQYMBaAFHJZpw5gy81W7ndg8p7YkU9QGznZMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQELBQADggIBAJkr6SD9dvKnxtF9taS2nTdHjwpBVEmMDudujJya +NL/L9BhFWKsuUynF3Z1T+B2q9O5x2T7m25f3/o6K6uArJQlgLuAP8/v33YqDOiX2 +pYIZkzFXb9aEl6lVQ9MbMTYHpWrEPzd3n0Rd9SmgVYiTSaj/vPVXeWAnnXFUVVRC +r936t2JuHOyf39os3OL71ndPoHIBXOHVJM2PH7i1V1hl2sM6N/MtVpOagy7RT4tt +14NQSIeYWZGV2XCes9fYmlNlMIr6v1rs4VlDojR1Ska8wyeF0V4/+dAVjzUVqsu5 +MoviLOM5ULxQQNbShFMKTK+xB2DK2V/AqAlDPAhfwj/WTH40iueIz4/6XAqaDrwO +knkXsG4hHnhR+UnSMozuD2dHD+JHrozXZ9NWonEgGzaBz9jhdpYtrhHwh3XrZDkC +wP5wm8My+Py2NofYOo8YMqHZoHBHYQWYfBV6CU3VcYsg/OW8NCsz1Fm8GyWsFDvK +NJFBY1K3N2fRyBVxBdYqPnVKHhXlIu0c7u8Gk881trqtcq5YXvA6HvPGtMODqiLg +sMUlLt9o4q34s8QohlOD6FjWiDCyThxaMVMgo1kPiIb07iWTfyErPNu+DXx13fCp +M21hYqRlIXqnO1Hwjfaj0H5P5CbOdXrRhhMOtazeVfQX3WuXkdzIhhlYXGRIPRXj ++wvB +-----END CERTIFICATE----- diff --git a/certs/create-cert.sh b/certs/create-cert.sh new file mode 100755 index 00000000..b096a8d0 --- /dev/null +++ b/certs/create-cert.sh @@ -0,0 +1,6 @@ +#! /bin/bash + +# Generates a self-signed certificate used for the SSL Certificate used by the Git Proxy HTTPS endpoint + +# The certificate expires in 10 years (9 May 2034) +openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3650 -nodes -subj "/C=US/ST=NY/L=New York/O=FINOS/OU=CTI/CN=localhost" diff --git a/certs/key.pem b/certs/key.pem new file mode 100644 index 00000000..2b5e00c7 --- /dev/null +++ b/certs/key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +JHu4PGii4YIS1gGXOCviXYD0VZi3eQ== +-----END PRIVATE KEY----- diff --git a/src/config/env.js b/src/config/env.js index c78bb3ed..709f8bbb 100644 --- a/src/config/env.js +++ b/src/config/env.js @@ -1,3 +1,3 @@ -const { GIT_PROXY_SERVER_PORT = 8000, GIT_PROXY_UI_PORT = 8080 } = process.env; +const { GIT_PROXY_SERVER_PORT = 8000, GIT_PROXY_HTTPS_SERVER_PORT = 8443, GIT_PROXY_UI_PORT = 8080 } = process.env; -exports.Vars = { GIT_PROXY_SERVER_PORT, GIT_PROXY_UI_PORT }; +exports.Vars = { GIT_PROXY_SERVER_PORT, GIT_PROXY_HTTPS_SERVER_PORT, GIT_PROXY_UI_PORT }; diff --git a/src/config/index.js b/src/config/index.js index 1708fada..b2a68aec 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -15,6 +15,8 @@ let _proxyUrl = defaultSettings.proxyUrl; let _api = defaultSettings.api; let _cookieSecret = defaultSettings.cookieSecret; let _sessionMaxAgeHours = defaultSettings.sessionMaxAgeHours; +let _sslKeyPath = defaultSettings.sslKeyPemPath; +let _sslCertPath = defaultSettings.sslCertPemPath; const _commitConfig = defaultSettings.commitConfig; const _attestationConfig = defaultSettings.attestationConfig; const _privateOrganizations = defaultSettings.privateOrganizations; @@ -140,6 +142,26 @@ const getCSRFProtection = () => { return _csrfProtection; }; +const getSSLKeyPath = () => { + if (_userSettings && _userSettings.sslKeyPemPath) { + _sslKeyPath = _userSettings.sslKeyPemPath; + } + if (!_sslKeyPath) { + return "../../certs/key.pem"; + } + return _sslKeyPath; +}; + +const getSSLCertPath = () => { + if (_userSettings && _userSettings.sslCertPemPath) { + _sslCertPath = _userSettings.sslCertPemPath; + } + if (!_sslCertPath) { + return "../../certs/cert.pem"; + } + return _sslCertPath; +}; + exports.getAPIs = getAPIs; exports.getProxyUrl = getProxyUrl; exports.getAuthorisedList = getAuthorisedList; @@ -155,3 +177,5 @@ exports.getPrivateOrganizations = getPrivateOrganizations; exports.getURLShortener = getURLShortener; exports.getContactEmail = getContactEmail; exports.getCSRFProtection = getCSRFProtection; +exports.getSSLKeyPath = getSSLKeyPath; +exports.getSSLCertPath = getSSLCertPath; \ No newline at end of file diff --git a/src/proxy/index.js b/src/proxy/index.js index 4dfc14d6..7d6d7874 100644 --- a/src/proxy/index.js +++ b/src/proxy/index.js @@ -1,14 +1,21 @@ const proxyApp = require('express')(); const bodyParser = require('body-parser'); +const http = require("http"); +const https = require("https"); +const fs = require('fs'); +const path = require("path"); const router = require('./routes').router; const config = require('../config'); const db = require('../db'); const { GIT_PROXY_SERVER_PORT: proxyHttpPort } = require('../config/env').Vars; +const { GIT_PROXY_HTTPS_SERVER_PORT: proxyHttpsPort } = require('../config/env').Vars; const options = { inflate: true, limit: '100000kb', type: '*/*', + key: fs.readFileSync(path.join(__dirname, config.getSSLKeyPath())), + cert: fs.readFileSync(path.join(__dirname, config.getSSLCertPath())) }; // Setup the proxy middleware @@ -29,9 +36,13 @@ const start = async () => { } }); - proxyApp.listen(proxyHttpPort, () => { - console.log(`Proxy Listening on ${proxyHttpPort}`); + http.createServer(options, proxyApp).listen(proxyHttpPort, () => { + console.log(`HTTP Proxy Listening on ${proxyHttpPort}`); }); + https.createServer(options, proxyApp).listen(proxyHttpsPort, () => { + console.log(`HTTPS Proxy Listening on ${proxyHttpsPort}`); + }); + return proxyApp; }; diff --git a/website/docs/configuration/overview.mdx b/website/docs/configuration/overview.mdx index b95785b2..df451860 100644 --- a/website/docs/configuration/overview.mdx +++ b/website/docs/configuration/overview.mdx @@ -45,16 +45,17 @@ npx -- @finos/git-proxy --config ./config.json ### Set ports with ENV variables By default, Git Proxy uses port 8000 to expose the Git Server and 8080 for the frontend application. -The ports can be changed by setting the `GIT_PROXY_SERVER_PORT` and `GIT_PROXY_UI_PORT` +The ports can be changed by setting the `GIT_PROXY_SERVER_PORT`, `GIT_PROXY_HTTPS_SERVER_PORT` (optional) and `GIT_PROXY_UI_PORT` environment variables: ``` export GIT_PROXY_UI_PORT="5000" export GIT_PROXY_SERVER_PORT="9090" +export GIT_PROXY_HTTPS_SERVER_PORT="9443" ``` Note that `GIT_PROXY_UI_PORT` is needed for both server and UI Node processes, -whereas `GIT_PROXY_SERVER_PORT` is only needed by the server process. +whereas `GIT_PROXY_SERVER_PORT` (and `GIT_PROXY_HTTPS_SERVER_PORT`) is only needed by the server process. By default, Git Proxy CLI connects to Git Proxy running on localhost and default port. This can be changed by setting the `GIT_PROXY_UI_HOST` and `GIT_PROXY_UI_PORT` environment variables: diff --git a/website/docs/quickstart/intercept.mdx b/website/docs/quickstart/intercept.mdx index 7a55c039..e42feecf 100644 --- a/website/docs/quickstart/intercept.mdx +++ b/website/docs/quickstart/intercept.mdx @@ -62,6 +62,7 @@ git remote set-url origin http://localhost:8000//git-proxy git remote -v ``` +You can also try HTTPS with `git -c http.sslVerify=false remote set-url origin https://localhost:8443//git-proxy.git` :::note SSH protocol is currently not supported, see [#27](https://github.com/finos/git-proxy/issues/27). From e1d8f7c5d0b580a2030bd465525469e943eac167 Mon Sep 17 00:00:00 2001 From: Maurizio Pillitu Date: Fri, 10 May 2024 18:12:40 +0200 Subject: [PATCH 2/2] test: test coverage for https (config) support --- test/testConfig.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/testConfig.test.js b/test/testConfig.test.js index df5f7461..125ee7b4 100644 --- a/test/testConfig.test.js +++ b/test/testConfig.test.js @@ -16,6 +16,8 @@ describe('default configuration', function () { expect(config.getDatabase()).to.be.eql(defaultSettings.sink[0]); expect(config.getTempPasswordConfig()).to.be.eql(defaultSettings.tempPassword); expect(config.getAuthorisedList()).to.be.eql(defaultSettings.authorisedList); + expect(config.getSSLKeyPath()).to.be.eql("../../certs/key.pem"); + expect(config.getSSLCertPath()).to.be.eql("../../certs/cert.pem"); }); after(function () { delete require.cache[require.resolve('../src/config')]; @@ -90,6 +92,19 @@ describe('user configuration', function () { expect(config.getTempPasswordConfig()).to.be.eql(defaultSettings.tempPassword); }); + it('should override default settings for SSL certificate', function () { + const user = { + sslKeyPemPath: "my-key.pem", + sslCertPemPath: "my-cert.pem" + }; + fs.writeFileSync(tempUserFile, JSON.stringify(user)); + + const config = require('../src/config'); + + expect(config.getSSLKeyPath()).to.be.eql(user.sslKeyPemPath); + expect(config.getSSLCertPath()).to.be.eql(user.sslCertPemPath); + }); + afterEach(function () { fs.rmSync(tempUserFile); fs.rmdirSync(tempDir);