auth0 4.4.0 → 5.1.2

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 (289) hide show
  1. checksums.yaml +4 -4
  2. data/.bundle/config +3 -2
  3. data/.circleci/config.yml +44 -0
  4. data/.env.example +2 -0
  5. data/.github/CODEOWNERS +1 -0
  6. data/.github/ISSUE_TEMPLATE/config.yml +8 -0
  7. data/.github/ISSUE_TEMPLATE/feature_request.md +39 -0
  8. data/.github/ISSUE_TEMPLATE/report_a_bug.md +55 -0
  9. data/.github/PULL_REQUEST_TEMPLATE.md +35 -0
  10. data/.github/stale.yml +20 -0
  11. data/.gitignore +1 -2
  12. data/.rubocop.yml +2 -0
  13. data/.yardoc/checksums +22 -0
  14. data/.yardoc/complete +0 -0
  15. data/.yardoc/object_types +0 -0
  16. data/.yardoc/objects/root.dat +0 -0
  17. data/.yardoc/proxy_types +0 -0
  18. data/CHANGELOG.md +334 -19
  19. data/CODE_OF_CONDUCT.md +3 -0
  20. data/DEPLOYMENT.md +56 -9
  21. data/Gemfile +10 -3
  22. data/README.md +260 -37
  23. data/Rakefile +4 -23
  24. data/auth0.gemspec +10 -9
  25. data/codecov.yml +22 -0
  26. data/examples/ruby-api/.gitignore +0 -6
  27. data/lib/auth0/algorithm.rb +5 -0
  28. data/lib/auth0/api/authentication_endpoints.rb +244 -237
  29. data/lib/auth0/api/v2/anomaly.rb +36 -0
  30. data/lib/auth0/api/v2/branding.rb +66 -0
  31. data/lib/auth0/api/v2/client_grants.rb +14 -5
  32. data/lib/auth0/api/v2/clients.rb +9 -6
  33. data/lib/auth0/api/v2/connections.rb +19 -7
  34. data/lib/auth0/api/v2/device_credentials.rb +5 -4
  35. data/lib/auth0/api/v2/guardian.rb +142 -0
  36. data/lib/auth0/api/v2/jobs.rb +77 -13
  37. data/lib/auth0/api/v2/log_streams.rb +78 -0
  38. data/lib/auth0/api/v2/logs.rb +11 -11
  39. data/lib/auth0/api/v2/organizations.rb +335 -0
  40. data/lib/auth0/api/v2/prompts.rb +70 -0
  41. data/lib/auth0/api/v2/resource_servers.rb +32 -8
  42. data/lib/auth0/api/v2/roles.rb +172 -0
  43. data/lib/auth0/api/v2/rules.rb +6 -2
  44. data/lib/auth0/api/v2/tickets.rb +55 -8
  45. data/lib/auth0/api/v2/users.rb +168 -28
  46. data/lib/auth0/api/v2/users_by_email.rb +3 -2
  47. data/lib/auth0/api/v2.rb +16 -2
  48. data/lib/auth0/client.rb +1 -1
  49. data/lib/auth0/exception.rb +34 -9
  50. data/lib/auth0/mixins/access_token_struct.rb +20 -0
  51. data/lib/auth0/mixins/api_token_struct.rb +10 -0
  52. data/lib/auth0/mixins/headers.rb +35 -0
  53. data/lib/auth0/mixins/httpproxy.rb +37 -14
  54. data/lib/auth0/mixins/initializer.rb +10 -26
  55. data/lib/auth0/mixins/permission_struct.rb +3 -0
  56. data/lib/auth0/mixins/validation.rb +346 -0
  57. data/lib/auth0/mixins.rb +9 -1
  58. data/lib/auth0/version.rb +1 -1
  59. data/lib/auth0.rb +1 -0
  60. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_change_password/should_trigger_a_password_reset.yml +63 -0
  61. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_fail_with_an_incorrect_email.yml +54 -0
  62. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_fail_with_an_incorrect_password.yml +54 -0
  63. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_fail_with_an_invalid_audience.yml +55 -0
  64. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_login_successfully_with_a_custom_audience.yml +117 -0
  65. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_login_successfully_with_a_default_scope.yml +119 -0
  66. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_saml_metadata/should_retrieve_SAML_metadata.yml +57 -0
  67. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_userinfo/should_fail_as_not_authorized.yml +55 -0
  68. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_userinfo/should_return_the_userinfo.yml +118 -0
  69. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_wsfed_metadata/should_retrieve_WSFED_metadata.yml +55 -0
  70. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/create_test_user.yml +58 -0
  71. data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/delete_test_user.yml +54 -0
  72. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Anomaly/_check_if_ip_is_blocked/should_return_200_response_code.yml +65 -0
  73. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Anomaly/_remove_ip_block/should_remove_an_IP_successfully.yml +60 -0
  74. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Blacklists/_add_token_to_blacklist/should_add_a_token_to_the_blacklist.yml +56 -0
  75. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Blacklists/_blacklisted_tokens/should_get_the_added_token_from_the_blacklist.yml +59 -0
  76. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_client_grants/should_return_at_least_1_result.yml +62 -0
  77. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_client_grants/should_return_the_first_page_of_one_result.yml +66 -0
  78. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_client_grants/should_return_the_test_client_grant.yml +62 -0
  79. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_delete_client_grant/should_delete_the_test_client_grant.yml +54 -0
  80. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_patch_client_grant/should_update_the_test_client_grant.yml +64 -0
  81. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/create_test_client.yml +118 -0
  82. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/create_test_client_grant.yml +64 -0
  83. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/delete_test_client.yml +54 -0
  84. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/delete_test_client_grant.yml +54 -0
  85. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_client/_filters/should_exclude_and_include_fields_properly.yml +91 -0
  86. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_client/_filters/should_include_the_specified_fields.yml +63 -0
  87. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_client/should_get_the_test_client.yml +92 -0
  88. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_exclude_fields_not_specified.yml +60 -0
  89. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_exclude_the_specified_fields.yml +132 -0
  90. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_include_the_specified_fields.yml +63 -0
  91. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_paginate_results.yml +65 -0
  92. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/should_get_at_least_one_client.yml +132 -0
  93. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_delete_client/should_delete_the_test_client_without_an_error.yml +54 -0
  94. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_patch_client/should_update_the_client_with_the_correct_attributes.yml +94 -0
  95. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/create_test_client.yml +118 -0
  96. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connection/_filters/should_exclude_the_fields_indicated.yml +63 -0
  97. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connection/_filters/should_include_the_fields_indicated.yml +61 -0
  98. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connection/should_find_the_correct_connection.yml +63 -0
  99. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/_filters/should_include_previously-created_connection_when_filtered.yml +59 -0
  100. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/_filters/should_should_exclude_the_fields_indicated_from_filtered_results.yml +59 -0
  101. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/_filters/should_should_include_the_fields_indicated_from_filtered_results.yml +59 -0
  102. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/should_include_the_previously_created_connection.yml +59 -0
  103. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/should_not_be_empty.yml +59 -0
  104. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_delete_connection/should_delete_the_connection.yml +54 -0
  105. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_delete_connection_user/should_delete_the_user_created.yml +110 -0
  106. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_update_connection/should_update_the_connection.yml +66 -0
  107. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/create_test_connection.yml +65 -0
  108. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/create_test_user.yml +68 -0
  109. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/_delete_device_credential/should_delete_the_test_credential_without_an_error.yml +54 -0
  110. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/_device_credentials/_filter_by_type/should_exclude_the_test_credential.yml +59 -0
  111. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/_device_credentials/should_have_at_least_1_entry.yml +62 -0
  112. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/_device_credentials/should_include_the_test_credential.yml +62 -0
  113. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/create_test_credential.yml +62 -0
  114. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/create_test_user.yml +68 -0
  115. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/delete_test_credential.yml +54 -0
  116. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/delete_test_user.yml +54 -0
  117. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_configure_provider/should_configure_a_new_email_provider.yml +63 -0
  118. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_delete_provider/should_delete_the_existing_email_provider_without_an_error.yml +54 -0
  119. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_delete_provider/should_throw_an_error_trying_to_get_the_email_provider.yml +51 -0
  120. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_get_provider/_filters/should_get_the_existing_email_provider_with_specific_fields.yml +60 -0
  121. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_get_provider/_filters/should_get_the_existing_email_provider_without_specific_fields.yml +61 -0
  122. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_get_provider/should_get_the_existing_email_provider.yml +61 -0
  123. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_update_provider/should_update_the_existing_email_provider.yml +63 -0
  124. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/delete_existing_provider.yml +54 -0
  125. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_export_users_and_get_job/should_create_an_export_users_job_successfully.yml +61 -0
  126. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_export_users_and_get_job/should_get_the_export_users_job.yml +117 -0
  127. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_import_users_and_get_job/should_create_an_import_users_job_successfully.yml +60 -0
  128. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_import_users_and_get_job/should_get_the_import_users_job.yml +116 -0
  129. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_send_verification_email_and_get_job/should_create_a_new_verification_email_job.yml +119 -0
  130. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_send_verification_email_and_get_job/should_get_the_completed_verification_email.yml +175 -0
  131. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_send_verification_email_and_get_job/should_reject_an_invalid_client_id.yml +109 -0
  132. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/delete_imported_user.yml +110 -0
  133. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/search_for_connection_id.yml +59 -0
  134. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_log/should_match_the_created_log_entry.yml +265 -0
  135. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_log/should_not_be_empty.yml +265 -0
  136. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_exclude_fields_not_specified.yml +61 -0
  137. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_exclude_the_specified_fields.yml +75 -0
  138. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_have_one_log_entry.yml +76 -0
  139. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_include_the_specified_fields.yml +62 -0
  140. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_from/should_take_one_log_entry.yml +258 -0
  141. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/create_test_user.yml +68 -0
  142. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/delete_test_disabled_rule.yml +54 -0
  143. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/delete_test_enabled_rule.yml +54 -0
  144. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/delete_test_user.yml +54 -0
  145. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_delete_resource_server/should_delete_the_test_server_without_an_error.yml +54 -0
  146. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_patch_resource_server/should_update_the_resource_server_with_the_correct_attributes.yml +61 -0
  147. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_resource_server/should_get_the_test_server.yml +59 -0
  148. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_resource_servers/should_get_the_test_server.yml +59 -0
  149. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_resource_servers/should_return_at_least_1_result.yml +59 -0
  150. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_resource_servers/should_return_the_first_page_of_one_result.yml +64 -0
  151. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/create_test_server.yml +61 -0
  152. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/delete_test_server.yml +54 -0
  153. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_add_role_permissions/should_add_a_Permission_to_the_Role_successfully.yml +69 -0
  154. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_add_role_users/should_add_a_User_to_the_Role_successfully.yml +69 -0
  155. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_delete_role/should_delete_the_Role_successfully.yml +62 -0
  156. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role/should_get_the_Role_successfully.yml +67 -0
  157. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_permissions/should_get_exactly_1_Permission.yml +67 -0
  158. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_permissions/should_get_the_added_Permission_from_the_Role_successfully.yml +67 -0
  159. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_users/should_get_exactly_1_User.yml +67 -0
  160. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_users/should_get_the_added_User_from_the_Role_successfully.yml +67 -0
  161. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_roles/should_get_the_Role_successfully.yml +67 -0
  162. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_remove_role_permissions/should_remove_a_Permission_from_the_Role_successfully.yml +64 -0
  163. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_update_role/should_update_the_Role_successfully.yml +69 -0
  164. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/create_test_api.yml +69 -0
  165. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/create_test_role.yml +69 -0
  166. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/create_test_user.yml +69 -0
  167. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/delete_test_api.yml +62 -0
  168. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/delete_test_user.yml +62 -0
  169. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_delete_rule/should_delete_the_test_disabled_rule_without_an_error.yml +54 -0
  170. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_delete_rule/should_delete_the_test_enabled_rule_without_an_error.yml +54 -0
  171. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/_filters/should_exclude_the_fields_not_specified.yml +62 -0
  172. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/_filters/should_exclude_the_specified_fields.yml +62 -0
  173. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/_filters/should_include_the_specified_fields.yml +61 -0
  174. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/should_get_a_specific_rule.yml +62 -0
  175. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_exclude_fields_not_specified.yml +60 -0
  176. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_include_the_specified_fields.yml +61 -0
  177. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_return_at_least_1_disabled_rule.yml +63 -0
  178. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_return_at_least_1_enabled_rule.yml +62 -0
  179. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_return_paginated_results.yml +128 -0
  180. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/should_return_at_least_1_rule.yml +64 -0
  181. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_update_rule/should_update_the_disabled_rule_to_be_enabled.yml +64 -0
  182. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/create_test_disabled_rule.yml +65 -0
  183. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/create_test_enabled_rule.yml +65 -0
  184. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Stats/_active_users/should_have_at_least_one_active_user.yml +59 -0
  185. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Stats/_daily_stats/should_have_at_least_one_stats_entry_for_the_timeframe.yml +63 -0
  186. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_get_tenant_settings/should_get_the_tenant_settings.yml +95 -0
  187. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_get_tenant_settings_with_specific_fields/should_exclude_a_field_not_requested.yml +61 -0
  188. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_get_tenant_settings_with_specific_fields/should_include_the_field_requested.yml +61 -0
  189. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_update_tenant_settings/should_revert_the_tenant_name.yml +96 -0
  190. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_update_tenant_settings/should_update_the_tenant_settings_with_a_new_tenant_name.yml +96 -0
  191. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/_post_email_verification/should_create_an_email_verification_ticket.yml +63 -0
  192. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/_post_password_change/should_create_a_password_change_ticket.yml +63 -0
  193. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/create_test_user.yml +68 -0
  194. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/delete_test_user.yml +54 -0
  195. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_add_user_permissions/should_add_a_Permissions_for_a_User_successfully.yml +67 -0
  196. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_add_user_roles/should_add_a_Role_to_a_User_successfully.yml +62 -0
  197. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_delete_user/should_delete_the_User_successfully.yml +60 -0
  198. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_delete_user/should_delete_the_secondary_User_successfully.yml +60 -0
  199. 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
  200. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_enrollments/should_get_Enrollments_for_a_User_successfully.yml +65 -0
  201. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_user_permissions/should_get_exactly_1_Permission_for_a_User_successfully.yml +65 -0
  202. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_user_permissions/should_get_the_correct_Permission_for_a_User_successfully.yml +65 -0
  203. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_user_roles/should_get_Roles_for_a_User_successfully.yml +65 -0
  204. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_invalidate_browsers/should_invalidate_MFA_browsers_for_the_User_successfully.yml +62 -0
  205. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_link_user_account/should_link_two_Users_successfully.yml +67 -0
  206. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_patch_user/should_patch_the_User_successfully.yml +68 -0
  207. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_remove_user_permissions/should_remove_a_Permission_from_a_User_successfully.yml +62 -0
  208. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_remove_user_roles/should_remove_a_Role_from_a_User_successfully.yml +62 -0
  209. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_unlink_user_account/should_unlink_two_Users_successfully.yml +65 -0
  210. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/_filters/should_exclude_fields_not_indicated.yml +65 -0
  211. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/_filters/should_exclude_the_fields_indicated.yml +65 -0
  212. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/_filters/should_include_the_fields_indicated.yml +65 -0
  213. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/should_retrieve_the_created_user.yml +65 -0
  214. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user_logs/should_get_Logs_for_a_User_successfully.yml +69 -0
  215. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/is_expected_to_find_a_user_with_a_v2_search_engine_query.yml +65 -0
  216. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/is_expected_to_find_a_user_with_a_v3_search_engine_query.yml +65 -0
  217. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_exclude_the_indicated_fields_when_paginated.yml +65 -0
  218. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_include_the_indicated_fields_when_paginated.yml +65 -0
  219. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_not_include_other_fields_when_paginated.yml +65 -0
  220. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_return_the_correct_number_of_results_when_paginated.yml +65 -0
  221. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/should_have_at_least_one_user.yml +65 -0
  222. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_secondary_test_user.yml +67 -0
  223. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_test_api.yml +67 -0
  224. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_test_role.yml +67 -0
  225. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_test_user.yml +67 -0
  226. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/delete_test_api.yml +60 -0
  227. data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/delete_test_role.yml +60 -0
  228. data/spec/integration/lib/auth0/api/api_authentication_spec.rb +96 -54
  229. data/spec/integration/lib/auth0/api/v2/api_anomaly_spec.rb +17 -0
  230. data/spec/integration/lib/auth0/api/v2/api_blacklist_spec.rb +18 -5
  231. data/spec/integration/lib/auth0/api/v2/api_client_grants_spec.rb +46 -33
  232. data/spec/integration/lib/auth0/api/v2/api_clients_spec.rb +115 -61
  233. data/spec/integration/lib/auth0/api/v2/api_connections_spec.rb +117 -103
  234. data/spec/integration/lib/auth0/api/v2/api_device_credentials_spec.rb +101 -58
  235. data/spec/integration/lib/auth0/api/v2/api_email_spec.rb +72 -77
  236. data/spec/integration/lib/auth0/api/v2/api_jobs_spec.rb +113 -60
  237. data/spec/integration/lib/auth0/api/v2/api_logs_spec.rb +46 -38
  238. data/spec/integration/lib/auth0/api/v2/api_resource_servers_spec.rb +110 -40
  239. data/spec/integration/lib/auth0/api/v2/api_roles_spec.rb +145 -0
  240. data/spec/integration/lib/auth0/api/v2/api_rules_spec.rb +119 -62
  241. data/spec/integration/lib/auth0/api/v2/api_stats_spec.rb +11 -14
  242. data/spec/integration/lib/auth0/api/v2/api_tenants_spec.rb +40 -34
  243. data/spec/integration/lib/auth0/api/v2/api_tickets_spec.rb +42 -28
  244. data/spec/integration/lib/auth0/api/v2/api_user_blocks_spec.rb +1 -1
  245. data/spec/integration/lib/auth0/api/v2/api_users_spec.rb +252 -120
  246. data/spec/integration/lib/auth0/auth0_client_spec.rb +32 -26
  247. data/spec/lib/auth0/api/v2/anomaly_spec.rb +26 -0
  248. data/spec/lib/auth0/api/v2/branding_spec.rb +70 -0
  249. data/spec/lib/auth0/api/v2/client_grants_spec.rb +34 -2
  250. data/spec/lib/auth0/api/v2/clients_spec.rb +50 -5
  251. data/spec/lib/auth0/api/v2/connections_spec.rb +49 -1
  252. data/spec/lib/auth0/api/v2/guardian_spec.rb +154 -0
  253. data/spec/lib/auth0/api/v2/jobs_spec.rb +109 -6
  254. data/spec/lib/auth0/api/v2/log_streams_spec.rb +84 -0
  255. data/spec/lib/auth0/api/v2/organizations_spec.rb +593 -0
  256. data/spec/lib/auth0/api/v2/prompts_spec.rb +88 -0
  257. data/spec/lib/auth0/api/v2/resource_servers_spec.rb +23 -0
  258. data/spec/lib/auth0/api/v2/roles_spec.rb +362 -0
  259. data/spec/lib/auth0/api/v2/rules_spec.rb +23 -1
  260. data/spec/lib/auth0/api/v2/tickets_spec.rb +95 -5
  261. data/spec/lib/auth0/api/v2/users_spec.rb +465 -61
  262. data/spec/lib/auth0/client_spec.rb +196 -18
  263. data/spec/lib/auth0/mixins/httpproxy_spec.rb +83 -4
  264. data/spec/lib/auth0/mixins/initializer_spec.rb +1 -0
  265. data/spec/lib/auth0/mixins/validation_spec.rb +498 -0
  266. data/spec/spec_helper.rb +54 -11
  267. data/spec/support/credentials.rb +6 -18
  268. data/spec/support/dummy_class.rb +7 -3
  269. data/spec/support/dummy_class_for_proxy.rb +1 -0
  270. data/spec/support/stub_response.rb +1 -1
  271. metadata +497 -53
  272. data/.travis.yml +0 -18
  273. data/build_travis.sh +0 -7
  274. data/deploy_documentation.sh +0 -29
  275. data/doc_config/templates/default/fulldoc/html/css/full_list.css +0 -79
  276. data/doc_config/templates/default/fulldoc/html/css/style.css +0 -546
  277. data/doc_config/templates/default/layout/html/breadcrumb.erb +0 -11
  278. data/doc_config/templates/default/layout/html/footer.erb +0 -115
  279. data/doc_config/templates/default/layout/html/headers.erb +0 -17
  280. data/doc_config/templates/default/layout/html/layout.erb +0 -27
  281. data/lib/auth0/api/v1/clients.rb +0 -48
  282. data/lib/auth0/api/v1/connections.rb +0 -53
  283. data/lib/auth0/api/v1/logs.rb +0 -34
  284. data/lib/auth0/api/v1/rules.rb +0 -45
  285. data/lib/auth0/api/v1/users.rb +0 -164
  286. data/lib/auth0/api/v1.rb +0 -19
  287. data/spec/lib/auth0/api/authentication_endpoints_spec.rb +0 -348
  288. data/spec/spec_helper_full.rb +0 -45
  289. data/spec/spec_helper_unit.rb +0 -3
