diff --git a/fhir_client.gemspec b/fhir_client.gemspec index cdc05d33..0656f1c9 100644 --- a/fhir_client.gemspec +++ b/fhir_client.gemspec @@ -28,7 +28,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'fhir_stu3_models', '>= 3.1.1' spec.add_dependency 'fhir_dstu2_models', '>= 1.1.1' spec.add_dependency 'nokogiri', '>= 1.10.4' - spec.add_dependency 'oauth2', '~> 1.1' + spec.add_dependency 'oauth2', '~> 2.0' spec.add_dependency 'rack', '>= 1.5' spec.add_dependency 'rest-client', '~> 2.0' spec.add_dependency 'tilt', '>= 1.1' diff --git a/lib/fhir_client/client.rb b/lib/fhir_client/client.rb index 034c5320..c552ae08 100644 --- a/lib/fhir_client/client.rb +++ b/lib/fhir_client/client.rb @@ -172,10 +172,11 @@ def set_oauth2_auth(client, secret, authorize_path, token_path, site = nil) site: site || @base_service_url, authorize_url: authorize_path, token_url: token_path, - raise_errors: true + raise_errors: true, + auth_scheme: :request_body } + options[:connection_opts] = { proxy: proxy } unless proxy.nil? client = OAuth2::Client.new(client, secret, options) - client.connection.proxy(proxy) unless proxy.nil? @client = client.client_credentials.get_token end diff --git a/lib/fhir_client/fhir_api_validation.json b/lib/fhir_client/fhir_api_validation.json index 1601d76b..4a3add82 100644 --- a/lib/fhir_client/fhir_api_validation.json +++ b/lib/fhir_client/fhir_api_validation.json @@ -344,7 +344,7 @@ "Accept": "optional", "Prefer": false }, - "body": { "regex": "([\w\-]+(=[\w\-.:\/\|]*)?(&[\w\-]+(=[\w\-.:\/\|]*)?)*)?" } + "body": { "regex": "([\\w\\-]+(=[\\w\\-.:\\/\\|]*)?(&[\\w\\-]+(=[\\w\\-.:\\/\\|]*)?)*)?" } }, "response": { "status": [200], diff --git a/test/unit/basic_test.rb b/test/unit/basic_test.rb index 53567a43..72c01adc 100644 --- a/test/unit/basic_test.rb +++ b/test/unit/basic_test.rb @@ -52,6 +52,17 @@ def test_oauth2_token_auth_custom assert client.client.client.site == "http://custom-test.com/fhir/" end + def test_oauth2_auth_with_proxy + stub_request(:post, /token_path/).to_return(status: 200, body: '{"access_token" : "valid_token"}', headers: {'Content-Type' => 'application/json'}) + + proxy_client = FHIR::Client.new("http://basic-test.com/fhir/", proxy: "http://proxy.example.com:8080") + proxy_client.set_oauth2_auth("client", "secret", "authorize_path", "token_path") + + assert proxy_client.use_oauth2_auth + oauth2_client = proxy_client.client.client + assert_equal({ proxy: "http://proxy.example.com:8080" }, oauth2_client.options[:connection_opts]) + end + def test_client_logs_without_response # This used to provide a NoMethodError: # undefined method `request' for nil:NilClass diff --git a/test/unit/client_reply_validation_test.rb b/test/unit/client_reply_validation_test.rb new file mode 100644 index 00000000..2276f647 --- /dev/null +++ b/test/unit/client_reply_validation_test.rb @@ -0,0 +1,45 @@ +require_relative '../test_helper' + +class ClientReplyValidationTest < Test::Unit::TestCase + VALIDATION_JSON_PATH = File.join( + File.expand_path('../../..', __FILE__), + 'lib', 'fhir_client', 'fhir_api_validation.json' + ).freeze + + def validation_rules + @validation_rules ||= JSON.parse(File.read(VALIDATION_JSON_PATH)) + end + + def form_body_regex + rule = validation_rules.find { |r| r.dig('request', 'body').is_a?(Hash) && r.dig('request', 'body', 'regex') } + Regexp.new(rule['request']['body']['regex']) + end + + def test_fhir_api_validation_json_parses_without_error + assert_nothing_raised(JSON::ParserError) { JSON.parse(File.read(VALIDATION_JSON_PATH)) } + end + + def test_operation_form_body_regex_matches_empty_body + assert_match form_body_regex, '' + end + + def test_operation_form_body_regex_matches_single_param + assert_match form_body_regex, 'foo=bar' + end + + def test_operation_form_body_regex_matches_multiple_params + assert_match form_body_regex, 'foo=bar&baz=qux' + end + + def test_operation_form_body_regex_matches_param_without_value + assert_match form_body_regex, 'param1=value1¶m2' + end + + def test_operation_form_body_regex_treats_backslash_w_as_word_char_class + # If \\\\w was used in the JSON instead of \\w, the compiled regex would + # treat [\\w] as matching a literal backslash or 'w', not word characters. + # Verify \w acts as a word-character class by matching digits and underscores. + assert_match form_body_regex, '_count=10' + assert_match form_body_regex, 'param1=value1' + end +end