auth0 4.7.0 → 4.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +23 -0
  3. data/.env.example +2 -0
  4. data/.github/CODEOWNERS +1 -0
  5. data/.github/stale.yml +20 -0
  6. data/.gitignore +0 -1
  7. data/.rubocop.yml +2 -0
  8. data/CHANGELOG.md +83 -0
  9. data/DEPLOYMENT.md +25 -3
  10. data/Gemfile +3 -1
  11. data/Gemfile.lock +231 -0
  12. data/README.md +114 -25
  13. data/auth0.gemspec +6 -6
  14. data/codecov.yml +22 -0
  15. data/deploy_documentation.sh +1 -1
  16. data/lib/auth0.rb +1 -0
  17. data/lib/auth0/algorithm.rb +5 -0
  18. data/lib/auth0/api/authentication_endpoints.rb +38 -2
  19. data/lib/auth0/api/v2.rb +6 -0
  20. data/lib/auth0/api/v2/anomaly.rb +36 -0
  21. data/lib/auth0/api/v2/client_grants.rb +5 -1
  22. data/lib/auth0/api/v2/guardian.rb +142 -0
  23. data/lib/auth0/api/v2/jobs.rb +22 -3
  24. data/lib/auth0/api/v2/roles.rb +172 -0
  25. data/lib/auth0/api/v2/users.rb +115 -4
  26. data/lib/auth0/exception.rb +35 -7
  27. data/lib/auth0/mixins.rb +8 -3
  28. data/lib/auth0/mixins/httpproxy.rb +11 -8
  29. data/lib/auth0/mixins/permission_struct.rb +3 -0
  30. data/lib/auth0/mixins/validation.rb +340 -0
  31. data/lib/auth0/version.rb +1 -1
  32. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Anomaly/_check_if_ip_is_blocked/should_return_200_response_code.yml +65 -0
  33. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Anomaly/_remove_ip_block/should_remove_an_IP_successfully.yml +60 -0
  34. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_client_grants/should_return_at_least_1_result.yml +1 -1
  35. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_client_grants/should_return_the_first_page_of_one_result.yml +1 -1
  36. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_client_grants/should_return_the_test_client_grant.yml +1 -1
  37. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_delete_client_grant/should_delete_the_test_client_grant.yml +1 -1
  38. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_patch_client_grant/should_update_the_test_client_grant.yml +1 -1
  39. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/create_test_client.yml +1 -1
  40. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/create_test_client_grant.yml +1 -1
  41. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/delete_test_client.yml +1 -1
  42. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/delete_test_client_grant.yml +1 -1
  43. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_client/_filters/should_exclude_and_include_fields_properly.yml +1 -1
  44. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_client/_filters/should_include_the_specified_fields.yml +1 -1
  45. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_client/should_get_the_test_client.yml +1 -1
  46. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_exclude_fields_not_specified.yml +1 -1
  47. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_exclude_the_specified_fields.yml +1 -1
  48. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_include_the_specified_fields.yml +1 -1
  49. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_paginate_results.yml +1 -1
  50. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/should_get_at_least_one_client.yml +1 -1
  51. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_delete_client/should_delete_the_test_client_without_an_error.yml +1 -1
  52. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_patch_client/should_update_the_client_with_the_correct_attributes.yml +1 -1
  53. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/create_test_client.yml +1 -1
  54. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connection/_filters/should_exclude_the_fields_indicated.yml +1 -1
  55. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connection/_filters/should_include_the_fields_indicated.yml +1 -1
  56. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connection/should_find_the_correct_connection.yml +1 -1
  57. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/_filters/should_include_previously-created_connection_when_filtered.yml +1 -1
  58. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/_filters/should_should_exclude_the_fields_indicated_from_filtered_results.yml +1 -1
  59. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/_filters/should_should_include_the_fields_indicated_from_filtered_results.yml +1 -1
  60. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/should_include_the_previously_created_connection.yml +1 -1
  61. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/should_not_be_empty.yml +1 -1
  62. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_delete_connection/should_delete_the_connection.yml +1 -1
  63. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_delete_connection_user/should_delete_the_user_created.yml +2 -2
  64. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_update_connection/should_update_the_connection.yml +1 -1
  65. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/create_test_connection.yml +1 -1
  66. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/create_test_user.yml +1 -1
  67. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/create_test_user.yml +1 -1
  68. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/delete_test_credential.yml +1 -1
  69. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/delete_test_user.yml +1 -1
  70. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_configure_provider/should_configure_a_new_email_provider.yml +1 -1
  71. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_delete_provider/should_delete_the_existing_email_provider_without_an_error.yml +1 -1
  72. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_delete_provider/should_throw_an_error_trying_to_get_the_email_provider.yml +1 -1
  73. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_get_provider/_filters/should_get_the_existing_email_provider_with_specific_fields.yml +1 -1
  74. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_get_provider/_filters/should_get_the_existing_email_provider_without_specific_fields.yml +1 -1
  75. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_get_provider/should_get_the_existing_email_provider.yml +1 -1
  76. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_update_provider/should_update_the_existing_email_provider.yml +1 -1
  77. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/delete_existing_provider.yml +1 -1
  78. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_log/should_match_the_created_log_entry.yml +2 -2
  79. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_log/should_not_be_empty.yml +2 -2
  80. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_exclude_fields_not_specified.yml +1 -1
  81. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_exclude_the_specified_fields.yml +1 -1
  82. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_have_one_log_entry.yml +1 -1
  83. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_include_the_specified_fields.yml +1 -1
  84. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_from/should_take_one_log_entry.yml +2 -2
  85. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/create_test_user.yml +1 -1
  86. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/delete_test_disabled_rule.yml +1 -1
  87. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/delete_test_enabled_rule.yml +1 -1
  88. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/delete_test_user.yml +1 -1
  89. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_add_role_permissions/should_add_a_Permission_to_the_Role_successfully.yml +69 -0
  90. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_add_role_users/should_add_a_User_to_the_Role_successfully.yml +69 -0
  91. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_delete_role/should_delete_the_Role_successfully.yml +62 -0
  92. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role/should_get_the_Role_successfully.yml +67 -0
  93. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_permissions/should_get_exactly_1_Permission.yml +67 -0
  94. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_permissions/should_get_the_added_Permission_from_the_Role_successfully.yml +67 -0
  95. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_users/should_get_exactly_1_User.yml +67 -0
  96. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_users/should_get_the_added_User_from_the_Role_successfully.yml +67 -0
  97. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_roles/should_get_the_Role_successfully.yml +67 -0
  98. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_remove_role_permissions/should_remove_a_Permission_from_the_Role_successfully.yml +64 -0
  99. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_update_role/should_update_the_Role_successfully.yml +69 -0
  100. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/create_test_api.yml +69 -0
  101. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/create_test_role.yml +69 -0
  102. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/create_test_user.yml +69 -0
  103. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/delete_test_api.yml +62 -0
  104. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/delete_test_user.yml +62 -0
  105. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_delete_rule/should_delete_the_test_disabled_rule_without_an_error.yml +1 -1
  106. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_delete_rule/should_delete_the_test_enabled_rule_without_an_error.yml +1 -1
  107. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/_filters/should_exclude_the_fields_not_specified.yml +1 -1
  108. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/_filters/should_exclude_the_specified_fields.yml +1 -1
  109. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/_filters/should_include_the_specified_fields.yml +1 -1
  110. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/should_get_a_specific_rule.yml +1 -1
  111. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_exclude_fields_not_specified.yml +1 -1
  112. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_include_the_specified_fields.yml +1 -1
  113. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_return_at_least_1_disabled_rule.yml +1 -1
  114. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_return_at_least_1_enabled_rule.yml +1 -1
  115. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_return_paginated_results.yml +2 -2
  116. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/should_return_at_least_1_rule.yml +1 -1
  117. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_update_rule/should_update_the_disabled_rule_to_be_enabled.yml +1 -1
  118. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/create_test_disabled_rule.yml +1 -1
  119. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/create_test_enabled_rule.yml +1 -1
  120. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Stats/_active_users/should_have_at_least_one_active_user.yml +1 -1
  121. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Stats/_daily_stats/should_have_at_least_one_stats_entry_for_the_timeframe.yml +1 -1
  122. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_get_tenant_settings/should_get_the_tenant_settings.yml +1 -1
  123. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_get_tenant_settings_with_specific_fields/should_exclude_a_field_not_requested.yml +1 -1
  124. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_get_tenant_settings_with_specific_fields/should_include_the_field_requested.yml +1 -1
  125. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_update_tenant_settings/should_revert_the_tenant_name.yml +1 -1
  126. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_update_tenant_settings/should_update_the_tenant_settings_with_a_new_tenant_name.yml +1 -1
  127. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/_post_email_verification/should_create_an_email_verification_ticket.yml +1 -1
  128. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/_post_password_change/should_create_a_password_change_ticket.yml +1 -1
  129. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/create_test_user.yml +1 -1
  130. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/delete_test_user.yml +1 -1
  131. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_add_user_permissions/should_add_a_Permissions_for_a_User_successfully.yml +67 -0
  132. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_add_user_roles/should_add_a_Role_to_a_User_successfully.yml +62 -0
  133. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_delete_user/{should_delete_the_user_successfully.yml → should_delete_the_User_successfully.yml} +14 -8
  134. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_delete_user/should_delete_the_secondary_User_successfully.yml +60 -0
  135. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_delete_user_provider/should_attempt_to_delete_the_MFA_provider_for_the_User.yml +60 -0
  136. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_enrollments/should_get_Enrollments_for_a_User_successfully.yml +65 -0
  137. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_user_permissions/should_get_exactly_1_Permission_for_a_User_successfully.yml +65 -0
  138. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_user_permissions/should_get_the_correct_Permission_for_a_User_successfully.yml +65 -0
  139. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_user_roles/should_get_Roles_for_a_User_successfully.yml +65 -0
  140. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_invalidate_browsers/should_invalidate_MFA_browsers_for_the_User_successfully.yml +62 -0
  141. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_link_user_account/should_link_two_Users_successfully.yml +67 -0
  142. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_patch_user/should_patch_the_User_successfully.yml +68 -0
  143. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_remove_user_permissions/should_remove_a_Permission_from_a_User_successfully.yml +62 -0
  144. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_remove_user_roles/should_remove_a_Role_from_a_User_successfully.yml +62 -0
  145. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_unlink_user_account/should_unlink_two_Users_successfully.yml +65 -0
  146. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/_filters/should_exclude_fields_not_indicated.yml +15 -10
  147. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/_filters/should_exclude_the_fields_indicated.yml +15 -13
  148. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/_filters/should_include_the_fields_indicated.yml +15 -13
  149. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/should_retrieve_the_created_user.yml +15 -16
  150. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user_logs/should_get_Logs_for_a_User_successfully.yml +69 -0
  151. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/is_expected_to_find_a_user_with_a_v2_search_engine_query.yml +14 -8
  152. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/is_expected_to_find_a_user_with_a_v3_search_engine_query.yml +14 -8
  153. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_exclude_the_indicated_fields_when_paginated.yml +13 -7
  154. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_include_the_indicated_fields_when_paginated.yml +13 -7
  155. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_not_include_other_fields_when_paginated.yml +13 -7
  156. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_return_the_correct_number_of_results_when_paginated.yml +13 -7
  157. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/should_have_at_least_one_user.yml +13 -7
  158. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_secondary_test_user.yml +67 -0
  159. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_test_api.yml +67 -0
  160. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_test_role.yml +67 -0
  161. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_test_user.yml +15 -16
  162. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/delete_test_api.yml +60 -0
  163. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/delete_test_role.yml +60 -0
  164. data/spec/integration/lib/auth0/api/v2/api_anomaly_spec.rb +17 -0
  165. data/spec/integration/lib/auth0/api/v2/api_roles_spec.rb +145 -0
  166. data/spec/integration/lib/auth0/api/v2/api_users_spec.rb +150 -32
  167. data/spec/integration/lib/auth0/auth0_client_spec.rb +3 -4
  168. data/spec/lib/auth0/api/authentication_endpoints_spec.rb +37 -10
  169. data/spec/lib/auth0/api/v2/anomaly_spec.rb +26 -0
  170. data/spec/lib/auth0/api/v2/client_grants_spec.rb +17 -0
  171. data/spec/lib/auth0/api/v2/guardian_spec.rb +154 -0
  172. data/spec/lib/auth0/api/v2/jobs_spec.rb +33 -1
  173. data/spec/lib/auth0/api/v2/roles_spec.rb +362 -0
  174. data/spec/lib/auth0/api/v2/users_spec.rb +406 -66
  175. data/spec/lib/auth0/mixins/httpproxy_spec.rb +81 -2
  176. data/spec/lib/auth0/mixins/validation_spec.rb +474 -0
  177. data/spec/spec_helper.rb +11 -7
  178. data/spec/support/credentials.rb +4 -13
  179. data/spec/support/dummy_class.rb +1 -1
  180. data/spec/support/stub_response.rb +1 -1
  181. metadata +145 -23
  182. data/.travis.yml +0 -18
  183. data/build_travis.sh +0 -7
  184. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_patch_user/should_patch_email_verified_and_return_the_updated_data.yml +0 -68
  185. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_patch_user/should_patch_user_metadata_and_return_the_updated_user.yml +0 -69
