From 8d36dfa5d367473057e5022c49177508b974f176 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:14:49 -0500 Subject: [PATCH] Make development easier (#3504) * Remove Certificate Steps from Setup * Add Helpers to VSCode Tasks * Force Ephermal Key in Integration Tests * Add Property to Interface --- .../community_dev/postCreateCommand.sh | 13 ++----- .devcontainer/internal_dev/devcontainer.json | 8 ++++- .../internal_dev/postCreateCommand.sh | 13 ++----- .vscode/tasks.json | 36 +++++++++++++++++++ .../src/Sso/appsettings.Development.json | 3 +- dev/.gitignore | 2 ++ dev/create_certificates_linux.sh | 12 ------- dev/create_certificates_mac.sh | 9 ----- dev/create_certificates_windows.ps1 | 3 -- src/Core/Settings/GlobalSettings.cs | 3 +- src/Core/Settings/IGlobalSettings.cs | 1 + src/Identity/appsettings.Development.json | 3 +- .../Utilities/ServiceCollectionExtensions.cs | 5 +++ .../Factories/WebApplicationFactoryBase.cs | 3 ++ 14 files changed, 64 insertions(+), 50 deletions(-) diff --git a/.devcontainer/community_dev/postCreateCommand.sh b/.devcontainer/community_dev/postCreateCommand.sh index afb852dc1..832f510f3 100755 --- a/.devcontainer/community_dev/postCreateCommand.sh +++ b/.devcontainer/community_dev/postCreateCommand.sh @@ -19,20 +19,11 @@ configure_other_vars() { cp secrets.json .secrets.json.tmp # set DB_PASSWORD equal to .services.mssql.environment.MSSQL_SA_PASSWORD, accounting for quotes DB_PASSWORD="$(grep -oP 'MSSQL_SA_PASSWORD=["'"'"']?\K[^"'"'"'\s]+' $DEV_DIR/.env)" - CERT_OUTPUT="$(./create_certificates_linux.sh)" - #shellcheck disable=SC2086 - IDENTITY_SERVER_FINGERPRINT="$(echo $CERT_OUTPUT | awk -F 'Identity Server Dev: ' '{match($2, /[[:alnum:]]+/); print substr($2, RSTART, RLENGTH)}')" - #shellcheck disable=SC2086 - DATA_PROTECTION_FINGERPRINT="$(echo $CERT_OUTPUT | awk -F 'Data Protection Dev: ' '{match($2, /[[:alnum:]]+/); print substr($2, RSTART, RLENGTH)}')" SQL_CONNECTION_STRING="Server=localhost;Database=vault_dev;User Id=SA;Password=$DB_PASSWORD;Encrypt=True;TrustServerCertificate=True" - echo "Identity Server Dev: $IDENTITY_SERVER_FINGERPRINT" - echo "Data Protection Dev: $DATA_PROTECTION_FINGERPRINT" jq \ ".globalSettings.sqlServer.connectionString = \"$SQL_CONNECTION_STRING\" | .globalSettings.postgreSql.connectionString = \"Host=localhost;Username=postgres;Password=$DB_PASSWORD;Database=vault_dev;Include Error Detail=true\" | - .globalSettings.mySql.connectionString = \"server=localhost;uid=root;pwd=$DB_PASSWORD;database=vault_dev\" | - .globalSettings.identityServer.certificateThumbprint = \"$IDENTITY_SERVER_FINGERPRINT\" | - .globalSettings.dataProtection.certificateThumbprint = \"$DATA_PROTECTION_FINGERPRINT\"" \ + .globalSettings.mySql.connectionString = \"server=localhost;uid=root;pwd=$DB_PASSWORD;database=vault_dev\"" \ .secrets.json.tmp >secrets.json rm -f .secrets.json.tmp popd >/dev/null || exit @@ -51,7 +42,7 @@ Proceed? [y/N] " response pushd ./dev >/dev/null || exit pwsh ./setup_secrets.ps1 || true popd >/dev/null || exit - + echo "Running migrations..." sleep 5 # wait for DB container to start dotnet run --project ./util/MsSqlMigratorUtility "$SQL_CONNECTION_STRING" diff --git a/.devcontainer/internal_dev/devcontainer.json b/.devcontainer/internal_dev/devcontainer.json index d86d0576a..6c2b7350b 100644 --- a/.devcontainer/internal_dev/devcontainer.json +++ b/.devcontainer/internal_dev/devcontainer.json @@ -12,5 +12,11 @@ "extensions": ["ms-dotnettools.csdevkit"] } }, - "postCreateCommand": "bash .devcontainer/internal_dev/postCreateCommand.sh" + "postCreateCommand": "bash .devcontainer/internal_dev/postCreateCommand.sh", + "portsAttributes": { + "1080": { + "label": "Mail Catcher", + "onAutoForward": "notify" + } + } } diff --git a/.devcontainer/internal_dev/postCreateCommand.sh b/.devcontainer/internal_dev/postCreateCommand.sh index db074e218..b013be1ce 100755 --- a/.devcontainer/internal_dev/postCreateCommand.sh +++ b/.devcontainer/internal_dev/postCreateCommand.sh @@ -29,20 +29,11 @@ configure_other_vars() { cp secrets.json .secrets.json.tmp # set DB_PASSWORD equal to .services.mssql.environment.MSSQL_SA_PASSWORD, accounting for quotes DB_PASSWORD="$(grep -oP 'MSSQL_SA_PASSWORD=["'"'"']?\K[^"'"'"'\s]+' $DEV_DIR/.env)" - CERT_OUTPUT="$(./create_certificates_linux.sh)" - #shellcheck disable=SC2086 - IDENTITY_SERVER_FINGERPRINT="$(echo $CERT_OUTPUT | awk -F 'Identity Server Dev: ' '{match($2, /[[:alnum:]]+/); print substr($2, RSTART, RLENGTH)}')" - #shellcheck disable=SC2086 - DATA_PROTECTION_FINGERPRINT="$(echo $CERT_OUTPUT | awk -F 'Data Protection Dev: ' '{match($2, /[[:alnum:]]+/); print substr($2, RSTART, RLENGTH)}')" SQL_CONNECTION_STRING="Server=localhost;Database=vault_dev;User Id=SA;Password=$DB_PASSWORD;Encrypt=True;TrustServerCertificate=True" - echo "Identity Server Dev: $IDENTITY_SERVER_FINGERPRINT" - echo "Data Protection Dev: $DATA_PROTECTION_FINGERPRINT" jq \ ".globalSettings.sqlServer.connectionString = \"$SQL_CONNECTION_STRING\" | .globalSettings.postgreSql.connectionString = \"Host=localhost;Username=postgres;Password=$DB_PASSWORD;Database=vault_dev;Include Error Detail=true\" | - .globalSettings.mySql.connectionString = \"server=localhost;uid=root;pwd=$DB_PASSWORD;database=vault_dev\" | - .globalSettings.identityServer.certificateThumbprint = \"$IDENTITY_SERVER_FINGERPRINT\" | - .globalSettings.dataProtection.certificateThumbprint = \"$DATA_PROTECTION_FINGERPRINT\"" \ + .globalSettings.mySql.connectionString = \"server=localhost;uid=root;pwd=$DB_PASSWORD;database=vault_dev\"" \ .secrets.json.tmp >secrets.json rm .secrets.json.tmp popd >/dev/null || exit @@ -74,7 +65,7 @@ Press to continue." echo "Injecting dotnet secrets..." pwsh ./setup_secrets.ps1 || true popd >/dev/null || exit - + echo "Running migrations..." sleep 5 # wait for DB container to start dotnet run --project ./util/MsSqlMigratorUtility "$SQL_CONNECTION_STRING" diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 69077ec5d..9136f3178 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -211,6 +211,42 @@ "clear": false }, "problemMatcher": "$msCompile" + }, + { + "label": "Setup Secrets", + "type": "shell", + "command": "pwsh -WorkingDirectory ${workspaceFolder}/dev -Command '${workspaceFolder}/dev/setup_secrets.ps1 -clear:$${input:setupSecretsClear}'", + "problemMatcher": [] + }, + { + "label": "Install Dev Cert", + "type": "shell", + "command": "dotnet tool install -g dotnet-certificate-tool -g && certificate-tool add --file ${workspaceFolder}/dev/dev.pfx --password '${input:certPassword}'", + "problemMatcher": [] + } + ], + "inputs": [ + { + "id": "setupSecretsClear", + "type": "pickString", + "default": "true", + "description": "Whether or not to clear existing secrets", + "options": [ + { + "label": "true", + "value": "true" + }, + { + "label": "false", + "value": "false" + } + ] + }, + { + "id": "certPassword", + "type": "promptString", + "description": "Password for your dev certificate.", + "password": true } ] } diff --git a/bitwarden_license/src/Sso/appsettings.Development.json b/bitwarden_license/src/Sso/appsettings.Development.json index d45377822..8aae28106 100644 --- a/bitwarden_license/src/Sso/appsettings.Development.json +++ b/bitwarden_license/src/Sso/appsettings.Development.json @@ -23,6 +23,7 @@ }, "storage": { "connectionString": "UseDevelopmentStorage=true" - } + }, + "developmentDirectory": "../../../dev" } } diff --git a/dev/.gitignore b/dev/.gitignore index a9962f37b..55615e716 100644 --- a/dev/.gitignore +++ b/dev/.gitignore @@ -15,5 +15,7 @@ data_protection_dev.crt data_protection_dev.key data_protection_dev.pfx +signingkey.jwk + # Reverse Proxy Conifg reverse-proxy.conf diff --git a/dev/create_certificates_linux.sh b/dev/create_certificates_linux.sh index 1d42dc859..10f084475 100755 --- a/dev/create_certificates_linux.sh +++ b/dev/create_certificates_linux.sh @@ -4,9 +4,6 @@ IDENTITY_SERVER_KEY=identity_server_dev.key IDENTITY_SERVER_CERT=identity_server_dev.crt IDENTITY_SERVER_CN="Bitwarden Identity Server Dev" -DATA_PROTECTION_KEY=data_protection_dev.key -DATA_PROTECTION_CERT=data_protection_dev.crt -DATA_PROTECTION_CN="Bitwarden Data Protection Dev" # Detect management command to trust generated certificates. if [ -x "$(command -v update-ca-certificates)" ]; then @@ -30,19 +27,10 @@ openssl req -x509 -newkey rsa:4096 -sha256 -nodes -days 3650 \ sudo cp $IDENTITY_SERVER_CERT $CA_CERT_DIR -openssl req -x509 -newkey rsa:4096 -sha256 -nodes -days 3650 \ - -keyout $DATA_PROTECTION_KEY \ - -out $DATA_PROTECTION_CERT \ - -subj "/CN=$DATA_PROTECTION_CN" - -sudo cp $DATA_PROTECTION_CERT $CA_CERT_DIR - sudo $UPDATE_CA_CMD identity=($(openssl x509 -in $IDENTITY_SERVER_CERT -outform der | sha1sum | tr a-z A-Z)) -data=($(openssl x509 -in $DATA_PROTECTION_CERT -outform der | sha1sum | tr a-z A-Z)) echo "Certificate fingerprints:" echo "Identity Server Dev: ${identity}" -echo "Data Protection Dev: ${data}" diff --git a/dev/create_certificates_mac.sh b/dev/create_certificates_mac.sh index 2c3ed5350..c123cd0f4 100755 --- a/dev/create_certificates_mac.sh +++ b/dev/create_certificates_mac.sh @@ -7,17 +7,8 @@ openssl pkcs12 -export -legacy -out identity_server_dev.pfx -inkey identity_serv security import ./identity_server_dev.pfx -k ~/Library/Keychains/Login.keychain -openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout data_protection_dev.key -out data_protection_dev.crt \ - -subj "/CN=Bitwarden Data Protection Dev" -days 3650 -openssl pkcs12 -export -legacy -out data_protection_dev.pfx -inkey data_protection_dev.key -in data_protection_dev.crt \ - -certfile data_protection_dev.crt - -security import ./data_protection_dev.pfx -k ~/Library/Keychains/Login.keychain - identity=($(openssl x509 -in identity_server_dev.crt -outform der | shasum -a 1 | tr a-z A-Z)); -data=($(openssl x509 -in data_protection_dev.crt -outform der | shasum -a 1 | tr a-z A-Z)); echo "Certificate fingerprints:" echo "Identity Server Dev: ${identity}" -echo "Data Protection Dev: ${data}" diff --git a/dev/create_certificates_windows.ps1 b/dev/create_certificates_windows.ps1 index 7521ccbf4..3382a9b2b 100644 --- a/dev/create_certificates_windows.ps1 +++ b/dev/create_certificates_windows.ps1 @@ -9,6 +9,3 @@ $params = @{ $params['Subject'] = 'CN=Bitwarden Identity Server Dev'; New-SelfSignedCertificate @params; - -$params['Subject'] = 'CN=Bitwarden Data Protection Dev'; -New-SelfSignedCertificate @params; diff --git a/src/Core/Settings/GlobalSettings.cs b/src/Core/Settings/GlobalSettings.cs index 09cf684c0..4732ec1a3 100644 --- a/src/Core/Settings/GlobalSettings.cs +++ b/src/Core/Settings/GlobalSettings.cs @@ -80,6 +80,7 @@ public class GlobalSettings : IGlobalSettings public virtual IPasswordlessAuthSettings PasswordlessAuth { get; set; } = new PasswordlessAuthSettings(); public virtual IDomainVerificationSettings DomainVerification { get; set; } = new DomainVerificationSettings(); public virtual ILaunchDarklySettings LaunchDarkly { get; set; } = new LaunchDarklySettings(); + public virtual string DevelopmentDirectory { get; set; } public string BuildExternalUri(string explicitValue, string name) { @@ -401,7 +402,7 @@ public class GlobalSettings : IGlobalSettings /// public string CertificatePassword { get; set; } /// - /// The thumbprint of the certificate in the X.509 certificate store for personal certificates for the user account running Bitwarden. + /// The thumbprint of the certificate in the X.509 certificate store for personal certificates for the user account running Bitwarden. /// /// public string CertificateThumbprint { get; set; } diff --git a/src/Core/Settings/IGlobalSettings.cs b/src/Core/Settings/IGlobalSettings.cs index 56b004c31..d91d4b8c3 100644 --- a/src/Core/Settings/IGlobalSettings.cs +++ b/src/Core/Settings/IGlobalSettings.cs @@ -23,4 +23,5 @@ public interface IGlobalSettings IPasswordlessAuthSettings PasswordlessAuth { get; set; } IDomainVerificationSettings DomainVerification { get; set; } ILaunchDarklySettings LaunchDarkly { get; set; } + string DevelopmentDirectory { get; set; } } diff --git a/src/Identity/appsettings.Development.json b/src/Identity/appsettings.Development.json index ac697a6b1..2eaecdfa3 100644 --- a/src/Identity/appsettings.Development.json +++ b/src/Identity/appsettings.Development.json @@ -25,6 +25,7 @@ }, "storage": { "connectionString": "UseDevelopmentStorage=true" - } + }, + "developmentDirectory": "../../dev" } } diff --git a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs index a526ee742..f6e7c609f 100644 --- a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs +++ b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs @@ -511,6 +511,11 @@ public static class ServiceCollectionExtensions { identityServerBuilder.AddSigningCredential(certificate); } + else if (env.IsDevelopment() && !string.IsNullOrEmpty(globalSettings.DevelopmentDirectory)) + { + var developerSigningKeyPath = Path.Combine(globalSettings.DevelopmentDirectory, "signingkey.jwk"); + identityServerBuilder.AddDeveloperSigningCredential(true, developerSigningKeyPath); + } else if (env.IsDevelopment()) { identityServerBuilder.AddDeveloperSigningCredential(false); diff --git a/test/IntegrationTestCommon/Factories/WebApplicationFactoryBase.cs b/test/IntegrationTestCommon/Factories/WebApplicationFactoryBase.cs index fe8e9c2f1..418369c55 100644 --- a/test/IntegrationTestCommon/Factories/WebApplicationFactoryBase.cs +++ b/test/IntegrationTestCommon/Factories/WebApplicationFactoryBase.cs @@ -88,6 +88,9 @@ public abstract class WebApplicationFactoryBase : WebApplicationFactory { "globalSettings:send:connectionString", null}, { "globalSettings:notifications:connectionString", null}, { "globalSettings:storage:connectionString", null}, + + // This will force it to use an ephemeral key for IdentityServer + { "globalSettings:developmentDirectory", null } }); });