udap_security_test_kit 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/lib/udap_security_test_kit/authorization_code_authentication_group.rb +44 -0
  4. data/lib/udap_security_test_kit/authorization_code_group.rb +103 -0
  5. data/lib/udap_security_test_kit/authorization_code_received_test.rb +31 -0
  6. data/lib/udap_security_test_kit/authorization_code_redirect_test.rb +74 -0
  7. data/lib/udap_security_test_kit/authorization_code_token_exchange_test.rb +103 -0
  8. data/lib/udap_security_test_kit/authorization_endpoint_field_test.rb +43 -0
  9. data/lib/udap_security_test_kit/certs/InfernoCA.key +52 -0
  10. data/lib/udap_security_test_kit/certs/InfernoCA.pem +35 -0
  11. data/lib/udap_security_test_kit/certs/TestClient.pem +32 -0
  12. data/lib/udap_security_test_kit/certs/TestClientPrivateKey.key +28 -0
  13. data/lib/udap_security_test_kit/client_credentials_authentication_group.rb +40 -0
  14. data/lib/udap_security_test_kit/client_credentials_group.rb +105 -0
  15. data/lib/udap_security_test_kit/client_credentials_token_exchange_test.rb +130 -0
  16. data/lib/udap_security_test_kit/common_assertions.rb +16 -0
  17. data/lib/udap_security_test_kit/default_cert_file_loader.rb +27 -0
  18. data/lib/udap_security_test_kit/discovery_group.rb +90 -0
  19. data/lib/udap_security_test_kit/dynamic_client_registration_group.rb +129 -0
  20. data/lib/udap_security_test_kit/generate_client_certs_test.rb +60 -0
  21. data/lib/udap_security_test_kit/grant_types_supported_field_test.rb +53 -0
  22. data/lib/udap_security_test_kit/reg_endpoint_jwt_signing_alg_values_supported_field_test.rb +29 -0
  23. data/lib/udap_security_test_kit/registration_endpoint_field_test.rb +30 -0
  24. data/lib/udap_security_test_kit/registration_failure_invalid_contents_test.rb +68 -0
  25. data/lib/udap_security_test_kit/registration_failure_invalid_jwt_signature_test.rb +70 -0
  26. data/lib/udap_security_test_kit/registration_success_contents_test.rb +64 -0
  27. data/lib/udap_security_test_kit/registration_success_test.rb +68 -0
  28. data/lib/udap_security_test_kit/scopes_supported_field_test.rb +26 -0
  29. data/lib/udap_security_test_kit/signed_metadata_contents_test.rb +89 -0
  30. data/lib/udap_security_test_kit/signed_metadata_field_test.rb +31 -0
  31. data/lib/udap_security_test_kit/signed_metadata_trust_verification_test.rb +54 -0
  32. data/lib/udap_security_test_kit/software_statement_builder.rb +32 -0
  33. data/lib/udap_security_test_kit/token_endpoint_auth_methods_supported_field_test.rb +22 -0
  34. data/lib/udap_security_test_kit/token_endpoint_auth_signing_alg_values_supported_field_test.rb +32 -0
  35. data/lib/udap_security_test_kit/token_endpoint_field_test.rb +30 -0
  36. data/lib/udap_security_test_kit/token_exchange_response_body_test.rb +30 -0
  37. data/lib/udap_security_test_kit/token_exchange_response_headers_test.rb +30 -0
  38. data/lib/udap_security_test_kit/udap_auth_extensions_required_field_test.rb +38 -0
  39. data/lib/udap_security_test_kit/udap_auth_extensions_supported_field_test.rb +31 -0
  40. data/lib/udap_security_test_kit/udap_certifications_required_field_test.rb +45 -0
  41. data/lib/udap_security_test_kit/udap_certifications_supported_field_test.rb +33 -0
  42. data/lib/udap_security_test_kit/udap_client_assertion_payload_builder.rb +15 -0
  43. data/lib/udap_security_test_kit/udap_jwt_builder.rb +30 -0
  44. data/lib/udap_security_test_kit/udap_jwt_validator.rb +71 -0
  45. data/lib/udap_security_test_kit/udap_profiles_supported_field_test.rb +47 -0
  46. data/lib/udap_security_test_kit/udap_request_builder.rb +43 -0
  47. data/lib/udap_security_test_kit/udap_versions_supported_field_test.rb +21 -0
  48. data/lib/udap_security_test_kit/udap_x509_certificate.rb +42 -0
  49. data/lib/udap_security_test_kit/version.rb +3 -0
  50. data/lib/udap_security_test_kit/well_known_endpoint_test.rb +31 -0
  51. data/lib/udap_security_test_kit.rb +63 -0
  52. metadata +124 -0