@@ -1,3 +1,5 @@
1
+ require "addressable/uri"
2
+
1
3
  module Auth0
2
4
  module Mixins
3
5
  # here's the proxy for Rest calls based on rest-client, we're building all request on that gem
@@ -6,25 +8,40 @@ module Auth0
6
8
  attr_accessor :headers, :base_uri, :timeout
7
9
 
8
10
  # proxying requests from instance methods to HTTP class methods
9
- %i(get post post_file put patch delete).each do |method|
10
- define_method(method) do |path, body = {}|
11
- safe_path = URI.escape(path)
11
+ %i(get post post_file put patch delete delete_with_body).each do |method|
12
+ define_method(method) do |path, body = {}, extra_headers = {}|
13
+ safe_path = Addressable::URI.escape(path)
12
14
  body = body.delete_if { |_, v| v.nil? }
13
- result = if [:get, :delete].include?(method)
14
- call(method, url(safe_path), timeout, add_headers(params: body))
15
+ result = if method == :get
16
+ # Mutate the headers property to add parameters.
17
+ add_headers({params: body})
18
+ # Merge custom headers into existing ones for this req.
19
+ # This prevents future calls from using them.
20
+ get_headers = headers.merge extra_headers
21
+ # Make the call with extra_headers, if provided.
22
+ call(:get, url(safe_path), timeout, get_headers)
23
+ elsif method == :delete
24
+ call(:delete, url(safe_path), timeout, add_headers({params: body}))
25
+ elsif method == :delete_with_body
26
+ call(:delete, url(safe_path), timeout, headers, body.to_json)
15
27
  elsif method == :post_file
