From cfd64d467809ce6215cf10b14d1f966bb364fd01 Mon Sep 17 00:00:00 2001 From: Manu de Bump Date: Wed, 30 Oct 2024 16:17:39 +0100 Subject: [PATCH] Rotate keys and dotenv working --- .env | 38 ++++++++++++++++++++++++++++++++++++++ README.md | 10 +++++----- config.ru | 2 +- proxy_server.rb | 7 +++++-- rotake_keys.rb | 24 ++++++++++++++++++++++++ spec/proxy_server_spec.rb | 32 +++++++++++++++++++++----------- 6 files changed, 94 insertions(+), 19 deletions(-) create mode 100644 .env create mode 100755 rotake_keys.rb diff --git a/.env b/.env new file mode 100644 index 0000000..07ca7bd --- /dev/null +++ b/.env @@ -0,0 +1,38 @@ +JWT_SIGNING_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA8PYdftBuWoq/9GeNHO8bA8/gHYBe5wB0W+F2jPfQwuIm5vlO +EKFUTt2boAF1RI+gLrBzOEWDHu9/Pen8/XUxeXG9/w0KaawK1Nc/jlMaUs9jZceE +40mBcNypOPcPITRNuClrE05ACawd0MvXSwDrIIkF4RVxmigsuVwBy0BPTGaq0XkJ +IF372wow0y5YaJVcF5Lo013ILY7U7hziNIXx9hpZEuT65d+HRXnmVYt09HY2PMwm +QJc4foPZXE57yDjeJ8kIiGvWamcEEr1spa82uuykoAEOmw42JOgMME8tIf+9jjnd +ubYMkiAo6MFSVflHd7wYZ6WeBIOzBegD/40MHQIDAQABAoIBAADKrZRPGLxOcEm/ +P7VXaUt3EJqhwlIyGHgJPA1tFdOh1qxBI8BOSRJIQ+kIFmNt/5rTR7S7bKPoBI8p +vJBkmJPdjJ8kb1WvwmtiLEhHMrQIQflPDDMC4hljpcPSD8vJD4omiOGikzVF9bvc +apCJg/ghEQ+pLQ/OYyngdVw+ewCbeP0A7xWag33Kg2OKY6v/N0dZsRzTndL+qonk +qfKBA2bFUO476IjSZRNLiaGBk1Vx36ygJ/cI3BEpmDzDkSMJ6HMIH2JKnKk6rq/t +rA28y7Ot4aCEXJJpE4isDoxIgwjwLuuPDPWnL4UHeBvogFHL87wqihJ9lG1feb6q +jXiCUdkCgYEA/TgkV05ipwkFzg5hT+JJmIX6tNzcc8+M51mjBAtpNDf85T+8+Ja2 +HMujMrnf6E+T7rnAKD9zBQQ1hKi1eSeCU/osgtaLIhATa/H1EQw+EVnJ/TkVa8xj +loO3HQ++IWHDHkH2o0KcJ3/CuxUlu0EqeXmcsagtVXq9hyq660moxKkCgYEA85uD +b2tkcWc74sRf05x9lGU1vlHQaVFzFvna2EaODhqvHjR4gRJubOfsjbkglZ9pdTeQ +QG5cj6V4FtF+m9Zq7THF8f5kYVvw9bwgSdD67PUFmoMrbB8wiI3XRH57tYME4pCS +MIyT0525qTR0sNWSGxmNgCh0xDyc96fHJDz9wFUCgYEA8Msfe8p1c6PX2k/AaAem +tpzJgI36MULwGdwacbEsNNT87z/CQp6GxTE8mvM4oiBya3RF78AOb3nGLsWD9JcG +jzb6dtzv589juKWYxsJej39T3jIXVbBCD5JnYgJjajkeI7rUgAHKnqEWm3MLs1rP +uj5ULHjhy0Rx0IRoxXABRikCgYEA8ZEY+Pfplnrka66Hx/O6o9jpPl0q6gUWt4X0 +edsdKudTGAS4KmX4ko45iSA3K6f0j4QVy46kwt03BImhny80wRlGTP4S1GizvTpc +WladPTSL5fiEqqcTHZZqDUXPruLJiVILZZFBVetmHGAkBucCB1WDd76ma6IflYYO +d+TzTDECgYB8KpcFFQ6axarjJuwrCfZz5nyS7R+8Mj/l8vLYjLqZCobJjNe1vR6n +GiEYgNwVy3noHm5Mbcx8njxVr9SBsH7K4URodDvHbt82JX1sslBF0mjhYVWmXCUz +jX/40A6eR1XAJjjCYma6Gft6e26CpW/087uui7TzxqUtjj7uzahwAA== +-----END RSA PRIVATE KEY----- +" +JWT_SIGNING_PUBLIC_KEY="-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8PYdftBuWoq/9GeNHO8b +A8/gHYBe5wB0W+F2jPfQwuIm5vlOEKFUTt2boAF1RI+gLrBzOEWDHu9/Pen8/XUx +eXG9/w0KaawK1Nc/jlMaUs9jZceE40mBcNypOPcPITRNuClrE05ACawd0MvXSwDr +IIkF4RVxmigsuVwBy0BPTGaq0XkJIF372wow0y5YaJVcF5Lo013ILY7U7hziNIXx +9hpZEuT65d+HRXnmVYt09HY2PMwmQJc4foPZXE57yDjeJ8kIiGvWamcEEr1spa82 +uuykoAEOmw42JOgMME8tIf+9jjndubYMkiAo6MFSVflHd7wYZ6WeBIOzBegD/40M +HQIDAQAB +-----END PUBLIC KEY----- +" diff --git a/README.md b/README.md index f83160d..e6db021 100644 --- a/README.md +++ b/README.md @@ -24,17 +24,17 @@ gem install sinatra jwt ### Configuration -- Set the `SECRET_KEY` environment variable for JWT verification: - ```ruby - # .env - SECRET_KEY = 'your-secret-key' +Use the script to rotate the keys + ```bash + ./rotate_keys ``` +This will add the keys to the .env file ### Starting the Server Run the following command to start the server on port 4567: ```bash -ruby proxy_server.rb +rackup config.ru ``` ### Making Requests diff --git a/config.ru b/config.ru index 8dcc0ba..780e2b0 100644 --- a/config.ru +++ b/config.ru @@ -1,4 +1,4 @@ # config.ru -require "./proxy_server" # Adjust the path if necessary +require "./proxy_server" run ProxyServer diff --git a/proxy_server.rb b/proxy_server.rb index 5e51511..22fe1e1 100644 --- a/proxy_server.rb +++ b/proxy_server.rb @@ -4,12 +4,14 @@ require "json" require "jwt" require "debug" +require "dotenv/load" +require "openssl/pkey" class ProxyServer < Sinatra::Base set :port, 4567 # Secret key for JWT verification - SECRET_KEY = "your-secret-key" + PUBLIC_KEY = ENV.fetch("JWT_SIGNING_PUBLIC_KEY").gsub("\\n", "\n") # Handle CORS headers before do @@ -30,7 +32,8 @@ class ProxyServer < Sinatra::Base # Verify JWT token begin - JWT.decode(token, SECRET_KEY, true, {algorithm: "HS256"}) + public_key = OpenSSL::PKey.read(PUBLIC_KEY) + JWT.decode(token, public_key, true, {algorithm: "RS512"}) rescue JWT::DecodeError halt 401, {error: "Invalid token"}.to_json end diff --git a/rotake_keys.rb b/rotake_keys.rb new file mode 100755 index 0000000..13ac33b --- /dev/null +++ b/rotake_keys.rb @@ -0,0 +1,24 @@ +#!/usr/bin/env ruby +require 'openssl' +require 'debug' + +# Define the RSA key size +key_size = 2048 + +# Generate a new RSA key pair +rsa_key = OpenSSL::PKey::RSA.new(key_size) + +# Display the private key in PEM format +puts "Private Key:" +private_key = rsa_key.to_pem +puts private_key +`sed -i '' '/JWT_SIGNING_PRIVATE_KEY/d' ./.env` +`echo 'JWT_SIGNING_PRIVATE_KEY="#{private_key}"' >> ./.env` + +# Display the public key in PEM format +puts "\nPublic Key:" +public_key = rsa_key.public_key.to_pem +puts public_key +`sed -i '' '/JWT_SIGNING_PUBLIC_KEY/d' ./.env` +`echo 'JWT_SIGNING_PUBLIC_KEY="#{public_key}"' >> ./.env` + diff --git a/spec/proxy_server_spec.rb b/spec/proxy_server_spec.rb index f60874e..73fefc6 100644 --- a/spec/proxy_server_spec.rb +++ b/spec/proxy_server_spec.rb @@ -2,9 +2,10 @@ require "rack/test" require "webmock/rspec" require_relative "../proxy_server" +require "dotenv/load" require "jwt" -SECRET_KEY = "your-secret-key" +PRIVATE_KEY = ENV.fetch("JWT_SIGNING_PRIVATE_KEY").gsub("\\n", "\n") describe "ProxyServer" do include Rack::Test::Methods @@ -17,7 +18,10 @@ def expect_header(k, v) expect(last_response.headers[k]).to eq v end - let(:valid_token) { JWT.encode({data: "test"}, SECRET_KEY, "HS256") } + let(:valid_token) do + private_key = OpenSSL::PKey::RSA.new(PRIVATE_KEY) + JWT.encode({data: "test"}, private_key, "RS512") + end let(:invalid_token) { "invalid.token.here" } let(:target_url) { "https://jsonplaceholder.typicode.com/posts" } @@ -37,21 +41,27 @@ def expect_header(k, v) before(:each) do options "/?url=#{target_url}" end + it "returns CORS headers" do expect_header("access-control-allow-origin", "*") end end context "when x-bump-jwt-token is present" do - before(:each) do - header "x-bump-jwt-token", valid_token - header "x-foo", "bar" - get "/?url=#{target_url}" - end - - it "returns 200 for a valid token" do - expect(last_response.status).to eq(200) - expect_header("access-control-allow-origin", "*") + context "and is valid" do + before(:each) do + header "x-bump-jwt-token", valid_token + header "x-foo", "bar" + get "/?url=#{target_url}" + end + + it "returns 200" do + expect(last_response.status).to eq(200) + end + + it "returns cors headers" do + expect_header("access-control-allow-origin", "*") + end end it "returns 401 for an invalid token" do