From 029c0afaa9e92a63e1f2780bb3addfe380636ce6 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 10 Nov 2022 15:58:49 +1100 Subject: [PATCH] Verify token signature for authenticated login We were just logging in any user without password or other verification before. Now we verify the Keycloak signature and know that the person is indeed logged in. --- .../dfc_provider/authorization_control.rb | 19 ++++++++++++++++++- .../services/authorization_control_spec.rb | 17 +++++++++++++++-- .../spec/support/authorization_helper.rb | 10 +++++++++- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/engines/dfc_provider/app/services/dfc_provider/authorization_control.rb b/engines/dfc_provider/app/services/dfc_provider/authorization_control.rb index e6922490c7..a7da60984b 100644 --- a/engines/dfc_provider/app/services/dfc_provider/authorization_control.rb +++ b/engines/dfc_provider/app/services/dfc_provider/authorization_control.rb @@ -4,12 +4,25 @@ # It controls an OICD Access token and an enterprise. module DfcProvider class AuthorizationControl + # Copied from: https://login.lescommuns.org/auth/realms/data-food-consortium/ + LES_COMMUNES_PUBLIC_KEY = <<~KEY + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl68JGqAILFzoi/1+6siXXp2vylu+7mPjYKjKelTtHFYXWVkbmVptCsamHlY3jRhqSQYe6M1SKfw8D+uXrrWsWficYvpdlV44Vm7uETZOr1/XBOjpWOi1vLmBVtX6jFeqN1BxfE1PxLROAiGn+MeMg90AJKShD2c5RoNv26e20dgPhshRVFPUGru+0T1RoKyIa64z/qcTcTVD2V7KX+ANMweRODdoPAzQFGGjTnL1uUqIdUwSfHSpXYnKxXOsnPC3Mowkv8UIGWWDxS/yzhWc7sOk1NmC7pb+Cg7G8NKj+Pp9qQZnXF39Dg95ZsxJrl6fyPFvTo3zf9CPG/fUM1CkkwIDAQAB + -----END PUBLIC KEY----- + KEY + + def self.public_key + OpenSSL::PKey::RSA.new(LES_COMMUNES_PUBLIC_KEY) + end + def initialize(request) @request = request end def user oidc_user || ofn_user + rescue JWT::ExpiredSignature + nil end private @@ -23,7 +36,11 @@ module DfcProvider end def decode_token - JWT.decode(access_token, nil, false).first + JWT.decode( + access_token, + self.class.public_key, + true, { algorithm: "RS256" } + ).first end def access_token diff --git a/engines/dfc_provider/spec/services/authorization_control_spec.rb b/engines/dfc_provider/spec/services/authorization_control_spec.rb index 2880d964c0..4be4ca8bfc 100644 --- a/engines/dfc_provider/spec/services/authorization_control_spec.rb +++ b/engines/dfc_provider/spec/services/authorization_control_spec.rb @@ -1,13 +1,15 @@ # frozen_string_literal: true -require 'spec_helper' +require DfcProvider::Engine.root.join("spec/spec_helper") describe DfcProvider::AuthorizationControl do + include AuthorizationHelper + let(:user) { create(:user) } describe "with OIDC token" do it "finds a user" do - token = JWT.encode({ email: user.email }, nil) + token = allow_token_for(email: user.email) auth = described_class.new( double(:request, headers: { "Authorization" => "Bearer #{token}" }) @@ -15,5 +17,16 @@ describe DfcProvider::AuthorizationControl do expect(auth.user).to eq user end + + it "ignores expired signatures" do + token = allow_token_for(exp: Time.now.to_i, email: user.email) + + auth = described_class.new( + double(:request, + headers: { "Authorization" => "Bearer #{token}" }) + ) + + expect(auth.user).to eq nil + end end end diff --git a/engines/dfc_provider/spec/support/authorization_helper.rb b/engines/dfc_provider/spec/support/authorization_helper.rb index fb453c329e..f35e028f1a 100644 --- a/engines/dfc_provider/spec/support/authorization_helper.rb +++ b/engines/dfc_provider/spec/support/authorization_helper.rb @@ -2,7 +2,15 @@ module AuthorizationHelper def authorise(email) - token = JWT.encode({ email: email }, nil) + token = allow_token_for(email: email) request.headers["Authorization"] = "JWT #{token}" end + + def allow_token_for(payload) + private_key = OpenSSL::PKey::RSA.generate 2048 + allow(DfcProvider::AuthorizationControl).to receive(:public_key). + and_return(private_key.public_key) + + JWT.encode(payload, private_key, "RS256") + end end