16
- call(:post, url(safe_path), timeout, headers, body)
28
+ body.merge!(multipart: true)
29
+ # Ignore the default Content-Type headers and let the HTTP client define them
30
+ post_file_headers = headers.slice(*headers.keys - ['Content-Type'])
31
+ # Actual call with the altered headers
32
+ call(:post, url(safe_path), timeout, post_file_headers, body)
17
33
  else
18
34
  call(method, url(safe_path), timeout, headers, body.to_json)
19
35
  end
20
36
  case result.code
21
37
  when 200...226 then safe_parse_json(result.body)
22
- when 400 then raise Auth0::BadRequest, result.to_s
23
- when 401 then raise Auth0::Unauthorized, result.body
24
- when 403 then raise Auth0::AccessDenied, result.body
25
- when 404 then raise Auth0::NotFound, result.body
26
- when 500 then raise Auth0::ServerError, result.body
27
- else raise Auth0::Unsupported, result.body
38
+ when 400 then raise Auth0::BadRequest.new(result.body, code: result.code, headers: result.headers)
39
+ when 401 then raise Auth0::Unauthorized.new(result.body, code: result.code, headers: result.headers)
40
+ when 403 then raise Auth0::AccessDenied.new(result.body, code: result.code, headers: result.headers)
41
+ when 404 then raise Auth0::NotFound.new(result.body, code: result.code, headers: result.headers)
42
+ when 429 then raise Auth0::RateLimitEncountered.new(result.body, code: result.code, headers: result.headers)
43
+ when 500 then raise Auth0::ServerError.new(result.body, code: result.code, headers: result.headers)
44
+ else raise Auth0::Unsupported.new(result.body, code: result.code, headers: result.headers)
28
45
  end
