-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FI-2865: FHIR Client Auth Info Refresh (#513)
* Added support for auth_info to fhir_client Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * Added unit test for auth info Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * WIP:perform refresh using auth_info Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * support for backend services authentication using auth_info Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * WIP auth info unit test Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * Updated auth_info_spec Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * Extracted the auth info sample data to its own fixture file" Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * Updated fhir_client_spec Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * Freeze constants Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * Updated ffhir client spec Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * Update based on PR comments Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * Update to return for and Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * Update ENV name for the inferno core jwks path Co-authored-by: Stephen MacVicar <Jammjammjamm@users.noreply.github.com> * Added doc to JWKS class Signed-off-by: Vanessa Fotso <vfotso@mitre.org> * proofread JWKs doc Co-authored-by: Stephen MacVicar <Jammjammjamm@users.noreply.github.com> * extract reading content of jwks file into its own method Signed-off-by: Vanessa Fotso <vfotso@mitre.org> --------- Signed-off-by: Vanessa Fotso <vfotso@mitre.org> Co-authored-by: Stephen MacVicar <Jammjammjamm@users.noreply.github.com>
- Loading branch information
1 parent
6eef3b3
commit 3e96653
Showing
8 changed files
with
812 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
{ | ||
"keys": [ | ||
{ | ||
"kty": "EC", | ||
"crv": "P-384", | ||
"x": "JQKTsV6PT5Szf4QtDA1qrs0EJ1pbimQmM2SKvzOlIAqlph3h1OHmZ2i7MXahIF2C", | ||
"y": "bRWWQRJBgDa6CTgwofYrHjVGcO-A7WNEnu4oJA5OUJPPPpczgx1g2NsfinK-D2Rw", | ||
"use": "sig", | ||
"key_ops": [ | ||
"verify" | ||
], | ||
"ext": true, | ||
"kid": "4b49a739d1eb115b3225f4cf9beb6d1b", | ||
"alg": "ES384" | ||
}, | ||
{ | ||
"kty": "EC", | ||
"crv": "P-384", | ||
"d": "kDkn55p7gryKk2tj6z2ij7ExUnhi0ngxXosvqa73y7epwgthFqaJwApmiXXU2yhK", | ||
"x": "JQKTsV6PT5Szf4QtDA1qrs0EJ1pbimQmM2SKvzOlIAqlph3h1OHmZ2i7MXahIF2C", | ||
"y": "bRWWQRJBgDa6CTgwofYrHjVGcO-A7WNEnu4oJA5OUJPPPpczgx1g2NsfinK-D2Rw", | ||
"key_ops": [ | ||
"sign" | ||
], | ||
"ext": true, | ||
"kid": "4b49a739d1eb115b3225f4cf9beb6d1b", | ||
"alg": "ES384" | ||
}, | ||
{ | ||
"kty": "RSA", | ||
"alg": "RS384", | ||
"n": "vjbIzTqiY8K8zApeNng5ekNNIxJfXAue9BjoMrZ9Qy9m7yIA-tf6muEupEXWhq70tC7vIGLqJJ4O8m7yiH8H2qklX2mCAMg3xG3nbykY2X7JXtW9P8VIdG0sAMt5aZQnUGCgSS3n0qaooGn2LUlTGIR88Qi-4Nrao9_3Ki3UCiICeCiAE224jGCg0OlQU6qj2gEB3o-DWJFlG_dz1y-Mxo5ivaeM0vWuodjDrp-aiabJcSF_dx26sdC9dZdBKXFDq0t19I9S9AyGpGDJwzGRtWHY6LsskNHLvo8Zb5AsJ9eRZKpnh30SYBZI9WHtzU85M9WQqdScR69Vyp-6Uhfbvw", | ||
"e": "AQAB", | ||
"use": "sig", | ||
"key_ops": [ | ||
"verify" | ||
], | ||
"ext": true, | ||
"kid": "b41528b6f37a9500edb8a905a595bdd7" | ||
}, | ||
{ | ||
"kty": "RSA", | ||
"alg": "RS384", | ||
"n": "vjbIzTqiY8K8zApeNng5ekNNIxJfXAue9BjoMrZ9Qy9m7yIA-tf6muEupEXWhq70tC7vIGLqJJ4O8m7yiH8H2qklX2mCAMg3xG3nbykY2X7JXtW9P8VIdG0sAMt5aZQnUGCgSS3n0qaooGn2LUlTGIR88Qi-4Nrao9_3Ki3UCiICeCiAE224jGCg0OlQU6qj2gEB3o-DWJFlG_dz1y-Mxo5ivaeM0vWuodjDrp-aiabJcSF_dx26sdC9dZdBKXFDq0t19I9S9AyGpGDJwzGRtWHY6LsskNHLvo8Zb5AsJ9eRZKpnh30SYBZI9WHtzU85M9WQqdScR69Vyp-6Uhfbvw", | ||
"e": "AQAB", | ||
"d": "rriV9GYimi5by7TOW4xNh6_gYBHVRDBsft2OFF8qapdVHt2GNuRDDxc_B6ga6TY2Enh2MLKLTr1dD3W4FIdTCJiMerrorp07FJS7nJEMgWQDxrfgkX4_EqrhW42L5d4vypYnRXEEW6u4gzkx5uFOkdvJBIK7CsIdSaBFYhochnynNgvbKWasi4rl2hayEH8tdf3B7Z6OIH9alspBTaq3j_zJt_KkrpYEzIUb4UgALB5NTWn5YKr0Avk_asOg8YfjViQwO9ASGaWjQeJ2Rx8OEQwBMQHSDMCSWNiWmYOu9PcwSZFc1vLxqzyIM8QrQSJHCCMo_wGYgke_r0CLeONHEQ", | ||
"p": "5hH_QApWGeobRi1n7XbMfJYohB8K3JDPa0MspfplHpJ-17JiGG2sNoBdBcpaPRf9OX48P8VqO0qrSSRAk-I-uO6OO9BHbIukXJILqnY2JmurYzbcYbt5FVbknlHRJojkF6-7sFBazpueUlOnXCw7X7Z_SkfNE4QX5Ejm2Zm5mek", | ||
"q": "06bZz7c7K9s1-aEZsxYnLJ9eTpKlt1tIBDA_LwIh5W3w259pes2kUtimbnkyOf-V2ZIERsFCh5s-S9IOEMvAIa6M5j9GW1ILNT7AcHIUfcyFcH-FF8BU_KJdRP5PXnIXFdYcylvsdoIdchy1AaUIzyiKRCU3HBYI75hez0l_F2c", | ||
"dp": "h_sVIXW6hCCRND48EedIX06k7conMkxIu_39ErDXOWWeoMAnKIcR5TijQnviL__QxD1vQMXezuKIMHfDz2RGbClbWdD1lhtG7wvG515tDPJQXxia0wzqOQmdoFF9S8hXAAT26vPjaAAkaEZXQaxG_4Au5elgNWu6b0wDXZN1Vpk", | ||
"dq": "GqS0YpuUTU8JGmWXUJ4HTGy7eHSpe8134V8ZdRd1oOYYHe2RX64nc25mdR24nuh3uq3Q7_9AGsYGL5E_yAl-JD9O6WUpvDE1y_wcSYty3Os0GRdUb8r8Z9kgmKDS6Pa_xTXw5eBwgfKbNlQ6zPwzgbB-x1lP-K8lbNPni3ybDR0", | ||
"qi": "cqQfoi0sM5Su8ZOhznmdWrDIQB28H6fBKiabgaIKkbWZV4e0nwFvLquHjPOvv4Ao8iEGU5dyhvg0n5BKYPi-4mp6M6OA1sy0NrTr7EsKSYGyu2pBq9rw4oAYTM2LXKg6K-awgUUlkc451IwxHBAe15PWCBM3kvLQeijNid0Vz5I", | ||
"key_ops": [ | ||
"sign" | ||
], | ||
"ext": true, | ||
"kid": "b41528b6f37a9500edb8a905a595bdd7" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
module Inferno | ||
module DSL | ||
# The JWKS class provides methods to handle JSON Web Key Sets (JWKS) | ||
# within Inferno. | ||
# | ||
# This class allows users to fetch, parse, and manage JWKS, ensuring | ||
# that the necessary keys for verifying tokens are available. | ||
class JWKS | ||
class << self | ||
# Returns a formatted JSON string of the JWKS public keys that are used for verification. | ||
# This method filters out keys that do not have the 'verify' operation. | ||
# | ||
# @return [String] The formatted JSON string of the JWKS public keys. | ||
# | ||
# @example | ||
# jwks_json = Inferno::JWKS.jwks_json | ||
# puts jwks_json | ||
def jwks_json | ||
@jwks_json ||= | ||
JSON.pretty_generate( | ||
{ keys: jwks.export[:keys].select { |key| key[:key_ops]&.include?('verify') } } | ||
) | ||
end | ||
|
||
# Provides the default file path to the JWKS file. | ||
# This method is primarily used internally to locate the default JWKS file. | ||
# | ||
# @return [String] The default JWKS file path. | ||
# | ||
# @private | ||
def default_jwks_path | ||
@default_jwks_path ||= File.join(__dir__, 'jwks.json') | ||
end | ||
|
||
# Fetches the JWKS file path from the environment variable `INFERNO_JWKS_PATH`. | ||
# If the environment variable is not set, it falls back to the default path | ||
# provided by `.default_jwks_path`. | ||
# | ||
# @return [String] The JWKS file path. | ||
# | ||
# @private | ||
def jwks_path | ||
@jwks_path ||= | ||
ENV.fetch('INFERNO_JWKS_PATH', default_jwks_path) | ||
end | ||
|
||
# Reads the JWKS content from the file located at the JWKS path. | ||
# | ||
# @return [String] The json content of the JWKS file. | ||
# | ||
# @private | ||
def default_jwks_json | ||
@default_jwks_json ||= File.read(jwks_path) | ||
end | ||
|
||
# Parses and returns a `JWT::JWK::Set` object from the provided JWKS string | ||
# or from the file located at the JWKS path. If a user-provided JWKS string | ||
# is not available, it reads the JWKS from the file. | ||
# | ||
# @param user_jwks [String, nil] An optional json containing the JWKS. | ||
# If not provided, the method reads from the file. | ||
# @return [JWT::JWK::Set] The parsed JWKS set. | ||
# | ||
# @example | ||
# # Using a user-provided JWKS string | ||
# user_jwks = '{"keys":[...]}' | ||
# jwks_set = Inferno::JWKS.jwks(user_jwks: user_jwks) | ||
# | ||
# # Using the default JWKS file | ||
# jwks_set = Inferno::JWKS.jwks | ||
def jwks(user_jwks: nil) | ||
JWT::JWK::Set.new(JSON.parse(user_jwks.presence || default_jwks_json)) | ||
end | ||
end | ||
end | ||
end | ||
|
||
JWKS = DSL::JWKS | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
module AuthInfoConstants | ||
AUTH_URL = 'http://example.com/authorization'.freeze | ||
TOKEN_URL = 'http://example.com/token'.freeze | ||
REQUESTED_SCOPES = 'launch/patient openid fhirUser patient/*.*'.freeze | ||
ENCRYPTION_ALGORITHM = 'ES384'.freeze | ||
KID = '4b49a739d1eb115b3225f4cf9beb6d1b'.freeze | ||
JWKS = File.read(File.join('lib', 'inferno', 'dsl', 'jwks.json')).freeze | ||
class << self | ||
def token_info | ||
{ | ||
access_token: 'SAMPLE_TOKEN', | ||
refresh_token: 'SAMPLE_REFRESH_TOKEN', | ||
expires_in: '3600', | ||
issue_time: Time.now.iso8601 | ||
} | ||
end | ||
|
||
def public_access_default | ||
{ | ||
auth_type: 'public', | ||
token_url: TOKEN_URL, | ||
client_id: 'SAMPLE_PUBLIC_CLIENT_ID', | ||
requested_scopes: REQUESTED_SCOPES, | ||
pkce_support: 'enabled', | ||
pkce_code_challenge_method: 'S256', | ||
auth_request_method: 'GET' | ||
}.merge(token_info) | ||
end | ||
|
||
def symmetric_confidential_access_default | ||
{ | ||
auth_type: 'symmetric', | ||
token_url: TOKEN_URL, | ||
client_id: 'SAMPLE_CONFIDENTIAL_CLIENT_ID', | ||
client_secret: 'SAMPLE_CONFIDENTIAL_CLIENT_SECRET', | ||
auth_url: AUTH_URL, | ||
requested_scopes: REQUESTED_SCOPES, | ||
pkce_support: 'enabled', | ||
pkce_code_challenge_method: 'S256', | ||
auth_request_method: 'POST', | ||
use_discovery: 'false' | ||
}.merge(token_info) | ||
end | ||
|
||
def asymmetric_confidential_access_default | ||
{ | ||
auth_type: 'asymmetric', | ||
token_url: TOKEN_URL, | ||
client_id: 'SAMPLE_CONFIDENTIAL_CLIENT_ID', | ||
requested_scopes: REQUESTED_SCOPES, | ||
pkce_support: 'disabled', | ||
auth_request_method: 'POST', | ||
encryption_algorithm: ENCRYPTION_ALGORITHM, | ||
jwks: JWKS, | ||
kid: KID | ||
}.merge(token_info) | ||
end | ||
|
||
def backend_services_access_default | ||
{ | ||
auth_type: 'backend_services', | ||
token_url: TOKEN_URL, | ||
client_id: 'SAMPLE_CONFIDENTIAL_CLIENT_ID', | ||
requested_scopes: REQUESTED_SCOPES, | ||
encryption_algorithm: ENCRYPTION_ALGORITHM, | ||
jwks: JWKS, | ||
kid: KID | ||
}.merge(token_info) | ||
end | ||
end | ||
end |
Oops, something went wrong.