@@ -1,14 +1,19 @@
1
1
  require 'base64'
2
2
  require 'rest-client'
3
3
  require 'uri'
4
- require 'auth0/mixins/httpproxy'
5
- require 'auth0/mixins/initializer'
6
- require 'auth0/mixins/headers'
4
+
7
5
  require 'auth0/mixins/access_token_struct'
8
6
  require 'auth0/mixins/api_token_struct'
7
+ require 'auth0/mixins/headers'
8
+ require 'auth0/mixins/httpproxy'
9
+ require 'auth0/mixins/initializer'
10
+ require 'auth0/mixins/permission_struct'
11
+ require 'auth0/mixins/validation'
12
+
9
13
  require 'auth0/api/authentication_endpoints'
10
14
  require 'auth0/api/v1'
11
15
  require 'auth0/api/v2'
16
+
12
17
  module Auth0
13
18
  # Collecting dependencies here
14
19
  module Mixins
@@ -6,7 +6,7 @@ module Auth0
6
6
  attr_accessor :headers, :base_uri, :timeout
7
7
 
8
8
  # proxying requests from instance methods to HTTP class methods
9
- %i(get post post_file put patch delete).each do |method|
9
+ %i(get post post_file put patch delete delete_with_body).each do |method|
10
10
  define_method(method) do |path, body = {}, extra_headers = {}|