29
46
  end
30
47
  end
@@ -46,11 +63,17 @@ module Auth0
46
63
  end
47
64
 
48
65
  def call(method, url, timeout, headers, body = nil)
49
- RestClient::Request.execute(method: method, url: url, timeout: timeout, headers: headers, payload: body)
66
+ RestClient::Request.execute(
67
+ method: method,
68
+ url: url,
69
+ timeout: timeout,
70
+ headers: headers,
71
+ payload: body
72
+ )
50
73
  rescue RestClient::Exception => e
51
74
  case e
52
75
  when RestClient::RequestTimeout
53
- raise Auth0::RequestTimeout
76
+ raise Auth0::RequestTimeout.new(e.message)
54
77
  else
55
78
  return e.response
56
79
  end
@@ -1,7 +1,10 @@
1
+ require 'json'
2
+
1
3
  module Auth0
2
4
  module Mixins
3
5
  # Help class where Auth0::Client initialization described
4
6
  module Initializer
7
+
5
8
  # Default initialization mechanism, moved here to keep Auth0::Client clear
6
9
  # accepts hash as parameter
7
10
  # you can get all required fields from here: https://auth0.com/docs/auth-api
@@ -10,10 +13,12 @@ module Auth0
10
13
  def initialize(config)
11
14
  options = Hash[config.map { |(k, v)| [k.to_sym, v] }]
