Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FI-3508 Update custom redirect path to include correct suite ID #14

Merged
merged 12 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ group :development, :test do
gem 'debug'
gem 'database_cleaner-sequel', '~> 1.8'
gem 'factory_bot', '~> 6.1'
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.10'
gem 'rubocop'
gem 'rubocop-rspec', require: false
Expand Down
69 changes: 37 additions & 32 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ PATH
remote: .
specs:
udap_security_test_kit (0.10.0)
inferno_core (>= 0.4.2)
inferno_core (>= 0.5.1)
jwt (~> 2.3)

GEM
Expand Down Expand Up @@ -34,6 +34,7 @@ GEM
database_cleaner-sequel (1.99.0)
database_cleaner (~> 1.99.0)
sequel
date (3.4.1)
date_time_precision (0.8.1)
debug (1.9.2)
irb (~> 1.10)
Expand Down Expand Up @@ -123,18 +124,18 @@ GEM
mustermann (~> 1.0)
mustermann-contrib (~> 1.0)
rack (~> 2.0)
hanami-utils (2.1.0)
hanami-utils (2.2.0)
concurrent-ruby (~> 1.0)
dry-core (~> 1.0, < 2)
dry-transformer (~> 1.0, < 2)
hansi (0.2.1)
hashdiff (1.1.1)
hashdiff (1.1.2)
http-accept (1.7.0)
http-cookie (1.0.7)
domain_name (~> 0.5)
i18n (1.14.6)
concurrent-ruby (~> 1.0)
inferno_core (0.5.0)
inferno_core (0.5.1)
activesupport (~> 6.1.7.5)
base62-rb (= 0.3.1)
blueprinter (= 0.25.2)
Expand All @@ -161,23 +162,23 @@ GEM
sqlite3 (~> 1.4)
thor (~> 1.2.1)
tty-markdown (~> 0.7.1)
io-console (0.7.2)
irb (1.14.0)
io-console (0.8.0)
irb (1.14.1)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.7.2)
json (2.9.0)
jwt (2.9.3)
base64
kramdown (2.4.0)
rexml
kramdown (2.5.1)
rexml (>= 3.3.9)
language_server-protocol (3.17.0.3)
logger (1.6.1)
logger (1.6.2)
method_source (1.1.0)
mime-types (3.6.0)
logger
mime-types-data (~> 3.2015)
mime-types-data (3.2024.1001)
minitest (5.25.1)
mime-types-data (3.2024.1203)
minitest (5.25.4)
multi_json (1.15.0)
multi_xml (0.7.1)
bigdecimal (~> 3.1)
Expand All @@ -189,11 +190,11 @@ GEM
mustermann (= 1.1.2)
netrc (0.11.0)
nio4r (2.7.4)
nokogiri (1.16.7-arm64-darwin)
nokogiri (1.16.8-arm64-darwin)
racc (~> 1.4)
nokogiri (1.16.7-x86_64-darwin)
nokogiri (1.16.8-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.16.7-x86_64-linux)
nokogiri (1.16.8-x86_64-linux)
racc (~> 1.4)
oauth2 (1.4.11)
faraday (>= 0.17.3, < 3.0)
Expand All @@ -203,7 +204,7 @@ GEM
rack (>= 1.2, < 4)
oj (3.11.0)
parallel (1.26.3)
parser (3.3.5.0)
parser (3.3.6.0)
ast (~> 2.4.1)
racc
pastel (0.8.0)
Expand All @@ -214,55 +215,58 @@ GEM
pry-byebug (3.10.1)
byebug (~> 11.0)
pry (>= 0.13, < 0.15)
psych (5.1.2)
psych (5.2.1)
date
stringio
public_suffix (6.0.1)
puma (5.6.9)
nio4r (~> 2.0)
racc (1.8.1)
rack (2.2.10)
rack-test (1.1.0)
rack (>= 1.0, < 3)
rainbow (3.1.1)
rake (13.2.1)
rdoc (6.7.0)
rdoc (6.8.1)
psych (>= 4.0.0)
redis-client (0.22.2)
connection_pool
regexp_parser (2.9.2)
reline (0.5.10)
regexp_parser (2.9.3)
reline (0.5.12)
io-console (~> 0.5)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
rexml (3.3.9)
rouge (4.4.0)
rouge (4.5.1)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.1)
rspec-core (3.13.2)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.1)
rspec-mocks (3.13.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.1)
rubocop (1.66.1)
rspec-support (3.13.2)
rubocop (1.69.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.4, < 3.0)
rubocop-ast (>= 1.32.2, < 2.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.36.2, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.32.3)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.36.2)
parser (>= 3.3.1.0)
rubocop-rspec (3.0.5)
rubocop-rspec (3.2.0)
rubocop (~> 1.61)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
Expand All @@ -275,7 +279,7 @@ GEM
sqlite3 (1.7.3-arm64-darwin)
sqlite3 (1.7.3-x86_64-darwin)
sqlite3 (1.7.3-x86_64-linux)
stringio (3.1.1)
stringio (3.1.2)
strings (0.2.1)
strings-ansi (~> 0.2)
unicode-display_width (>= 1.5, < 3.0)
Expand All @@ -296,7 +300,7 @@ GEM
concurrent-ruby (~> 1.0)
unicode-display_width (2.6.0)
unicode_utils (1.4.0)
webmock (3.23.1)
webmock (3.24.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
Expand All @@ -312,6 +316,7 @@ DEPENDENCIES
database_cleaner-sequel (~> 1.8)
debug
factory_bot (~> 6.1)
rack-test (~> 1.1.0)
rspec (~> 3.10)
rubocop
rubocop-rspec
Expand Down
5 changes: 5 additions & 0 deletions lib/udap_security_test_kit.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require_relative 'udap_security_test_kit/authorization_code_group'
require_relative 'udap_security_test_kit/client_credentials_group'
require_relative 'udap_security_test_kit/version'
require_relative 'udap_security_test_kit/redirect_uri'

module UDAPSecurityTestKit
class Suite < Inferno::TestSuite
Expand Down Expand Up @@ -61,6 +62,10 @@ class Suite < Inferno::TestSuite
request.query_parameters['state']
end

config options: {
redirect_uri: UDAPSecurityTestKit::UDAP_REDIRECT_URI
}

links [
{
label: 'Report Issue',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require_relative '../udap_security_test_kit'
module UDAPSecurityTestKit
class AuthorizationCodeRedirectTest < Inferno::Test
title 'Authorization server redirects client to redirect URI'
Expand All @@ -20,8 +21,6 @@ class AuthorizationCodeRedirectTest < Inferno::Test

receives_request :redirect

config options: { redirect_uri: "#{Inferno::Application['base_url']}/custom/udap_security_test_kit/redirect" }

def wait_message(auth_url)
if config.options[:redirect_message_proc].present?
return instance_exec(auth_url, &config.options[:redirect_message_proc])
Expand Down Expand Up @@ -49,6 +48,11 @@ def authorization_url_builder(url, params)
end

run do
assert_valid_http_uri(
udap_authorization_endpoint,
"UDAP authorization endpoint '#{udap_authorization_endpoint}' is not a valid URI"
)

output udap_authorization_code_state: SecureRandom.uuid

oauth2_params = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ class AuthorizationCodeTokenExchangeTest < Inferno::Test

makes_request :token_exchange

config options: { redirect_uri: "#{Inferno::Application['base_url']}/custom/udap_security_test_kit/redirect" }

run do
client_assertion_payload = UDAPClientAssertionPayloadBuilder.build(
udap_client_id,
Expand Down
3 changes: 3 additions & 0 deletions lib/udap_security_test_kit/redirect_uri.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module UDAPSecurityTestKit
UDAP_REDIRECT_URI = "#{Inferno::Application['base_url']}/custom/udap_security/redirect".freeze
end
3 changes: 2 additions & 1 deletion lib/udap_security_test_kit/software_statement_builder.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
require 'jwt'
require_relative 'redirect_uri'

module UDAPSecurityTestKit
class SoftwareStatementBuilder
def self.build_payload(iss, aud, grant_type, scope)
if grant_type == 'authorization_code'
redirect_uris = ["#{Inferno::Application['base_url']}/custom/udap_security_test_kit/redirect"]
redirect_uris = [UDAPSecurityTestKit::UDAP_REDIRECT_URI]
response_types = ['code']
client_name = 'Inferno UDAP Authorization Code Test Client'
elsif grant_type == 'client_credentials'
Expand Down
2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
require 'inferno'
Inferno::Application.finalize!

require Inferno::SpecSupport::FACTORY_BOT_SUPPORT_PATH
Inferno::SpecSupport.require_helpers

FactoryBot.definition_file_paths = [
Inferno::SpecSupport::FACTORY_PATH
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
require_relative '../../lib/udap_security_test_kit/authorization_code_redirect_test'

RSpec.describe UDAPSecurityTestKit::AuthorizationCodeRedirectTest, :request do
let(:suite_id) { 'udap_security' }
let(:test) { Inferno::Repositories::Tests.new.find('udap_authorization_code_redirect') }
let(:session_data_repo) { Inferno::Repositories::SessionData.new }
let(:results_repo) { Inferno::Repositories::Results.new }
let(:requests_repo) { Inferno::Repositories::Requests.new }
let(:test_session) { repo_create(:test_session, test_suite_id: 'udap_security') }
let(:url) { 'http://example.com/fhir' }
let(:inputs) do
{
udap_authorization_endpoint: 'http://example.com/authorize',
udap_client_id: 'CLIENT_ID'
}
end

def run(runnable, inputs = {})
test_run_params = { test_session_id: test_session.id }.merge(runnable.reference_hash)
test_run = Inferno::Repositories::TestRuns.new.create(test_run_params)
inputs.each do |name, value|
type = runnable.config.input_type(name)
type = 'text' if type == 'radio'
session_data_repo.save(
test_session_id: test_session.id,
name:,
value:,
type:
)
end
Inferno::TestRunner.new(test_session:, test_run:).run(runnable)
end

it 'waits and then passes when it receives a request with the correct state' do
allow(test).to receive(:parent).and_return(Inferno::TestGroup)
result = run(test, inputs)
expect(result.result).to eq('wait')

state = session_data_repo.load(test_session_id: test_session.id, name: 'udap_authorization_code_state')
get "/custom/udap_security/redirect?state=#{state}"

result = results_repo.find(result.id)
expect(result.result).to eq('pass')
end

it 'continues to wait when it receives a request with the incorrect state' do
result = run(test, inputs)
expect(result.result).to eq('wait')

state = SecureRandom.uuid
get "/custom/smart/redirect?state=#{state}"

result = results_repo.find(result.id)
expect(result.result).to eq('wait')
end

it 'fails if the authorization url is invalid' do
inputs[:udap_authorization_endpoint] = 'invalid'
result = run(test, inputs)
expect(result.result).to eq('fail')
expect(result.result_message).to match(/is not a valid URI/)
end

it "persists the incoming 'redirect' request" do
allow(test).to receive(:parent).and_return(Inferno::TestGroup)
run(test, inputs)
state = session_data_repo.load(test_session_id: test_session.id, name: 'udap_authorization_code_state')
url = "/custom/udap_security/redirect?state=#{state}"
get url

request = requests_repo.find_named_request(test_session.id, 'redirect')
expect(request.url).to end_with(url)
end

it "persists the 'udap_authorization_code_state' output" do
result = run(test, inputs)
expect(result.result).to eq('wait')

state = result.result_message.match(/a state of `(.*)`/)[1]
persisted_state = session_data_repo.load(test_session_id: test_session.id, name: 'udap_authorization_code_state')

expect(persisted_state).to eq(state)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require_relative '../../lib/udap_security_test_kit/default_cert_file_loader'

RSpec.describe UDAPSecurityTestKit::AuthorizationCodeTokenExchangeTest do
let(:suite_id) { 'udap_security' }
let(:runnable) { Inferno::Repositories::Tests.new.find('udap_authorization_code_token_exchange') }
let(:session_data_repo) { Inferno::Repositories::SessionData.new }
let(:results_repo) { Inferno::Repositories::Results.new }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require_relative '../../lib/udap_security_test_kit/authorization_endpoint_field_test'

RSpec.describe UDAPSecurityTestKit::AuthorizationEndpointFieldTest do
let(:suite_id) { 'udap_security' }
let(:runnable) { Inferno::Repositories::Tests.new.find('udap_authorization_endpoint_field') }
let(:session_data_repo) { Inferno::Repositories::SessionData.new }
let(:results_repo) { Inferno::Repositories::Results.new }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require_relative '../../lib/udap_security_test_kit/default_cert_file_loader'

RSpec.describe UDAPSecurityTestKit::ClientCredentialsTokenExchangeTest do
let(:suite_id) { 'udap_security' }
let(:runnable) { Inferno::Repositories::Tests.new.find('udap_client_credentials_token_exchange') }
let(:session_data_repo) { Inferno::Repositories::SessionData.new }
let(:results_repo) { Inferno::Repositories::Results.new }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require_relative '../../lib/udap_security_test_kit/default_cert_file_loader'

RSpec.describe UDAPSecurityTestKit::GenerateClientCertsTest do
let(:suite_id) { 'udap_security' }
let(:runnable) { Inferno::Repositories::Tests.new.find('udap_generate_client_certs') }
let(:session_data_repo) { Inferno::Repositories::SessionData.new }
let(:results_repo) { Inferno::Repositories::Results.new }
Expand Down
Loading
Loading