11
11
  safe_path = URI.escape(path)
12
12
  body = body.delete_if { |_, v| v.nil? }
@@ -20,6 +20,8 @@ module Auth0
20
20
  call(:get, url(safe_path), timeout, get_headers)
21
21
  elsif method == :delete
22
22
  call(:delete, url(safe_path), timeout, add_headers({params: body}))
23
+ elsif method == :delete_with_body
24
+ call(:delete, url(safe_path), timeout, headers, body)
23
25
  elsif method == :post_file
24
26
  body.merge!(multipart: true)
25
27
  call(:post, url(safe_path), timeout, headers, body)
@@ -28,12 +30,13 @@ module Auth0
28
30
  end
29
31
  case result.code
30
32
  when 200...226 then safe_parse_json(result.body)
31
- when 400 then raise Auth0::BadRequest, result.to_s
32
- when 401 then raise Auth0::Unauthorized, result.body
33
- when 403 then raise Auth0::AccessDenied, result.body
34
- when 404 then raise Auth0::NotFound, result.body
35
- when 500 then raise Auth0::ServerError, result.body
36
- else raise Auth0::Unsupported, result.body
33
+ when 400 then raise Auth0::BadRequest.new(result.body, code: result.code, headers: result.headers)
34
+ when 401 then raise Auth0::Unauthorized.new(result.body, code: result.code, headers: result.headers)
35
+ when 403 then raise Auth0::AccessDenied.new(result.body, code: result.code, headers: result.headers)
36
+ when 404 then raise Auth0::NotFound.new(result.body, code: result.code, headers: result.headers)
37
+ when 429 then raise Auth0::RateLimitEncountered.new(result.body, code: result.code, headers: result.headers)
38
+ when 500 then raise Auth0::ServerError.new(result.body, code: result.code, headers: result.headers)
39
+ else raise Auth0::Unsupported.new(result.body, code: result.code, headers: result.headers)
37
40
  end