12
15
  @base_uri = base_url(options)
13
- @headers = client_headers(config)
16
+ @headers = client_headers
14
17
  @timeout = options[:timeout] || 10
15
18
  extend Auth0::Api::AuthenticationEndpoints
16
19
  @client_id = options[:client_id]
20
+ @client_secret = options[:client_secret]
21
+ @organization = options[:organization]
17
22
  initialize_api(options)
18
23
  end
19
24
 
@@ -36,7 +41,7 @@ module Auth0
36
41
  private
37
42
 
38
43
  def initialize_api(options)
39
- api_v2?(options) ? initialize_v2(options) : initialize_v1(options)
44
+ initialize_v2(options)
40
45
  raise InvalidCredentials, 'Must supply a valid API token' if @token.nil?
41
46
  if options.fetch(:authorization, nil) == 'Basic'
42
47
  authorization_header_basic(options)
@@ -47,36 +52,15 @@ module Auth0
47
52
 
48
53
  def base_url(options)
49
54
  @domain = options[:domain] || options[:namespace]
50
- raise InvalidApiNamespace, 'Api namespace must supply an API domain' if @domain.to_s.empty?
55
+ raise InvalidApiNamespace, 'API namespace must supply an API domain' if @domain.to_s.empty?
51
56
  "https://#{@domain}"
52
57
  end
53
58
 
54
- def client_headers(config)
55
- client_info = JSON.dump(name: 'ruby-auth0', version: Auth0::VERSION)
56
-
57
- headers = {
58
- 'Content-Type' => 'application/json'
59
- }
60
-
61
- unless config[:opt_out_sdk_info]
62
- headers['User-Agent'] = "Ruby/#{RUBY_VERSION}"
63
- headers['Auth0-Client'] = Base64.urlsafe_encode64(client_info)
64
- end
65
-
66
- headers
67
- end
68
-
69
59
  def initialize_v2(options)
70
60
  extend Auth0::Api::V2
71
- @client_secret = options[:client_secret]
72
61
  @token = options[:access_token] || options[:token]