@@ -0,0 +1,35 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ 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
34
+ tsGvVZ6GCrAl5XejmwQBzyZQQw==
35
+ -----END CERTIFICATE-----
@@ -0,0 +1,32 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIFcjCCA1qgAwIBAgIUbdCfB3IJ9bdOPGQVtxJHhMxUWv0wDQYJKoZIhvcNAQEL
3
+ BQAwgYYxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEQMA4GA1UEBwwHQmVkZm9y
4
+ ZDEQMA4GA1UECgwHSW5mZXJubzEdMBsGA1UEAwwUSW5mZXJuby1VREFQLVJvb3Qt
5
+ Q0ExJzAlBgkqhkiG9w0BCQEWGGluZmVybm9AZ3JvdXBzLm1pdHJlLm9yZzAeFw0y
6
+ NDA4MTIyMzU4MTBaFw0zNDA4MTAyMzU4MTBaMGExCzAJBgNVBAYTAlVTMQswCQYD
7
+ VQQIDAJNQTEQMA4GA1UEBwwHQmVkZm9yZDEQMA4GA1UECgwHSW5mZXJubzEhMB8G
8
+ A1UEAwwYVURBUCBFeGFtcGxlIFRlc3QgQ2xpZW50MIIBIjANBgkqhkiG9w0BAQEF
9
+ AAOCAQ8AMIIBCgKCAQEAnfqzJCyeFNRhlcsrUPiO2LQtudObDHUKj4Q7fkYPUf9X
10
+ ecTMckfPKd8UJ7x8Vb5o1zmR3hsMoo1A7IkwBkmK2BXvxq243cCGO1q4w/jdL/EG
11
+ DiIZjTr7qvkawyeh9cAaApOrBlD4gnOxB05GjingDZgiT7GqBwrpEB2XJ4tw4idS
12
+ B3W9Rv0ynbgqPKgGw9hnEef+uNAvFIvSbfdz1n4xHNP0GuMuAX+edFCyxYFmDe74
13
+ 8pl3TH9dxkoM945r5tHmuJS9n1pXkTB9L5RVbqH77dIyOBobehHHpT4D3zjdSFmh
14
+ fta5NnDi5/iqRcFz7FVO79jJIoAqN+mWBlVH0yyfYQIDAQABo4H7MIH4MC8GA1Ud
15
+ EQQoMCaGJGh0dHBzOi8vaW5mZXJuby5jb20vdWRhcF9zZWN1cml0eS9hYzAxBgNV
16
+ HSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBDA6
17
+ BgNVHR8EMzAxMC+gLaArhilodHRwczovL2luZmVybm8uY29tL21vY2tfY3JsX2Vu
18
+ ZHBvaW50LmNybDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQU6Eo2
19
+ HE37gpSaW9zBGf0t7XfYnfIwHwYDVR0jBBgwFoAUNOqoPKju4u9y9JAuAfnSAcFb
20
+ NKAwDQYJKoZIhvcNAQELBQADggIBACh2uQ1Krkw6F3Gq0HG3ohCm2j1ynmLSJwGE
21
+ HvPlkiBcs8RBPxZzJOZJBMxGmjTPga2Kt6zsBlmjLg++C7C5/8JruwrMtrBuTtHx
22
+ Kky0Qw+YJm81IgATeDIU/qkJB8LcnHgkQbu3nyoyeKocx9XSW8nlEm4FkyREXxfC
23
+ rSVCoc70GGg2vSnSkRikNjxwKGnHvmEDUOW2bBbbzvTGKlTKSIF50NiNPM3Fi7vF
24
+ bOfi1aZh6m8IKVaI2KUXVFHco1qB3QDK5BUEimko+EyaWSZPvP83PE2+TIdapRrw
25
+ HxQQJEr774GUNH1/hdW0qlP4u3CMMMAjS2H4dOsRYOOmgC6iEewFEBQqTRLkEfgP
26
+ pMxYhGAVAmrglLLr4t+ZF9KOmifvB6f18qF352Bj1D0TMB+oLy67kFw3s2ah21la
27
+ 3Xm6hQt+M5mZ/EYZIOUPxMHtqVt5DSJdMENHO2cjcRARyeD/BGYnJqnf6yA1LL2V
28
+ TK+jhC/C/Dcv0hHQnVWlUGlwoFMOOzfsr2K3mXYezAuHASP8LIAyjodPpd6cLQu2
29
+ SZTVVobSebaNmZ2UeX8Bc9bcobM2bbVb2c3UeezEJWOpt5cSOeEScEiwkaktxD5p
30
+ ix1K3KkIg2yDP176ILlVqBBA0X2FqTSSvFbTa5us3XIwkDfARJBpLnA7OfmsO61+
31
+ Ij5io7+X
32
+ -----END CERTIFICATE-----
@@ -0,0 +1,28 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCd+rMkLJ4U1GGV
3
+ yytQ+I7YtC2505sMdQqPhDt+Rg9R/1d5xMxyR88p3xQnvHxVvmjXOZHeGwyijUDs
4
+ iTAGSYrYFe/GrbjdwIY7WrjD+N0v8QYOIhmNOvuq+RrDJ6H1wBoCk6sGUPiCc7EH
5
+ TkaOKeANmCJPsaoHCukQHZcni3DiJ1IHdb1G/TKduCo8qAbD2GcR5/640C8Ui9Jt
6
+ 93PWfjEc0/Qa4y4Bf550ULLFgWYN7vjymXdMf13GSgz3jmvm0ea4lL2fWleRMH0v
7
+ lFVuofvt0jI4Ght6EcelPgPfON1IWaF+1rk2cOLn+KpFwXPsVU7v2MkigCo36ZYG
8
+ VUfTLJ9hAgMBAAECggEAApTpPosYHkEGQztpvs4BD5uKL8I8g2yaOpQvoLWmZHGm
9
+ zU+hA7EWuplxq+CRq5kL/5BqSNXqU/G5AOSRC1lCUpuxKm8GWWFfEDNAV7uGadUn
10
+ gy2de0heeoHNpSjNpcV451fgcJ78IK2hU/w8fPBEQBSfYuwFWk4cVu4U3UmTE68I
11
+ O7PpCdTjk70IOsLT8uBagAOw92Fj0mGU7agCdWfJ+LjPRUtg+PhVvODatL3taG+l
12
+ FAParsomiRqKGINyn8vALXNISuBYHVDUzv93P10gG5rA2sJ7953/+++Hr9DoLpmL
13
+ SH/q/LebFzPJ2u6KzLc6bam1YX0w/MSNTJVIxA5V/QKBgQDU+iFXdShLwvEXGVtb
14
+ FdZuRk3XsN+yfkFyM9SZrmaLF2VBALkC5pd+rYkXSaTA/cbs623VOYpoJhVmjL8d
15
+ VvTlN/G+8TzfdsmOlAXiOSiUn3VKM/Othu5l9k0AgylU8aXBWTUv5FzmV8gMn+/s
16
+ 9oOucAVFa60LdkR2d609y/tKnwKBgQC95Gviall3E/+7drT05KxPPGDKRUjhCLBe
17
+ BNj2+ttSt4+v+E5v3K+LSd11VfGkvLkDvkhjiJlVamf+XgLne3TLrEThAKq8ySUr
18
+ XKBRi+nfmisUHSrMGljHw500Rx+MR/LEpfEERMosLQWTrOTz5VG2RueVHbWbD622
19
+ Witr8tnV/wKBgGDYUNr9GlLBFXJEhIc5ueUxMOp4sm/u+4Gb0fwEEvsCq3dQhdCs
20
+ 3IytCp69TR65B4DqWWpRHP/Y+XhFXg5QYVHuC46hEeYnlOWxp69EAJD8pZAVaaQp
21
+ rDRPOJqYCe5nZ9Ew6H+bnybbGcur2qTtP9nNdIgpu2lv4RfhubRVEjLPAoGAXqzb
22
+ SSii8GbNMwcNU6gLbPn6e/6tRl1RqZ6bGhCadxREFIUlfko2T6kFPDIcZ3kceYxO
23
+ hSme4WJK9RykMAtygPWj5daySauz13m4CNBMS4qO/dlI9DgSmY6i+2SWixd4J6lg
24
+ kDNH5VyREj66bAuigNG7NrJ4UBYyEt/EFG8hQrsCgYEAyLwk7f2Wgu9ykdwSrrQE
25
+ TBK0iOVUcwPhxj1UbFyDxPdO0EspyKtIFD5w/sbBtQbJGSUFd7ZPoCsYkT2yAsDp
26
+ 3cI/ubRxA+/GaqUo84QxvJ4Uqdu8YS8C0FCEnhXGjA60Y5HFzufJF5EqfzwNctCr
27
+ G0cRyX/4Ut4BNUcir/CRVL0=
28
+ -----END PRIVATE KEY-----
@@ -0,0 +1,40 @@
1
+ require_relative 'client_credentials_token_exchange_test'
2
+ require_relative 'token_exchange_response_body_test'
3
+ require_relative 'token_exchange_response_headers_test'
4
+
5
+ module UDAPSecurityTestKit
6
+ class ClientCredentialsAuthenticationGroup < Inferno::TestGroup
7
+ title 'UDAP Client Credentials Authorization & Authentication'
8
+ description %(
9
+ This group tests the use of the client_credentials grant type to authenticate to an authorization server and
10
+ receive an access token, as described
11
+ in the [business-to-business (B2B) profile requirements](https://hl7.org/fhir/us/udap-security/STU1/b2b.html).
12
+ )
13
+ id :udap_client_credentials_authentication_group
14
+
15
+ test from: :udap_client_credentials_token_exchange,
16
+ config: {
17
+ requests: {
18
+ token_exchange: {
19
+ name: :client_credentials_token_exchange
20
+ }
21
+ }
22
+ }
23
+ test from: :udap_token_exchange_response_body,
24
+ config: {
25
+ inputs: {
26
+ token_response_body: {
27
+ name: :client_credentials_token_response_body
28
+ }
29
+ }
30
+ }
31
+ test from: :udap_token_exchange_response_headers,
32
+ config: {
33
+ requests: {
34
+ token_exchange: {
35
+ name: :client_credentials_token_exchange
36
+ }
37
+ }
38
+ }
39
+ end
40
+ end
@@ -0,0 +1,105 @@
1
+ require_relative 'dynamic_client_registration_group'
2
+ require_relative 'discovery_group'
3
+ require_relative 'client_credentials_authentication_group'
4
+
5
+ module UDAPSecurityTestKit
6
+ class ClientCredentialsGroup < Inferno::TestGroup
7
+ title 'UDAP Client Credentials Flow'
8
+ description %(
9
+ This group tests UDAP servers that support JWT authentication using an OAuth2.0 client_credentials grant flow and
10
+ includes the following sub-groups.
11
+
12
+ 1. Discovery Group
13
+ 2. Dynamic Client Registration
14
+ 3. Authorization and Authentication - supports only the [Business-to-Business (B2B)](https://hl7.org/fhir/us/udap-security/STU1/b2b.html)
15
+ profile in the UDAP IG
16
+ )
17
+ id :udap_client_credentials_group
18
+
19
+ input_instructions %(
20
+ **Discovery Tests**
21
+
22
+ #{DiscoveryGroup.discovery_group_input_instructions}
23
+
24
+ **Dynamic Client Registration Tests**
25
+
26
+ #{DynamicClientRegistrationGroup.dynamic_client_registration_input_instructions}
27
+ )
28
+
29
+ group from: :udap_discovery_group,
30
+ id: :auth_code_discovery_group,
31
+ run_as_group: true,
32
+ config: {
33
+ inputs: {
34
+ required_flow_type: {
35
+ name: :flow_type_client_creds,
36
+ title: 'Required OAuth2.0 Flow Type for Client Credentials Workflow',
37
+ optional: 'false',
38
+ default: ['client_credentials'],
39
+ locked: true
40
+ }
41
+ }
42
+ }
43
+
44
+ group from: :udap_dynamic_client_registration_group,
45
+ id: :client_creds_dcr_group,
46
+ run_as_group: true,
47
+ config: {
48
+ inputs: {
49
+ udap_registration_grant_type: {
50
+ name: :reg_grant_type_client_creds,
51
+ default: 'client_credentials',
52
+ locked: true
53
+ },
54
+ udap_client_cert_pem: {
55
+ name: :udap_client_cert_pem_client_creds_flow,
56
+ title: 'Client Credentials Client Certificate(s) (PEM Format)'
57
+ },
58
+ udap_client_private_key_pem: {
59
+ name: :udap_client_private_key_client_creds_flow,
60
+ title: 'Client Credentials Client Private Key (PEM Format)'
61
+ },
62
+ udap_cert_iss: {
63
+ name: :udap_cert_iss_client_creds_flow,
64
+ title: 'Client Credentials JWT Issuer (iss) Claim'
65
+ },
66
+ udap_registration_requested_scope: {
67
+ name: :udap_registration_scope_client_creds_flow,
68
+ title: 'Client Credentials Registration Requested Scope(s)',
69
+ description: %(
70
+ String containing a space delimited list of scopes requested by the client application for use in
71
+ subsequent requests. The Authorization Server MAY consider this list when deciding the scopes that it
72
+ will allow the application to subsequently request. Apps requesting the "client_credentials" grant
73
+ type SHOULD request system scopes.
74
+ )
75
+ },
76
+ udap_registration_certifications: {
77
+ name: :udap_registration_certifications_client_creds_flow,
78
+ title: 'Client Credentials UDAP Registration Certifications'
79
+ }
80
+ },
81
+ outputs: {
82
+ udap_client_cert_pem: {
83
+ name: :udap_client_cert_pem_client_creds_flow
84
+ },
85
+ udap_client_private_key_pem: {
86
+ name: :udap_client_private_key_client_creds_flow
87
+ },
88
+ udap_cert_iss: {
89
+ name: :udap_cert_iss_client_creds_flow
90
+ }
91
+ }
92
+ } do
93
+ input_order :udap_registration_endpoint,
94
+ :reg_grant_type_client_creds,
95
+ :udap_client_cert_pem_client_creds_flow,
96
+ :udap_client_private_key_client_creds_flow,
97
+ :udap_cert_iss_client_creds_flow,
98
+ :udap_registration_scope_client_creds_flow,
99
+ :udap_jwt_signing_alg, :udap_registration_certifications_client_creds_flow
100
+ end
101
+
102
+ group from: :udap_client_credentials_authentication_group,
103
+ run_as_group: true
104
+ end
105
+ end
@@ -0,0 +1,130 @@
1
+ require_relative 'udap_client_assertion_payload_builder'
2
+
3
+ module UDAPSecurityTestKit
4
+ class ClientCredentialsTokenExchangeTest < Inferno::Test
5
+ title 'OAuth token exchange request succeeds when supplied correct information'
6
+ description %(
7
+ The [UDAP Security IG Section 5.2 on Obtaining an Access Token](https://hl7.org/fhir/us/udap-security/STU1/b2b.html#obtaining-an-access-token)
8
+ states the following:
9
+ - The client SHALL use its private key to sign an Authentication
10
+ Token ... and include this JWT in the
11
+ client_assertion parameter of its token request
12
+ - Client applications using the client credentials grant and
13
+ authenticating with a private key and
14
+ Authentication Token as per Section 5.2.1 SHALL submit a POST request to the Authorization Server’s token
15
+ endpoint
16
+ - An Authorization Server receiving token requests containin
17
+ Authentication Tokens as above SHALL validate and
18
+ respond to the request as per Sections 6 and 7 of UDAP JWT-Based Client Authentication.
19
+
20
+ Furthermore, the inclusion of an `extensions` claim in the Authentication JWT is required for B2B client apps
21
+ using the client credentials flow. Inferno provides an extensions object with the following information:
22
+ - `'version'`: `'1'`
23
+ - `'subject_name'`: `'UDAP Test Kit'`
24
+ - `'organization_name'`: `'Inferno Framework'`
25
+ - `'organization_id'`: `'https://inferno-framework.github.io/'`
26
+ - `'purpose_of_use'`: `['SYSDEV']`
27
+
28
+ This test creates an authentication JWT, POSTs a token request to the server's token endpoint, and expects a 200
29
+ response.
30
+ )
31
+ id :udap_client_credentials_token_exchange
32
+
33
+ input :udap_client_id,
34
+ title: 'Client ID',
35
+ description: 'Client ID as registered with the authorization server.'
36
+
37
+ input :udap_token_endpoint,
38
+ title: 'Token Endpoint',
39
+ description: 'The full URL from which Inferno will request an access token'
40
+
41
+ input :udap_client_cert_pem_client_creds_flow,
42
+ title: 'X.509 Client Certificate(s) (PEM Format)',
43
+ type: 'textarea',
44
+ description: %(
45
+ A list of one or more X.509 certificates in PEM format separated by a newline. The first (leaf) certificate
46
+ MUST represent the client entity Inferno registered as,
47
+ and the trust chain that will be built from the provided certificate(s) must resolve to a CA trusted by the
48
+ authorization server under test.
49
+ )
50
+
51
+ input :udap_client_private_key_client_creds_flow,
52
+ type: 'textarea',
53
+ title: 'Client Private Key (PEM Format)',
54
+ description: 'The private key corresponding to the X.509 client certificate'
55
+
56
+ input :udap_jwt_signing_alg,
57
+ title: 'JWT Signing Algorithm',
58
+ description: %(
59
+ Algorithm used to sign UDAP JSON Web Tokens (JWTs). UDAP Implementations SHALL support
60
+ RS256.
61
+ ),
62
+ type: 'radio',
63
+ options: {
64
+ list_options: [
65
+ {
66
+ label: 'RS256',
67
+ value: 'RS256'
68
+ }
69
+ ]
70
+ },
71
+ default: 'RS256',
72
+ locked: true
73
+
74
+ output :token_retrieval_time
75
+ output :client_credentials_token_response_body
76
+ makes_request :token_exchange
77
+
78
+ run do
79
+ # SYSDEV purpose of use definition:
80
+ # "To perform one or more operations on information to design, develop
81
+ # implement, test, or deploy a healthcare system or application."
82
+ # See https://terminology.hl7.org/5.5.0/ValueSet-v3-PurposeOfUse.html
83
+ extensions = {
84
+ 'hl7-b2b' => {
85
+ 'version' => '1',
86
+ 'subject_name' => 'UDAP Test Kit',
87
+ 'organization_name' => 'Inferno Framework',
88
+ 'organization_id' => 'https://inferno-framework.github.io/',
89
+ 'purpose_of_use' => ['SYSDEV']
90
+ }
91
+ }
92
+
93
+ client_assertion_payload = UDAPClientAssertionPayloadBuilder.build(
94
+ udap_client_id,
95
+ udap_token_endpoint,
96
+ extensions.to_json
97
+ )
98
+
99
+ x5c_certs = UDAPJWTBuilder.split_user_input_cert_string(
100
+ udap_client_cert_pem_client_creds_flow
101
+ )
102
+
103
+ client_assertion_jwt = UDAPJWTBuilder.encode_jwt_with_x5c_header(
104
+ client_assertion_payload,
105
+ udap_client_private_key_client_creds_flow,
106
+ udap_jwt_signing_alg,
107
+ x5c_certs
108
+ )
109
+
110
+ token_exchange_headers, token_exchange_body = UDAPRequestBuilder.build_token_exchange_request(
111
+ client_assertion_jwt,
112
+ 'client_credentials',
113
+ nil,
114
+ nil
115
+ )
116
+
117
+ post(udap_token_endpoint,
118
+ body: token_exchange_body,
119
+ name: :token_exchange,
120
+ headers: token_exchange_headers)
121
+
122
+ assert_response_status(200)
123
+ assert_valid_json(request.response_body)
124
+
125
+ output token_retrieval_time: Time.now.iso8601
126
+
127
+ output client_credentials_token_response_body: request.response_body
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,16 @@
1
+ # Module for assertion methods that are used across multiple tests
2
+ module CommonAssertions
3
+ extend Inferno::DSL::Assertions
4
+
5
+ def self.assert_array_of_strings(config, field)
6
+ values = config[field]
7
+
8
+ assert values.is_a?(Array), "`#{field}` should be an Array, but found #{values.class.name}"
9
+
10
+ non_string_values = values.reject { |value| value.is_a?(String) }
11
+
12
+ assert non_string_values.blank?,
13
+ "`#{field}` should be an Array of strings, but found
14
+ #{non_string_values.map(&:class).map(&:name).join(', ')}"
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ module UDAPSecurityTestKit
2
+ class DefaultCertFileLoader
3
+ def self.load_default_ca_pem_file
4
+ raw_cert = File.read(File.join(File.dirname(__FILE__), 'certs/InfernoCA.pem'))
5
+ cert = OpenSSL::X509::Certificate.new raw_cert
6
+ cert.to_pem
7
+ end
8
+
9
+ def self.load_default_ca_private_key_file
10
+ raw_key = File.read(File.join(File.dirname(__FILE__), 'certs/InfernoCA.key'))
11
+ private_key = OpenSSL::PKey::RSA.new raw_key
12
+ private_key.to_pem
13
+ end
14
+
15
+ def self.load_test_client_cert_pem_file
16
+ raw_cert = File.read(File.join(File.dirname(__FILE__), 'certs/TestClient.pem'))
17
+ cert = OpenSSL::X509::Certificate.new raw_cert
18
+ cert.to_pem
19
+ end
20
+
21
+ def self.load_test_client_private_key_file
22
+ raw_key = File.read(File.join(File.dirname(__FILE__), 'certs/TestClientPrivateKey.key'))
23
+ key = OpenSSL::PKey::RSA.new raw_key
24
+ key.to_pem
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,90 @@
1
+ require 'jwt'
2
+ require_relative 'authorization_endpoint_field_test'
3
+ require_relative 'grant_types_supported_field_test'
4
+ require_relative 'reg_endpoint_jwt_signing_alg_values_supported_field_test'
5
+ require_relative 'registration_endpoint_field_test'
6
+ require_relative 'scopes_supported_field_test'
7
+ require_relative 'signed_metadata_contents_test'
8
+ require_relative 'signed_metadata_field_test'
9
+ require_relative 'token_endpoint_auth_methods_supported_field_test'
10
+ require_relative 'token_endpoint_auth_signing_alg_values_supported_field_test'
11
+ require_relative 'token_endpoint_field_test'
12
+ require_relative 'udap_auth_extensions_required_field_test'
13
+ require_relative 'udap_auth_extensions_supported_field_test'
14
+ require_relative 'udap_certifications_required_field_test'
15
+ require_relative 'udap_certifications_supported_field_test'
16
+ require_relative 'udap_profiles_supported_field_test'
17
+ require_relative 'udap_versions_supported_field_test'
18
+ require_relative 'well_known_endpoint_test'
19
+ require_relative 'signed_metadata_trust_verification_test'
20
+ module UDAPSecurityTestKit
21
+ class DiscoveryGroup < Inferno::TestGroup
22
+ include Inferno::DSL::Assertions
23
+
24
+ title 'UDAP Discovery'
25
+ description %(
26
+ Verify that server configuration is made available and conforms with [the
27
+ discovery
28
+ requirements](https://hl7.org/fhir/us/udap-security/STU1/discovery.html).
29
+ )
30
+ id :udap_discovery_group
31
+
32
+ input :required_flow_type,
33
+ title: 'Required Supported OAuth2.0 Grant Type(s)',
34
+ description: 'Which grant type(s) must be supported per the returned Discovery metadata',
35
+ type: 'checkbox',
36
+ optional: 'true',
37
+ options: {
38
+ list_options: [
39
+ {
40
+ label: 'Authorization Code',
41
+ value: 'authorization_code'
42
+ },
43
+ {
44
+ label: 'Client Credentials',
45
+ value: 'client_credentials'
46
+ }
47
+ ]
48
+ }
49
+
50
+ def self.discovery_group_input_instructions
51
+ %(
52
+ Inferno currently does not support the use of the Authority Information Access (AIA) extension to access issuing
53
+ certificates. As such, Inferno must be provided any intermediate server certificates needed to establish a
54
+ trust chain. If the intermediate CAs are not included in the x5c header of the server's signed metadata JWT,
55
+ testers may include them along with the root CA as a trust anchor input.
56
+ )
57
+ end
58
+ input_instructions discovery_group_input_instructions
59
+
60
+ output :udap_registration_certficiations_required
61
+ output :udap_registration_endpoint
62
+ output :udap_registration_grant_type
63
+
64
+ test from: :udap_well_known_endpoint
65
+ test from: :udap_versions_supported_field
66
+ test from: :udap_grant_types_supported_field
67
+ test from: :udap_profiles_supported_field
68
+ test from: :udap_auth_extensions_supported_field
69
+ test from: :udap_auth_extensions_required_field
70
+ test from: :udap_certifications_supported_field
71
+ test from: :udap_certifications_required_field
72
+ test from: :udap_scopes_supported_field
73
+ test from: :udap_authorization_endpoint_field
74
+ test from: :udap_token_endpoint_field
75
+ test from: :udap_token_endpoint_auth_methods_supported_field
76
+ test from: :udap_token_endpoint_auth_signing_alg_values_supported_field
77
+ test from: :udap_registration_endpoint_field
78
+ test from: :udap_reg_endpoint_jwt_signing_alg_values_supported_field
79
+ test from: :udap_signed_metadata_field
80
+ test from: :udap_signed_metadata_contents
81
+ test from: :udap_signed_metadata_trust_verification, optional: true,
82
+ config: {
83
+ inputs: {
84
+ udap_server_trust_anchor_certs: {
85
+ optional: true
86
+ }
87
+ }
88
+ }
89
+ end
90
+ end
@@ -0,0 +1,129 @@
1
+ require_relative 'registration_failure_invalid_contents_test'
2
+ require_relative 'registration_failure_invalid_jwt_signature_test'
3
+ require_relative 'registration_success_test'
4
+ require_relative 'registration_success_contents_test'
5
+
6
+ module UDAPSecurityTestKit
7
+ class DynamicClientRegistrationGroup < Inferno::TestGroup
8
+ title 'UDAP Dynamic Client Registration'
9
+ description %(
10
+ Generate and sign a software statement to register the client with the authorization server as described in the
11
+ [dynamic client registration requirements](https://hl7.org/fhir/us/udap-security/STU1/registration.html).
12
+ )
13
+ id :udap_dynamic_client_registration_group
14
+
15
+ def self.dynamic_client_registration_input_instructions
16
+ %(
17
+ Testers must provide a client certificate and any additional CAs needed for the authorization server under test to
18
+ establish a trust chain.
19
+
20
+ Cancelling a UDAP client's registration is not a required server capability and as such the Inferno client has no
21
+ way of resetting state on the authorization server after a successful registration attempt. Testers wishing to
22
+ run the Dynamic Client Registration tests more than once must do one of the following:
23
+ - Remove the Inferno test client's registration out-of-band before re-running tests, to register the original
24
+ client URI anew
25
+ - Specifiy a different client URI as the issuer input (if the client cert has more than one Subject Alternative
26
+ Name (SAN) URI entry), to register a different logical client with the original certificate
27
+ - Provide a different client certificate and its associated URI to register a new logical client
28
+ )
29
+ end
30
+
31
+ input_instructions dynamic_client_registration_input_instructions
32
+
33
+ input :udap_registration_endpoint,
34
+ title: 'UDAP Dynamic Client Registration Endpoint',
35
+ description: %(
36
+ The absolute URL of the dynamic client registration endpoint.
37
+ )
38
+
39
+ input :udap_registration_grant_type,
40
+ title: 'Client Registration Grant Type',
41
+ description: %(
42
+ The OAuth2.0 grant type for which this client will register itself. A given client may register as either
43
+ option, but not both.
44
+ ),
45
+ type: 'radio',
46
+ options: {
47
+ list_options: [
48
+ {
49
+ label: 'Authorization Code',
50
+ value: 'authorization_code'
51
+ },
52
+ {
53
+ label: 'Client Credentials',
54
+ value: 'client_credentials'
55
+ }
56
+ ]
57
+ }
58
+
59
+ input :udap_client_cert_pem,
60
+ title: 'X.509 Client Certificate(s) (PEM Format)',
61
+ description: %(
62
+ A list of one or more X.509 certificates in PEM format separated by a newline. The first (leaf) certificate
63
+ MUST represent the client entity Inferno will register as,
64
+ and the trust chain that will be built from the provided certificate(s) must resolve to a CA trusted by the
65
+ authorization server under test.
66
+ ),
67
+ type: 'textarea',
68
+ optional: false
69
+
70
+ input :udap_client_private_key_pem,
71
+ title: 'Client Private Key (PEM Format)',
72
+ description: %(
73
+ The private key corresponding to the client certificate used for registration, in PEM format. Used to sign
74
+ registration and/or authentication JWTs.
75
+ ),
76
+ type: 'textarea',
77
+ optional: false
78
+
79
+ input :udap_cert_iss,
80
+ title: 'JWT Issuer (iss) Claim',
81
+ description: %(
82
+ MUST correspond to a unique URI entry in the Subject Alternative Name (SAN) extension of the client
83
+ certificate used for registration.
84
+ ),
85
+ optional: false
86
+
87
+ input :udap_jwt_signing_alg,
88
+ title: 'JWT Signing Algorithm',
89
+ description: %(
90
+ Algorithm used to sign UDAP JSON Web Tokens (JWTs). UDAP Implementations SHALL support
91
+ RS256.
92
+ ),
93
+ type: 'radio',
94
+ options: {
95
+ list_options: [
96
+ {
97
+ label: 'RS256',
98
+ value: 'RS256'
99
+ }
100
+ ]
101
+ },
102
+ default: 'RS256',
103
+ locked: true
104
+
105
+ input :udap_registration_requested_scope,
106
+ title: 'Scope(s) Requested',
107
+ description: %(
108
+ String containing a space delimited list of scopes requested by the client application for use in
109
+ subsequent requests. The Authorization Server MAY consider this list when deciding the scopes that it will
110
+ allow the application to subsequently request. Apps requesting the "client_credentials" grant type SHOULD
111
+ request system scopes; apps requesting
112
+ the "authorization_code" grant type SHOULD request user or patient scopes.
113
+ )
114
+
115
+ input :udap_registration_certifications,
116
+ title: 'UDAP Certifications',
117
+ description: %(
118
+ Additional UDAP certifications to include in registration request, if required by the authorization server.
119
+ Include a space separated list of strings representing a Base64-encoded, signed JWT.
120
+ ),
121
+ type: 'textarea',
122
+ optional: true
123
+
124
+ test from: :udap_registration_failure_invalid_contents
125
+ test from: :udap_registration_failure_invalid_jwt_signature
126
+ test from: :udap_registration_success
127
+ test from: :udap_registration_success_contents
128
+ end
129
+ end