38
41
  end
39
42
  end
@@ -65,7 +68,7 @@ module Auth0
65
68
  rescue RestClient::Exception => e
66
69
  case e
67
70
  when RestClient::RequestTimeout
68
- raise Auth0::RequestTimeout
71
+ raise Auth0::RequestTimeout.new(e.message)
69
72
  else
70
73
  return e.response
71
74
  end
@@ -0,0 +1,3 @@
1
+ Permission = Struct.new :permission_name, :resource_server_identifier do
2
+
3
+ end
@@ -0,0 +1,340 @@
1
+ require 'zache'
2
+
3
+ class Zache
4
+ def last(key)
5
+ @hash[key][:value] if @hash.key?(key)
6
+ end
7
+ end
8
+
9
+ module Auth0
10
+ module Mixins
11
+ # Module to provide validation for specific data structures.
12
+ module Validation
13
+
14
+ # Check a roles array
15
+ def validate_strings_array(strings)
16
+ raise Auth0::InvalidParameter, 'Must supply an array of strings' unless strings.kind_of?(Array)
17
+ raise Auth0::MissingParameter, 'Must supply an array of strings' if strings.empty?
18
+ raise Auth0::InvalidParameter, 'All array elements must be strings' unless strings.all? {|str| str.is_a? String}
19
+ end
20
+
21
+ # Check a permissions array
22
+ def validate_permissions_array(permissions)
23
+ raise Auth0::InvalidParameter, 'Must supply an array of Permissions' unless permissions.kind_of?(Array)
24
+ raise Auth0::MissingParameter, 'Must supply an array of Permissions' if permissions.empty?
25
+ raise Auth0::InvalidParameter, 'All array elements must be Permissions' unless permissions.all? do |permission|
26
+ permission.kind_of? Permission
27
+ end
28
+ permissions.map { |permission| permission.to_h }
29
+ end
30
+
31
+ # rubocop:disable Metrics/ClassLength
32
+ class IdTokenValidator
33
+ def initialize(context)
34
+ @context = context
35
+ end
36
+
37
+ def validate(id_token)
38
+ decoding_error = 'ID token could not be decoded'
39
+
40
+ unless !id_token.to_s.empty? && id_token.split('.').count == 3
41
+ raise Auth0::InvalidIdToken, decoding_error
42
+ end
43
+
44
+ begin
45
+ header = JWT::JSON.parse(JWT::Base64.url_decode(id_token.split('.').first))
46
+ rescue
47
+ raise Auth0::InvalidIdToken, decoding_error
48
+ end
49
+
50
+ claims = decode_and_validate_signature(id_token, header)
51
+ validate_claims(claims)
52
+ end
53
+
54
+ private
55
+
56
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
57
+ def decode_and_validate_signature(id_token, header)
58
+ algorithm = @context[:algorithm]
59
+
60
+ unless algorithm.is_a?(Auth0::Mixins::Validation::JWTAlgorithm)
61
+ raise Auth0::InvalidIdToken, "Signature algorithm of \"#{algorithm}\" is not supported"
62
+ end
63
+
64
+ # The expiration verification will be performed in the validate_claims method
65
+ options = { algorithms: [algorithm.name], verify_expiration: false, verify_not_before: false }
66
+ secret = nil
67
+
68
+ case algorithm
69
+ when Auth0::Algorithm::RS256
70
+ kid = header['kid']
71
+ jwks = JSON.parse(JSON[algorithm.jwks], symbolize_names: true)
72
+
73
+ if !jwks[:keys].find { |key| key[:kid] == kid } && !algorithm.fetched_jwks?
74
+ jwks = JSON.parse(JSON[algorithm.jwks(force: true)], symbolize_names: true)
75
+ end
76
+
77
+ options[:jwks] = jwks
78
+ when Auth0::Algorithm::HS256
79
+ secret = algorithm.secret
80
+ end
81
+
82
+ begin
83
+ result = JWT.decode(id_token, secret, true, options)
84
+ result.first
85
+ rescue JWT::VerificationError
86
+ raise Auth0::InvalidIdToken, 'Invalid ID token signature'
87
+ rescue JWT::IncorrectAlgorithm
88
+ alg = header['alg']
89
+ raise Auth0::InvalidIdToken, "Signature algorithm of \"#{alg}\" is not supported. Expected the ID token"\
90
+ " to be signed with \"#{algorithm.name}\""
91
+ rescue JWT::DecodeError
92
+ raise Auth0::InvalidIdToken, "Could not find a public key for Key ID (kid) \"#{kid}\""
93
+ end
94
+ end
95
+
96
+ # rubocop:disable Metrics/PerceivedComplexity
97
+ def validate_claims(claims)
98
+ leeway = @context[:leeway]
99
+ nonce = @context[:nonce]
100
+ issuer = @context[:issuer]
101
+ audience = @context[:audience]
102
+ max_age = @context[:max_age]
103
+
104
+ raise Auth0::InvalidParameter, 'Must supply a valid leeway' unless leeway.is_a?(Integer) && leeway >= 0
105
+ raise Auth0::InvalidParameter, 'Must supply a valid nonce' unless nonce.nil? || !nonce.to_s.empty?
106
+ raise Auth0::InvalidParameter, 'Must supply a valid issuer' unless issuer.nil? || !issuer.to_s.empty?
107
+ raise Auth0::InvalidParameter, 'Must supply a valid audience' unless audience.nil? || !audience.to_s.empty?
108
+
109
+ unless max_age.nil? || (max_age.is_a?(Integer) && max_age >= 0)
110
+ raise Auth0::InvalidParameter, 'Must supply a valid max_age'
111
+ end
112
+
113
+ validate_iss(claims, issuer)
114
+ validate_sub(claims)
115
+ validate_aud(claims, audience)
116
+ validate_exp(claims, leeway)
117
+ validate_iat(claims, leeway)
118
+ validate_nonce(claims, nonce) if nonce
119
+ validate_azp(claims, audience) if claims['aud'].is_a?(Array) && claims['aud'].count > 1
120
+ validate_auth_time(claims, max_age, leeway) if max_age
121
+ end
122
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
123
+
124
+ def validate_iss(claims, expected)
125
+ unless claims.key?('iss') && claims['iss'].is_a?(String)
126
+ raise Auth0::InvalidIdToken, 'Issuer (iss) claim must be a string present in the ID token'
127
+ end
128
+
129
+ unless expected == claims['iss']
130
+ raise Auth0::InvalidIdToken, "Issuer (iss) claim mismatch in the ID token; expected \"#{expected}\","\
131
+ " found \"#{claims['iss']}\""
132
+ end
133
+ end
134
+
135
+ def validate_sub(claims)
136
+ unless claims.key?('sub') && claims['sub'].is_a?(String)
137
+ raise Auth0::InvalidIdToken, 'Subject (sub) claim must be a string present in the ID token'
138
+ end
139
+ end
140
+
141
+ def validate_aud(claims, expected)
142
+ unless claims.key?('aud') && (claims['aud'].is_a?(String) || claims['aud'].is_a?(Array))
143
+ raise Auth0::InvalidIdToken, 'Audience (aud) claim must be a string or array of strings present'\
144
+ ' in the ID token'
145
+ end
146
+
147
+ if claims['aud'].is_a?(String) && expected != claims['aud']
148
+ raise Auth0::InvalidIdToken, "Audience (aud) claim mismatch in the ID token; expected \"#{expected}\","\
149
+ " found \"#{claims['aud']}\""
150
+ elsif claims['aud'].is_a?(Array) && !claims['aud'].include?(expected)
151
+ raise Auth0::InvalidIdToken, "Audience (aud) claim mismatch in the ID token; expected \"#{expected}\""\
152
+ " but was not one of \"#{claims['aud'].join ', '}\""
153
+ end
154
+ end
155
+
156
+ def validate_exp(claims, leeway)
157
+ unless claims.key?('exp') && claims['exp'].is_a?(Integer)
158
+ raise Auth0::InvalidIdToken, 'Expiration Time (exp) claim must be a number present in the ID token'
159
+ end
160
+
161
+ now = @context[:clock] || Time.now.to_i
162
+ exp_time = claims['exp'] + leeway
163
+
164
+ unless now < exp_time
165
+ raise Auth0::InvalidIdToken, 'Expiration Time (exp) claim mismatch in the ID token; current time'\
166
+ " \"#{now}\" is after expiration time \"#{exp_time}\""
167
+ end
168
+ end
169
+
170
+ def validate_iat(claims, leeway)
171
+ unless claims.key?('iat') && claims['iat'].is_a?(Integer)
172
+ raise Auth0::InvalidIdToken, 'Issued At (iat) claim must be a number present in the ID token'
173
+ end
174
+
175
+ now = @context[:clock] || Time.now.to_i
176
+ iat_time = claims['iat'] - leeway
177
+
178
+ unless now > iat_time
179
+ raise Auth0::InvalidIdToken, "Issued At (iat) claim mismatch in the ID token; current time \"#{now}\""\
180
+ " is before issued at time \"#{iat_time}\""
181
+ end
182
+ end
183
+
184
+ def validate_nonce(claims, expected)
185
+ unless claims.key?('nonce') && claims['nonce'].is_a?(String)
186
+ raise Auth0::InvalidIdToken, 'Nonce (nonce) claim must be a string present in the ID token'
187
+ end
188
+
189
+ unless expected == claims['nonce']
190
+ raise Auth0::InvalidIdToken, "Nonce (nonce) claim mismatch in the ID token; expected \"#{expected}\","\
191
+ " found \"#{claims['nonce']}\""
192
+ end
193
+ end
194
+
195
+ def validate_azp(claims, expected)
196
+ unless claims.key?('azp') && claims['azp'].is_a?(String)
197
+ raise Auth0::InvalidIdToken, 'Authorized Party (azp) claim must be a string present in the ID token'
198
+ end
199
+
200
+ unless expected == claims['azp']
201
+ raise Auth0::InvalidIdToken, 'Authorized Party (azp) claim mismatch in the ID token; expected'\
202
+ " \"#{expected}\", found \"#{claims['azp']}\""
203
+ end
204
+ end
205
+
206
+ def validate_auth_time(claims, max_age, leeway)
207
+ unless claims.key?('auth_time') && claims['auth_time'].is_a?(Integer)
208
+ raise Auth0::InvalidIdToken, 'Authentication Time (auth_time) claim must be a number present in the ID'\
209
+ ' token when Max Age (max_age) is specified'
210
+ end
211
+
212
+ now = @context[:clock] || Time.now.to_i
213
+ auth_valid_until = claims['auth_time'] + max_age + leeway
214
+
215
+ unless now < auth_valid_until
216
+ raise Auth0::InvalidIdToken, 'Authentication Time (auth_time) claim in the ID token indicates that too'\
217
+ ' much time has passed since the last end-user authentication. Current time'\
218
+ " \"#{now}\" is after last auth at \"#{auth_valid_until}\""
219
+ end
220
+ end
221
+ end
222
+ # rubocop:enable Metrics/ClassLength
223
+
224
+ class JWTAlgorithm
225
+ private_class_method :new
226
+
227
+ def name
228
+ raise RuntimeError, 'Must be overriden by the subclasses'
229
+ end
230
+ end
231
+
232
+ module Algorithm
233
+ # Represents the HS256 algorithm, which rely on shared secrets.
234
+ # @see https://auth0.com/docs/tokens/concepts/signing-algorithms
235
+ class HS256 < JWTAlgorithm
236
+ class << self
237
+ private :new
238
+
239
+ # Create a new instance passing the shared secret.
240
+ # @param secret [string] The HMAC shared secret.
241
+ # @return [HS256] A new instance.
242
+ def secret(secret)
243
+ new secret
244
+ end
245
+ end
246
+
247
+ attr_accessor :secret
248
+
249
+ def initialize(secret)
250
+ raise Auth0::InvalidParameter, 'Must supply a valid secret' if secret.to_s.empty?
251
+
252
+ @secret = secret
253
+ end
254
+
255
+ # Returns the algorithm name.
256
+ # @return [string] The algorithm name.
257
+ def name
258
+ 'HS256'
259
+ end
260
+ end
261
+
262
+ # Represents the RS256 algorithm, which rely on public key certificates.
263
+ # @see https://auth0.com/docs/tokens/concepts/signing-algorithms
264
+ class RS256 < JWTAlgorithm
265
+ include Auth0::Mixins::HTTPProxy
266
+
267
+ @@cache = Zache.new.freeze
268
+
269
+ class << self
270
+ private :new
271
+
272
+ # Create a new instance passing the JWK set url.
273
+ # @param url [string] The url where the JWK set is located.
274
+ # @param lifetime [integer] The lifetime of the JWK set in-memory cache in seconds.
275
+ # Must be a non-negative value. Defaults to *600 seconds* (10 minutes).
276
+ # @return [RS256] A new instance.
277
+ def jwks_url(url, lifetime: 10 * 60)
278
+ new url, lifetime
279
+ end
280
+
281
+ # Clear the JWK set cache.
282
+ def remove_jwks
283
+ @@cache.remove(:jwks)
284
+ end
285
+ end
286
+
287
+ def initialize(jwks_url, lifetime)
288
+ raise Auth0::InvalidParameter, 'Must supply a valid jwks_url' if jwks_url.to_s.empty?
289
+ raise Auth0::InvalidParameter, 'Must supply a valid lifetime' unless lifetime.is_a?(Integer) && lifetime >= 0
290
+
291
+ @lifetime = lifetime
292
+ @jwks_url = jwks_url
293
+ @did_fetch_jwks = false
294
+ end
295
+
296
+ # Returns the algorithm name.
297
+ # @return [string] The algorithm name.
298
+ def name
299
+ 'RS256'
300
+ end
301
+
302
+ # Fetches the JWK set from the in-memory cache or from the url.
303
+ # @return [hash] A JWK set.
304
+ def jwks(force: false)
305
+ result = fetch_jwks if force
306
+
307
+ if result
308
+ @@cache.put(:jwks, result, lifetime: @lifetime)
309
+ return result
310
+ end
311
+
312
+ previous_value = @@cache.last(:jwks)
313
+
314
+ @@cache.get(:jwks, lifetime: @lifetime, dirty: true) do
315
+ new_value = fetch_jwks
316
+
317
+ raise Auth0::InvalidIdToken, 'Could not fetch the JWK set' unless new_value || previous_value
318
+
319
+ new_value || previous_value
320
+ end
321
+ end
322
+
323
+ # Returns whether or not the JWK set was fetched from the url.
324
+ # @return [boolean] +true+ if a request to the JWK set url was made, +false+ otherwise.
325
+ def fetched_jwks?
326
+ @did_fetch_jwks
327
+ end
328
+
329
+ private
330
+
331
+ def fetch_jwks
332
+ result = get(@jwks_url)
333
+ @did_fetch_jwks = result.is_a?(Hash) && result.key?('keys')
334
+ result if @did_fetch_jwks
335
+ end
336
+ end
337
+ end
338
+ end
339
+ end
340
+ end
@@ -1,4 +1,4 @@
1
1
  # current version of gem