73
- end
74
-
75
- def initialize_v1(options)
76
- extend Auth0::Api::V1
77
- @client_secret = options[:client_secret]
78
- raise InvalidCredentials, 'Invalid API v1 client_id and client_secret' if @client_id.nil? || @client_secret.nil?
79
- @token = obtain_access_token
62
+ api_identifier = options[:api_identifier] || "https://#{@domain}/api/v2/"
63
+ @token = api_token(audience: api_identifier).token if @token.nil? && @client_id && @client_secret
80
64
  end
81
65
 
82
66
  def api_v2?(options)
@@ -0,0 +1,3 @@
1
+ Auth0::Permission = Struct.new :permission_name, :resource_server_identifier do
2
+
3
+ end
@@ -0,0 +1,346 @@
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? ::Auth0::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
+ org = @context[:organization]
104
+
105
+ raise Auth0::InvalidParameter, 'Must supply a valid leeway' unless leeway.is_a?(Integer) && leeway >= 0
106
+ raise Auth0::InvalidParameter, 'Must supply a valid nonce' unless nonce.nil? || !nonce.to_s.empty?
107
+ raise Auth0::InvalidParameter, 'Must supply a valid issuer' unless issuer.nil? || !issuer.to_s.empty?
108
+ raise Auth0::InvalidParameter, 'Must supply a valid audience' unless audience.nil? || !audience.to_s.empty?
109
+ raise Auth0::InvalidParameter, 'Must supply a valid organization' unless org.nil? || !org.to_s.empty?
110
+
111
+ unless max_age.nil? || (max_age.is_a?(Integer) && max_age >= 0)
112
+ raise Auth0::InvalidParameter, 'Must supply a valid max_age'
113
+ end
114
+
115
+ validate_iss(claims, issuer)
116
+ validate_sub(claims)
117
+ validate_aud(claims, audience)
118
+ validate_exp(claims, leeway)
119
+ validate_iat(claims, leeway)
120
+ validate_nonce(claims, nonce) if nonce
121
+ validate_azp(claims, audience) if claims['aud'].is_a?(Array) && claims['aud'].count > 1
122
+ validate_auth_time(claims, max_age, leeway) if max_age
123
+ validate_org(claims, org) if org
124
+ end
125
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
126
+
127
+ def validate_iss(claims, expected)
128
+ unless claims.key?('iss') && claims['iss'].is_a?(String)
129
+ raise Auth0::InvalidIdToken, 'Issuer (iss) claim must be a string present in the ID token'
130
+ end
131
+
132
+ unless expected == claims['iss']
133
+ raise Auth0::InvalidIdToken, "Issuer (iss) claim mismatch in the ID token; expected \"#{expected}\","\
134
+ " found \"#{claims['iss']}\""
135
+ end
136
+ end
137
+
138
+ def validate_sub(claims)
139
+ unless claims.key?('sub') && claims['sub'].is_a?(String)
140
+ raise Auth0::InvalidIdToken, 'Subject (sub) claim must be a string present in the ID token'
141
+ end
142
+ end
143
+
144
+ def validate_aud(claims, expected)
145
+ unless claims.key?('aud') && (claims['aud'].is_a?(String) || claims['aud'].is_a?(Array))
146
+ raise Auth0::InvalidIdToken, 'Audience (aud) claim must be a string or array of strings present'\
147
+ ' in the ID token'
148
+ end
149
+
150
+ if claims['aud'].is_a?(String) && expected != claims['aud']
151
+ raise Auth0::InvalidIdToken, "Audience (aud) claim mismatch in the ID token; expected \"#{expected}\","\
152
+ " found \"#{claims['aud']}\""
153
+ elsif claims['aud'].is_a?(Array) && !claims['aud'].include?(expected)
154
+ raise Auth0::InvalidIdToken, "Audience (aud) claim mismatch in the ID token; expected \"#{expected}\""\
155
+ " but was not one of \"#{claims['aud'].join ', '}\""
156
+ end
157
+ end
158
+
159
+ def validate_exp(claims, leeway)
160
+ unless claims.key?('exp') && claims['exp'].is_a?(Integer)
161
+ raise Auth0::InvalidIdToken, 'Expiration Time (exp) claim must be a number present in the ID token'
162
+ end
163
+
164
+ now = @context[:clock] || Time.now.to_i
165
+ exp_time = claims['exp'] + leeway
166
+
167
+ unless now < exp_time
168
+ raise Auth0::InvalidIdToken, 'Expiration Time (exp) claim mismatch in the ID token; current time'\
169
+ " \"#{now}\" is after expiration time \"#{exp_time}\""
170
+ end
171
+ end
172
+
173
+ def validate_iat(claims, leeway)
174
+ unless claims.key?('iat') && claims['iat'].is_a?(Integer)
175
+ raise Auth0::InvalidIdToken, 'Issued At (iat) claim must be a number present in the ID token'
176
+ end
177
+ end
178
+
179
+ def validate_nonce(claims, expected)
180
+ unless claims.key?('nonce') && claims['nonce'].is_a?(String)
181
+ raise Auth0::InvalidIdToken, 'Nonce (nonce) claim must be a string present in the ID token'
182
+ end
183
+
184
+ unless expected == claims['nonce']
185
+ raise Auth0::InvalidIdToken, "Nonce (nonce) claim mismatch in the ID token; expected \"#{expected}\","\
186
+ " found \"#{claims['nonce']}\""
187
+ end
188
+ end
189
+
190
+ def validate_org(claims, expected)
191
+ unless claims.key?('org_id') && claims['org_id'].is_a?(String)
192
+ raise Auth0::InvalidIdToken, 'Organization Id (org_id) claim must be a string present in the ID token'
193
+ end
194
+
195
+ unless expected == claims['org_id']
196
+ raise Auth0::InvalidIdToken, "Organization Id (org_id) claim value mismatch in the ID token; expected \"#{expected}\","\
197
+ " found \"#{claims['org_id']}\""
198
+ end
199
+ end
200
+
201
+ def validate_azp(claims, expected)
202
+ unless claims.key?('azp') && claims['azp'].is_a?(String)
203
+ raise Auth0::InvalidIdToken, 'Authorized Party (azp) claim must be a string present in the ID token'
204
+ end
205
+
206
+ unless expected == claims['azp']
207
+ raise Auth0::InvalidIdToken, 'Authorized Party (azp) claim mismatch in the ID token; expected'\
208
+ " \"#{expected}\", found \"#{claims['azp']}\""
209
+ end
210
+ end
211
+
212
+ def validate_auth_time(claims, max_age, leeway)
213
+ unless claims.key?('auth_time') && claims['auth_time'].is_a?(Integer)
214
+ raise Auth0::InvalidIdToken, 'Authentication Time (auth_time) claim must be a number present in the ID'\
215
+ ' token when Max Age (max_age) is specified'
216
+ end
217
+
218
+ now = @context[:clock] || Time.now.to_i
219
+ auth_valid_until = claims['auth_time'] + max_age + leeway
220
+
221
+ unless now < auth_valid_until
222
+ raise Auth0::InvalidIdToken, 'Authentication Time (auth_time) claim in the ID token indicates that too'\
223
+ ' much time has passed since the last end-user authentication. Current time'\
224
+ " \"#{now}\" is after last auth at \"#{auth_valid_until}\""
225
+ end
226
+ end
227
+ end
228
+ # rubocop:enable Metrics/ClassLength
229
+
230
+ class JWTAlgorithm
231
+ private_class_method :new
232
+
233
+ def name
234
+ raise RuntimeError, 'Must be overriden by the subclasses'
235
+ end
236
+ end
237
+
238
+ module Algorithm
239
+ # Represents the HS256 algorithm, which rely on shared secrets.
240
+ # @see https://auth0.com/docs/tokens/concepts/signing-algorithms
241
+ class HS256 < JWTAlgorithm
242
+ class << self
243
+ private :new
244
+
245
+ # Create a new instance passing the shared secret.
246
+ # @param secret [string] The HMAC shared secret.
247
+ # @return [HS256] A new instance.
248
+ def secret(secret)
249
+ new secret
250
+ end
251
+ end
252
+
253
+ attr_accessor :secret
254
+
255
+ def initialize(secret)
256
+ raise Auth0::InvalidParameter, 'Must supply a valid secret' if secret.to_s.empty?
257
+
258
+ @secret = secret
259
+ end
260
+
261
+ # Returns the algorithm name.
262
+ # @return [string] The algorithm name.
263
+ def name
264
+ 'HS256'
265
+ end
266
+ end
267
+
268
+ # Represents the RS256 algorithm, which rely on public key certificates.
269
+ # @see https://auth0.com/docs/tokens/concepts/signing-algorithms
270
+ class RS256 < JWTAlgorithm
271
+ include Auth0::Mixins::HTTPProxy
272
+
273
+ @@cache = Zache.new.freeze
274
+
275
+ class << self
276
+ private :new
277
+
278
+ # Create a new instance passing the JWK set url.
279
+ # @param url [string] The url where the JWK set is located.
280
+ # @param lifetime [integer] The lifetime of the JWK set in-memory cache in seconds.
281
+ # Must be a non-negative value. Defaults to *600 seconds* (10 minutes).
282
+ # @return [RS256] A new instance.
283
+ def jwks_url(url, lifetime: 10 * 60)
284
+ new url, lifetime
285
+ end
286
+
287
+ # Clear the JWK set cache.
288
+ def remove_jwks
289
+ @@cache.remove(:jwks)
290
+ end
291
+ end
292
+
293
+ def initialize(jwks_url, lifetime)
294
+ raise Auth0::InvalidParameter, 'Must supply a valid jwks_url' if jwks_url.to_s.empty?
295
+ raise Auth0::InvalidParameter, 'Must supply a valid lifetime' unless lifetime.is_a?(Integer) && lifetime >= 0
296
+
297
+ @lifetime = lifetime
298
+ @jwks_url = jwks_url
299
+ @did_fetch_jwks = false
300
+ end
301
+
302
+ # Returns the algorithm name.
303
+ # @return [string] The algorithm name.
304
+ def name
305
+ 'RS256'
306
+ end
307
+
308
+ # Fetches the JWK set from the in-memory cache or from the url.
309
+ # @return [hash] A JWK set.
310
+ def jwks(force: false)
311
+ result = fetch_jwks if force
312
+
313
+ if result
314
+ @@cache.put(:jwks, result, lifetime: @lifetime)
315
+ return result
316
+ end
317
+
318
+ previous_value = @@cache.last(:jwks)
319
+
320
+ @@cache.get(:jwks, lifetime: @lifetime, dirty: true) do
321
+ new_value = fetch_jwks
322
+
323
+ raise Auth0::InvalidIdToken, 'Could not fetch the JWK set' unless new_value || previous_value
324
+
325
+ new_value || previous_value
326
+ end
327
+ end
328
+
329
+ # Returns whether or not the JWK set was fetched from the url.
330
+ # @return [boolean] +true+ if a request to the JWK set url was made, +false+ otherwise.
331
+ def fetched_jwks?
332
+ @did_fetch_jwks
333
+ end
334
+
335
+ private
336
+
337
+ def fetch_jwks
338
+ result = get(@jwks_url)
339
+ @did_fetch_jwks = result.is_a?(Hash) && result.key?('keys')
340
+ result if @did_fetch_jwks
341
+ end
342
+ end
343
+ end
344
+ end
345
+ end
346
+ end
data/lib/auth0/mixins.rb CHANGED
@@ -1,14 +1,22 @@
1
1
  require 'base64'
