From 0895cf9e2d85f953224a89a2db1512d01b0d0d08 Mon Sep 17 00:00:00 2001 From: Pascal Deklerck Date: Mon, 15 May 2023 21:10:30 +0200 Subject: [PATCH] add example rspec request tests for /magic endpoint --- app/controllers/magic_controller.rb | 15 +++-- spec/requests/magic_spec.rb | 95 +++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 spec/requests/magic_spec.rb diff --git a/app/controllers/magic_controller.rb b/app/controllers/magic_controller.rb index 09b36929304..e90ea363ce0 100644 --- a/app/controllers/magic_controller.rb +++ b/app/controllers/magic_controller.rb @@ -49,14 +49,16 @@ class MagicController < ApplicationController # returns Net::HTTPResponse object res = Net::HTTP.post(owapath, data, signed_headers) + debug("Response: #{res}") debug("Status result: #{res.code}") - redirect_fallthrough and return unless res.code == '200' + redirect_fallthrough and return unless res.is_a? Net::HTTPSuccess body = JSON.parse(res.body) - redirect_fallthrough and return unless body.key?('encrypted_token') && body.key?('success') && body['success'] != 'true' + debug("Response body: #{body}") + redirect_fallthrough and return unless body.key?('encrypted_token') && body.key?('success') && body['success'] == true encrypted_token = body['encrypted_token'] - debug('Success returned!') + debug("Success returned! Encrypted token = #{encrypted_token}") # decrypt encrypted token token = privkey.private_decrypt(Base64.urlsafe_decode64(encrypted_token)) @@ -66,9 +68,12 @@ class MagicController < ApplicationController redirectdest = @dest + args log("Magic - Redirecting to #{redirectdest} now") redirect_to redirectdest + rescue OpenSSL::PKey::RSAError => e + log("Magic - RSA error: #{e.message}") + redirect_fallthrough rescue URI::InvalidURIError - log('Magic - Could not parse destination') - render status: 404 + log("Magic - Could not parse destination: #{@dest}") + redirect_fallthrough end private diff --git a/spec/requests/magic_spec.rb b/spec/requests/magic_spec.rb new file mode 100644 index 00000000000..31f73ec98f1 --- /dev/null +++ b/spec/requests/magic_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'rails_helper' + +dest_nok = 'https://invalid.owas.testing.net' +dest_ok = 'https://valid.owas.testing.net' + +# mock an encrypted token that can be decrypted by the user +def encrypt_token + public_key = OpenSSL::PKey.read(user.account.public_key) + Base64.urlsafe_encode64(public_key.public_encrypt(token)) +end + +def generate_args + "?f=&owt=#{token}" +end + +RSpec.configure do |config| + config.before do + stub_request(:post, "#{dest_nok}/owa"). + # run1: no HTTP OK status + to_return({ status: 404 }).then. + # run2: success = false + to_return({ body: { 'success' => false }.to_json.to_s }). + # run3: success = true, but no token provided + to_return({ body: { 'success' => true }.to_json.to_s }). + # run4: success = true, wrong token provided + to_return({ body: { 'success' => true, 'encrypted_token' => 'LALA' }.to_json.to_s }) + + # HTTP OK response, success = true, correct token provided + stub_request(:post, "#{dest_ok}/owa") + .to_return({ body: { 'success' => true, 'encrypted_token' => encrypted_token }.to_json.to_s }) + end + config.include Devise::Test::IntegrationHelpers, type: :request +end + +RSpec.describe 'GET /magic' do + let(:user) { Fabricate(:user) } + let(:token) { SecureRandom.hex(32) } + let(:encrypted_token) { encrypt_token } + + endp = '/magic' + owa_endp = "#{endp}?owa=1" + owa_dest_nok_endp = "#{owa_endp}&dest=#{dest_nok}" + bdest_nok = dest_nok.unpack1('H*') + owa_bdest_nok_endp = "#{owa_endp}&bdest=#{bdest_nok}" + + it 'redirects to sign in when no user is signed in' do + get owa_dest_nok_endp + expect(response).to redirect_to('/auth/sign_in') + end + + it 'falls through to destination in case of invalid response received from OpenWebAuth server' do + sign_in user + + # run1: no HTTP OK status + get owa_dest_nok_endp + expect(response).to have_http_status(302) + expect(response).to redirect_to(dest_nok) + + # run2: success = false + get owa_dest_nok_endp + expect(response).to have_http_status(302) + expect(response).to redirect_to(dest_nok) + + # run3: success = true, but no token provided + get owa_bdest_nok_endp + expect(response).to have_http_status(302) + expect(response).to redirect_to(dest_nok) + + # run4: success = true, invalid token provided + get owa_bdest_nok_endp + expect(response).to have_http_status(302) + expect(response).to redirect_to(dest_nok) + end + + # Happy case testing - destination is a working OpenWebAuth server + owa_dest_ok_endp = "#{owa_endp}&dest=#{dest_ok}" + bdest_ok = dest_ok.unpack1('H*') + owa_bdest_ok_endp = "#{owa_endp}&bdest=#{bdest_ok}" + + it 'returns a remotely authenticated redirect to the destination when using dest parameter' do + sign_in user + get owa_dest_ok_endp + expect(response).to have_http_status(302) + expect(response).to redirect_to("#{dest_ok}#{generate_args}") + end + + it 'returns a remotely authenticated redirect to the destination when using hex encoded dest parameter' do + sign_in user + get owa_bdest_ok_endp + expect(response).to have_http_status(302) + expect(response).to redirect_to("#{dest_ok}#{generate_args}") + end +end