2
2
  module Auth0
3
- VERSION = '4.7.0'.freeze
3
+ VERSION = '4.12.0'.freeze
4
4
  end
@@ -0,0 +1,65 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://auth0-sdk-tests.auth0.com/api/v2/anomaly/blocks/ips/192.0.2.0
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - rest-client/2.0.2 (darwin18.6.0 x86_64) ruby/2.6.3p62
16
+ Content-Type:
17
+ - application/json
18
+ Auth0-Client:
19
+ - eyJuYW1lIjoicnVieS1hdXRoMCIsInZlcnNpb24iOiI0LjUuMCJ9
20
+ Authorization:
21
+ - Bearer API_TOKEN
22
+ Host:
23
+ - auth0-sdk-tests.auth0.com
24
+ response:
25
+ status:
26
+ code: 200
27
+ message: OK
28
+ headers:
29
+ Date:
30
+ - Sat, 06 Jul 2019 23:02:59 GMT
31
+ Content-Type:
32
+ - application/json; charset=utf-8
33
+ Transfer-Encoding:
34
+ - chunked
35
+ Connection:
36
+ - keep-alive
37
+ Ot-Tracer-Spanid:
38
+ - '0539a861079ec5ad'
39
+ Ot-Tracer-Traceid:
40
+ - 14cbee1b1f015043
41
+ Ot-Tracer-Sampled:
42
+ - 'true'
43
+ X-Ratelimit-Limit:
44
+ - '10'
45
+ X-Ratelimit-Remaining:
46
+ - '9'
47
+ X-Ratelimit-Reset:
48
+ - '1562454181'
49
+ Vary:
50
+ - origin,accept-encoding
51
+ Cache-Control:
52
+ - private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
53
+ Content-Encoding:
54
+ - gzip
55
+ Strict-Transport-Security:
56
+ - max-age=15724800
57
+ X-Robots-Tag:
58
+ - noindex, nofollow, nosnippet, noarchive
59
+ body:
60
+ encoding: ASCII-8BIT
61
+ string: !binary |-
62
+ H4sIAAAAAAAAA6uuBQBDv6ajAgAAAA==
63
+ http_version:
64
+ recorded_at: Sat, 06 Jul 2019 23:02:59 GMT
65
+ recorded_with: VCR 4.0.0