2
2
  require 'rest-client'
3
3
  require 'uri'
4
+
5
+ require 'auth0/mixins/access_token_struct'
6
+ require 'auth0/mixins/api_token_struct'
7
+ require 'auth0/mixins/headers'
4
8
  require 'auth0/mixins/httpproxy'
5
9
  require 'auth0/mixins/initializer'
10
+ require 'auth0/mixins/permission_struct'
11
+ require 'auth0/mixins/validation'
12
+
6
13
  require 'auth0/api/authentication_endpoints'
7
- require 'auth0/api/v1'
8
14
  require 'auth0/api/v2'
15
+
9
16
  module Auth0
10
17
  # Collecting dependencies here
11
18
  module Mixins
19
+ include Auth0::Mixins::Headers
12
20
  include Auth0::Mixins::HTTPProxy
13
21
  include Auth0::Mixins::Initializer
14
22
  end
data/lib/auth0/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # current version of gem
2
2
  module Auth0
3
- VERSION = '4.4.0'.freeze
3
+ VERSION = '5.1.2'.freeze
4
4
  end
data/lib/auth0.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'auth0/version'
2
2
  require 'auth0/mixins'
3
3
  require 'auth0/exception'
4
+ require 'auth0/algorithm'
4
5
  require 'auth0/client'
5
6
  require 'auth0_client'
6
7
  # Namespace for ruby-auth0 logic
@@ -0,0 +1,63 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://auth0-sdk-tests.auth0.com/dbconnections/change_password
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"email":"rubytest-username-1@auth0.com","password":"","connection":"Username-Password-Authentication","client_id":"2cnWuug6zaFX1j0ge1P99jAUn0F4XSuI"}'
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - Ruby/2.5.1
16
+ Content-Type:
17
+ - application/json
18
+ Auth0-Client:
19
+ - eyJuYW1lIjoicnVieS1hdXRoMCIsInZlcnNpb24iOiI0LjUuMCJ9
20
+ Authorization:
21
+ - Bearer API_TOKEN
22
+ Content-Length:
23
+ - '150'
24
+ Host:
25
+ - auth0-sdk-tests.auth0.com
26
+ response:
27
+ status:
28
+ code: 200
29
+ message: OK
30
+ headers:
31
+ Date:
32
+ - Wed, 10 Oct 2018 23:19:59 GMT
33
+ Content-Type:
34
+ - text/html; charset=utf-8
35
+ Transfer-Encoding:
36
+ - chunked
37
+ Connection:
38
+ - keep-alive
39
+ Vary:
40
+ - Accept-Encoding
41
+ X-Auth0-Requestid:
42
+ - b1edcce5da4346cf4e72
43
+ X-Ratelimit-Limit:
44
+ - '10'
45
+ X-Ratelimit-Remaining:
46
+ - '9'
47
+ X-Ratelimit-Reset:
48
+ - '1539213660'
49
+ Cache-Control:
50
+ - private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
51
+ Strict-Transport-Security:
52
+ - max-age=15724800
53
+ X-Robots-Tag:
54
+ - noindex, nofollow, nosnippet, noarchive
55
+ Content-Encoding:
56
+ - gzip
57
+ body:
58
+ encoding: ASCII-8BIT
59
+ string: !binary |-
60
+ H4sIAAAAAAAAAwtPVS9LVcgqLS5RKE7NK1GozC9VSMxTSM1NzMxRKMlXKEotTgWLFikUJBYXl+cXpegBAKHKLwA0AAAA
61
+ http_version:
62
+ recorded_at: Wed, 10 Oct 2018 23:19:59 GMT
63
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,54 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://auth0-sdk-tests.auth0.com/oauth/token
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"username":"rubytest-username-1@auth0.com_invalid","password":"23kejn2jk3en2jke2jk3be2jk3ber","client_id":"2cnWuug6zaFX1j0ge1P99jAUn0F4XSuI","client_secret":"CLIENT_SECRET","scope":"openid","grant_type":"password"}'
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - Ruby/2.5.1
16
+ Content-Type:
17
+ - application/json
18
+ Auth0-Client:
19
+ - eyJuYW1lIjoicnVieS1hdXRoMCIsInZlcnNpb24iOiI0LjUuMCJ9
20
+ Authorization:
21
+ - Bearer API_TOKEN
22
+ Content-Length:
23
+ - '266'
24
+ Host:
25
+ - auth0-sdk-tests.auth0.com
26
+ response:
27
+ status:
28
+ code: 403
29
+ message: Forbidden
30
+ headers:
31
+ Date:
32
+ - Wed, 17 Oct 2018 17:17:52 GMT
33
+ Content-Type:
34
+ - application/json
35
+ Content-Length:
36
+ - '72'
37
+ Connection:
38
+ - keep-alive
39
+ X-Auth0-Requestid:
40
+ - b6bab16857282fef5757
41
+ X-Ratelimit-Limit:
42
+ - '100'
43
+ X-Ratelimit-Remaining:
44
+ - '94'
45
+ X-Ratelimit-Reset:
46
+ - '1539801484'
47
+ Cache-Control:
48
+ - private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
49
+ body:
50
+ encoding: UTF-8
51
+ string: '{"error":"invalid_grant","error_description":"Wrong email or password."}'
52
+ http_version:
53
+ recorded_at: Wed, 17 Oct 2018 17:17:52 GMT
54
+ recorded_with: VCR 4.0.0