descope 1.0.4

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 (197) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yaml +54 -0
  3. data/.gitignore +59 -0
  4. data/.release-please-manifest.json +3 -0
  5. data/.rubocop.yml +10 -0
  6. data/.rubocop_todo.yml +10 -0
  7. data/.ruby-version +1 -0
  8. data/CHANGELOG.md +90 -0
  9. data/Gemfile +22 -0
  10. data/Gemfile.lock +204 -0
  11. data/LICENSE +21 -0
  12. data/README.md +1171 -0
  13. data/Rakefile +31 -0
  14. data/descope.gemspec +34 -0
  15. data/examples/ruby/Gemfile +4 -0
  16. data/examples/ruby/Gemfile.lock +41 -0
  17. data/examples/ruby/access_key_app.rb +45 -0
  18. data/examples/ruby/enchantedlink_app.rb +65 -0
  19. data/examples/ruby/magiclink_app.rb +81 -0
  20. data/examples/ruby/management/Gemfile +5 -0
  21. data/examples/ruby/management/Gemfile.lock +38 -0
  22. data/examples/ruby/management/access_key_app.rb +71 -0
  23. data/examples/ruby/management/audit_app.rb +25 -0
  24. data/examples/ruby/management/authz_app.rb +135 -0
  25. data/examples/ruby/management/authz_files.json +229 -0
  26. data/examples/ruby/management/flow_app.rb +57 -0
  27. data/examples/ruby/management/permission_app.rb +56 -0
  28. data/examples/ruby/management/role_app.rb +58 -0
  29. data/examples/ruby/management/tenant_app.rb +60 -0
  30. data/examples/ruby/management/user_app.rb +60 -0
  31. data/examples/ruby/oauth_app.rb +39 -0
  32. data/examples/ruby/otp_app.rb +50 -0
  33. data/examples/ruby/password_app.rb +76 -0
  34. data/examples/ruby/saml_app.rb +38 -0
  35. data/examples/ruby-on-rails-api/descope/.dockerignore +37 -0
  36. data/examples/ruby-on-rails-api/descope/.gitattributes +9 -0
  37. data/examples/ruby-on-rails-api/descope/.gitignore +40 -0
  38. data/examples/ruby-on-rails-api/descope/.node-version +1 -0
  39. data/examples/ruby-on-rails-api/descope/.ruby-version +1 -0
  40. data/examples/ruby-on-rails-api/descope/Dockerfile +75 -0
  41. data/examples/ruby-on-rails-api/descope/Gemfile +67 -0
  42. data/examples/ruby-on-rails-api/descope/Gemfile.lock +284 -0
  43. data/examples/ruby-on-rails-api/descope/Procfile.dev +3 -0
  44. data/examples/ruby-on-rails-api/descope/README.md +54 -0
  45. data/examples/ruby-on-rails-api/descope/Rakefile +6 -0
  46. data/examples/ruby-on-rails-api/descope/app/assets/builds/.keep +0 -0
  47. data/examples/ruby-on-rails-api/descope/app/assets/config/manifest.js +3 -0
  48. data/examples/ruby-on-rails-api/descope/app/assets/images/.keep +0 -0
  49. data/examples/ruby-on-rails-api/descope/app/assets/images/descope.jpeg +0 -0
  50. data/examples/ruby-on-rails-api/descope/app/assets/images/favicon.ico +0 -0
  51. data/examples/ruby-on-rails-api/descope/app/assets/images/logo192.png +0 -0
  52. data/examples/ruby-on-rails-api/descope/app/assets/images/logo512.png +0 -0
  53. data/examples/ruby-on-rails-api/descope/app/assets/stylesheets/application.bootstrap.scss +67 -0
  54. data/examples/ruby-on-rails-api/descope/app/channels/application_cable/channel.rb +4 -0
  55. data/examples/ruby-on-rails-api/descope/app/channels/application_cable/connection.rb +4 -0
  56. data/examples/ruby-on-rails-api/descope/app/controllers/application_controller.rb +2 -0
  57. data/examples/ruby-on-rails-api/descope/app/controllers/concerns/.keep +0 -0
  58. data/examples/ruby-on-rails-api/descope/app/controllers/homepage_controller.rb +4 -0
  59. data/examples/ruby-on-rails-api/descope/app/controllers/session_controller.rb +66 -0
  60. data/examples/ruby-on-rails-api/descope/app/helpers/application_helper.rb +2 -0
  61. data/examples/ruby-on-rails-api/descope/app/helpers/homepage_helper.rb +2 -0
  62. data/examples/ruby-on-rails-api/descope/app/helpers/session_helper.rb +2 -0
  63. data/examples/ruby-on-rails-api/descope/app/javascript/App.css +53 -0
  64. data/examples/ruby-on-rails-api/descope/app/javascript/application.js +5 -0
  65. data/examples/ruby-on-rails-api/descope/app/javascript/components/App.jsx +4 -0
  66. data/examples/ruby-on-rails-api/descope/app/javascript/components/Dashboard.jsx +60 -0
  67. data/examples/ruby-on-rails-api/descope/app/javascript/components/Home.jsx +27 -0
  68. data/examples/ruby-on-rails-api/descope/app/javascript/components/Login.jsx +45 -0
  69. data/examples/ruby-on-rails-api/descope/app/javascript/components/Profile.jsx +81 -0
  70. data/examples/ruby-on-rails-api/descope/app/javascript/components/index.html +11 -0
  71. data/examples/ruby-on-rails-api/descope/app/javascript/components/index.jsx +24 -0
  72. data/examples/ruby-on-rails-api/descope/app/javascript/controllers/application.js +9 -0
  73. data/examples/ruby-on-rails-api/descope/app/javascript/controllers/index.js +5 -0
  74. data/examples/ruby-on-rails-api/descope/app/javascript/reportWebVitals.js +13 -0
  75. data/examples/ruby-on-rails-api/descope/app/javascript/routes/index.jsx +17 -0
  76. data/examples/ruby-on-rails-api/descope/app/jobs/application_job.rb +7 -0
  77. data/examples/ruby-on-rails-api/descope/app/mailers/application_mailer.rb +4 -0
  78. data/examples/ruby-on-rails-api/descope/app/models/application_record.rb +3 -0
  79. data/examples/ruby-on-rails-api/descope/app/models/concerns/.keep +0 -0
  80. data/examples/ruby-on-rails-api/descope/app/views/homepage/index.html.erb +2 -0
  81. data/examples/ruby-on-rails-api/descope/app/views/layouts/application.html.erb +16 -0
  82. data/examples/ruby-on-rails-api/descope/app/views/layouts/mailer.html.erb +13 -0
  83. data/examples/ruby-on-rails-api/descope/app/views/layouts/mailer.text.erb +1 -0
  84. data/examples/ruby-on-rails-api/descope/app/views/session/index.html.erb +2 -0
  85. data/examples/ruby-on-rails-api/descope/bin/bundle +109 -0
  86. data/examples/ruby-on-rails-api/descope/bin/dev +11 -0
  87. data/examples/ruby-on-rails-api/descope/bin/docker-entrypoint +8 -0
  88. data/examples/ruby-on-rails-api/descope/bin/rails +4 -0
  89. data/examples/ruby-on-rails-api/descope/bin/rake +4 -0
  90. data/examples/ruby-on-rails-api/descope/bin/setup +36 -0
  91. data/examples/ruby-on-rails-api/descope/build.js +30 -0
  92. data/examples/ruby-on-rails-api/descope/config/application.rb +42 -0
  93. data/examples/ruby-on-rails-api/descope/config/boot.rb +4 -0
  94. data/examples/ruby-on-rails-api/descope/config/cable.yml +10 -0
  95. data/examples/ruby-on-rails-api/descope/config/config.yml +9 -0
  96. data/examples/ruby-on-rails-api/descope/config/credentials.yml.enc +1 -0
  97. data/examples/ruby-on-rails-api/descope/config/database.yml +25 -0
  98. data/examples/ruby-on-rails-api/descope/config/environment.rb +5 -0
  99. data/examples/ruby-on-rails-api/descope/config/environments/development.rb +76 -0
  100. data/examples/ruby-on-rails-api/descope/config/environments/production.rb +97 -0
  101. data/examples/ruby-on-rails-api/descope/config/environments/test.rb +64 -0
  102. data/examples/ruby-on-rails-api/descope/config/initializers/assets.rb +13 -0
  103. data/examples/ruby-on-rails-api/descope/config/initializers/content_security_policy.rb +25 -0
  104. data/examples/ruby-on-rails-api/descope/config/initializers/filter_parameter_logging.rb +8 -0
  105. data/examples/ruby-on-rails-api/descope/config/initializers/inflections.rb +16 -0
  106. data/examples/ruby-on-rails-api/descope/config/initializers/load_config.rb +12 -0
  107. data/examples/ruby-on-rails-api/descope/config/initializers/permissions_policy.rb +13 -0
  108. data/examples/ruby-on-rails-api/descope/config/locales/en.yml +31 -0
  109. data/examples/ruby-on-rails-api/descope/config/puma.rb +35 -0
  110. data/examples/ruby-on-rails-api/descope/config/routes.rb +18 -0
  111. data/examples/ruby-on-rails-api/descope/config/storage.yml +34 -0
  112. data/examples/ruby-on-rails-api/descope/config.ru +6 -0
  113. data/examples/ruby-on-rails-api/descope/db/seeds.rb +9 -0
  114. data/examples/ruby-on-rails-api/descope/lib/assets/.keep +0 -0
  115. data/examples/ruby-on-rails-api/descope/lib/tasks/.keep +0 -0
  116. data/examples/ruby-on-rails-api/descope/log/.keep +0 -0
  117. data/examples/ruby-on-rails-api/descope/package-lock.json +19680 -0
  118. data/examples/ruby-on-rails-api/descope/package.json +51 -0
  119. data/examples/ruby-on-rails-api/descope/public/404.html +67 -0
  120. data/examples/ruby-on-rails-api/descope/public/422.html +67 -0
  121. data/examples/ruby-on-rails-api/descope/public/500.html +66 -0
  122. data/examples/ruby-on-rails-api/descope/public/apple-touch-icon-precomposed.png +0 -0
  123. data/examples/ruby-on-rails-api/descope/public/apple-touch-icon.png +0 -0
  124. data/examples/ruby-on-rails-api/descope/public/favicon.ico +0 -0
  125. data/examples/ruby-on-rails-api/descope/public/robots.txt +1 -0
  126. data/examples/ruby-on-rails-api/descope/storage/.keep +0 -0
  127. data/examples/ruby-on-rails-api/descope/tmp/.keep +0 -0
  128. data/examples/ruby-on-rails-api/descope/tmp/pids/.keep +0 -0
  129. data/examples/ruby-on-rails-api/descope/tmp/storage/.keep +0 -0
  130. data/examples/ruby-on-rails-api/descope/vendor/.keep +0 -0
  131. data/examples/ruby-on-rails-api/descope/yarn.lock +10780 -0
  132. data/lib/descope/api/v1/auth/enchantedlink.rb +156 -0
  133. data/lib/descope/api/v1/auth/magiclink.rb +170 -0
  134. data/lib/descope/api/v1/auth/oauth.rb +72 -0
  135. data/lib/descope/api/v1/auth/otp.rb +186 -0
  136. data/lib/descope/api/v1/auth/password.rb +100 -0
  137. data/lib/descope/api/v1/auth/saml.rb +48 -0
  138. data/lib/descope/api/v1/auth/totp.rb +72 -0
  139. data/lib/descope/api/v1/auth.rb +452 -0
  140. data/lib/descope/api/v1/management/access_key.rb +81 -0
  141. data/lib/descope/api/v1/management/audit.rb +82 -0
  142. data/lib/descope/api/v1/management/authz.rb +165 -0
  143. data/lib/descope/api/v1/management/common.rb +147 -0
  144. data/lib/descope/api/v1/management/flow.rb +55 -0
  145. data/lib/descope/api/v1/management/password.rb +58 -0
  146. data/lib/descope/api/v1/management/permission.rb +48 -0
  147. data/lib/descope/api/v1/management/project.rb +53 -0
  148. data/lib/descope/api/v1/management/role.rb +48 -0
  149. data/lib/descope/api/v1/management/scim.rb +206 -0
  150. data/lib/descope/api/v1/management/sso_settings.rb +153 -0
  151. data/lib/descope/api/v1/management/tenant.rb +71 -0
  152. data/lib/descope/api/v1/management/user.rb +619 -0
  153. data/lib/descope/api/v1/management.rb +38 -0
  154. data/lib/descope/api/v1/session.rb +84 -0
  155. data/lib/descope/api/v1.rb +13 -0
  156. data/lib/descope/client.rb +6 -0
  157. data/lib/descope/exception.rb +50 -0
  158. data/lib/descope/mixins/common.rb +129 -0
  159. data/lib/descope/mixins/headers.rb +15 -0
  160. data/lib/descope/mixins/http.rb +133 -0
  161. data/lib/descope/mixins/initializer.rb +80 -0
  162. data/lib/descope/mixins/logging.rb +30 -0
  163. data/lib/descope/mixins/validation.rb +79 -0
  164. data/lib/descope/mixins.rb +22 -0
  165. data/lib/descope/version.rb +7 -0
  166. data/lib/descope.rb +9 -0
  167. data/lib/descope_client.rb +5 -0
  168. data/release-please-config.json +18 -0
  169. data/renovate.json +6 -0
  170. data/spec/factories/user.rb +16 -0
  171. data/spec/lib.descope/api/v1/auth/enchantedlink_spec.rb +159 -0
  172. data/spec/lib.descope/api/v1/auth/magiclink_spec.rb +282 -0
  173. data/spec/lib.descope/api/v1/auth/oauth_spec.rb +117 -0
  174. data/spec/lib.descope/api/v1/auth/otp_spec.rb +285 -0
  175. data/spec/lib.descope/api/v1/auth/password_spec.rb +124 -0
  176. data/spec/lib.descope/api/v1/auth/saml_spec.rb +55 -0
  177. data/spec/lib.descope/api/v1/auth/totp_spec.rb +70 -0
  178. data/spec/lib.descope/api/v1/auth_spec.rb +372 -0
  179. data/spec/lib.descope/api/v1/management/access_key_spec.rb +118 -0
  180. data/spec/lib.descope/api/v1/management/audit_spec.rb +78 -0
  181. data/spec/lib.descope/api/v1/management/authz_spec.rb +336 -0
  182. data/spec/lib.descope/api/v1/management/flow_spec.rb +78 -0
  183. data/spec/lib.descope/api/v1/management/password_spec.rb +25 -0
  184. data/spec/lib.descope/api/v1/management/permission_spec.rb +81 -0
  185. data/spec/lib.descope/api/v1/management/project_spec.rb +63 -0
  186. data/spec/lib.descope/api/v1/management/role_spec.rb +85 -0
  187. data/spec/lib.descope/api/v1/management/scim_spec.rb +312 -0
  188. data/spec/lib.descope/api/v1/management/sso_settings_spec.rb +172 -0
  189. data/spec/lib.descope/api/v1/management/tenant_spec.rb +141 -0
  190. data/spec/lib.descope/api/v1/management/user_spec.rb +667 -0
  191. data/spec/lib.descope/api/v1/session_spec.rb +117 -0
  192. data/spec/lib.descope/client_spec.rb +40 -0
  193. data/spec/spec_helper.rb +72 -0
  194. data/spec/support/client_config.rb +14 -0
  195. data/spec/support/dummy_class.rb +36 -0
  196. data/spec/support/utils.rb +32 -0
  197. metadata +420 -0
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Descope
4
+ module Api
5
+ module V1
6
+ module Management
7
+ # Management API calls
8
+ module SCIM
9
+ include Descope::Api::V1::Management::Common
10
+
11
+ def scim_search_groups(filter: nil, start_index: nil, count: nil, excluded_attributes: nil)
12
+ # Search SCIM Groups
13
+ url = compose_scim_search_groups_url(filter, start_index, count, excluded_attributes)
14
+ get(url)
15
+ end
16
+
17
+ def scim_create_group(group_id: nil, display_name: nil, members: nil, external_id: nil,
18
+ excluded_attributes: nil)
19
+ # Create SCIM Group
20
+ body = compose_scim_create_group_body(group_id, display_name, members, external_id, excluded_attributes)
21
+ post(SCIM_GROUPS_PATH, body)
22
+ end
23
+
24
+ def scim_load_group(group_id: nil, display_name: nil, external_id: nil, excluded_attributes: nil)
25
+ # Load SCIM Group, using a valid access key.
26
+ validate_scim_group_id(group_id)
27
+ url = compose_scim_create_group_url(group_id, display_name, external_id, excluded_attributes)
28
+ get(url)
29
+ end
30
+
31
+ def scim_update_group(group_id: nil, display_name: nil, members: nil, external_id: nil,
32
+ excluded_attributes: nil)
33
+ # Update SCIM Group, using a valid access key.
34
+ validate_scim_group_id(group_id)
35
+ body = compose_scim_update_group_body(group_id, display_name, members, external_id, excluded_attributes)
36
+ patch("#{SCIM_GROUPS_PATH}/#{group_id}", body)
37
+ end
38
+
39
+ def scim_delete_group(group_id)
40
+ # Delete SCIM Group, using a valid access key.
41
+ validate_scim_group_id(group_id)
42
+ url = "#{SCIM_GROUPS_PATH}/#{group_id}"
43
+ delete(url)
44
+ end
45
+
46
+ def scim_patch_group(group_id: nil, user_id: nil, operations: nil)
47
+ # Patch SCIM Group, using a valid access key.
48
+ validate_scim_group_id(group_id)
49
+ url = compose_scim_patch_group_url(group_id, user_id, operations)
50
+ patch(url)
51
+ end
52
+
53
+ # SCIM Users
54
+ def scim_load_resource_types
55
+ # Load SCIM Resource Types, using a valid access key.
56
+ get(SCIM_RESOURCE_TYPES_PATH)
57
+ end
58
+
59
+ def scim_load_service_provider_config
60
+ # Load SCIM Service Provider Config, using a valid access key.
61
+ get(SCIM_SERVICE_PROVIDER_CONFIG_PATH)
62
+ end
63
+
64
+ def scim_search_users(filter: nil, start_index: nil, count: nil)
65
+ # Search SCIM Users, using a valid access key.
66
+ url = compose_scim_search_users_url(filter, start_index, count)
67
+ get(url)
68
+ end
69
+
70
+ def scim_create_user(user_id: nil, display_name: nil, emails: nil,
71
+ phone_numbers: nil, active: nil, name: nil, user_name: nil)
72
+ # Create SCIM User, using a valid access key.
73
+ validate_user_id(user_id)
74
+ body = compose_scim_create_user_body(user_id, display_name, emails, phone_numbers, active, name, user_name)
75
+ post(SCIM_USERS_PATH, body)
76
+ end
77
+
78
+ def scim_load_user(user_id)
79
+ # Load SCIM User, using a valid access key.
80
+ validate_user_id(user_id)
81
+ url = "#{SCIM_USERS_PATH}/#{user_id}"
82
+ get(url)
83
+ end
84
+
85
+ def scim_update_user(user_id)
86
+ # Update SCIM User, using a valid access key.
87
+ validate_user_id(user_id)
88
+ url = "#{SCIM_USERS_PATH}/#{user_id}"
89
+ patch(url)
90
+ end
91
+
92
+ def scim_delete_user(user_id)
93
+ # Delete SCIM User, using a valid access key.
94
+ validate_user_id(user_id)
95
+ url = "#{SCIM_USERS_PATH}/#{user_id}"
96
+ delete(url)
97
+ end
98
+
99
+ def scim_patch_user(user_id: nil, group_id: nil, operations: nil)
100
+ # Patch SCIM User, using a valid access key.
101
+ validate_user_id(user_id)
102
+ validate_scim_group_id(group_id)
103
+ body = compose_scim_patch_user_body(user_id, group_id, operations)
104
+ patch(SCIM_USERS_PATH, body)
105
+ end
106
+
107
+ private
108
+
109
+ def compose_scim_search_groups_url(filter, start_index, count, excluded_attributes)
110
+ url = "#{SCIM_GROUPS_PATH}?"
111
+ url += "filter=#{filter}&" unless filter.nil?
112
+ url += "startIndex=#{start_index}&" unless start_index.nil?
113
+ url += "count=#{count}&" unless count.nil?
114
+ url += "excludedAttributes=#{excluded_attributes}&" unless excluded_attributes.nil?
115
+ url
116
+ end
117
+
118
+ def compose_scim_create_group_body(group_id, display_name, members, external_id, excluded_attributes)
119
+ body = {}
120
+ body['id'] = group_id unless group_id.nil?
121
+ body['displayName'] = display_name unless display_name.nil?
122
+ body['members'] = members unless members.nil?
123
+ body['externalId'] = external_id unless external_id.nil?
124
+ body['excludedAttributes'] = excluded_attributes unless excluded_attributes.nil?
125
+ body
126
+ end
127
+
128
+ def compose_scim_create_group_url(group_id, display_name, external_id, excluded_attributes)
129
+ display_name = CGI.escape(display_name) unless display_name.nil?
130
+ url = "#{SCIM_GROUPS_PATH}/#{group_id}?"
131
+ url += "displayName=#{display_name}&" unless display_name.nil?
132
+ url += "externalId=#{external_id}&" unless external_id.nil?
133
+ url += "excludedAttributes=#{excluded_attributes}" unless excluded_attributes.nil?
134
+ url
135
+ end
136
+
137
+ def compose_scim_update_group_body(group_id, display_name, members, external_id, excluded_attributes)
138
+ body = {}
139
+ body[:groupId] = group_id unless group_id.nil?
140
+ body[:displayName] = display_name unless display_name.nil?
141
+ body[:members] = members unless members.nil?
142
+ body[:externalId] = external_id unless external_id.nil?
143
+ body[:excludedAttributes] = excluded_attributes unless excluded_attributes.nil?
144
+ body
145
+ end
146
+
147
+ def compose_scim_patch_group_url(group_id, user_id, operations)
148
+ url = "#{SCIM_GROUPS_PATH}/#{group_id}&"
149
+ url += "userId=#{user_id}&" unless user_id.nil?
150
+ url += "operations=#{compose_operations_param(operations)}&" unless operations.nil?
151
+ url
152
+ end
153
+
154
+ def compose_scim_search_users_url(filter, start_index, count)
155
+ url = "#{SCIM_USERS_PATH}?"
156
+ url += "filter=#{filter}&" unless filter.nil?
157
+ url += "startIndex=#{start_index}&" unless start_index.nil?
158
+ url += "count=#{count}&" unless count.nil?
159
+ url
160
+ end
161
+
162
+ def compose_scim_create_user_body(user_id, display_name, emails, phone_numbers, active, name, user_name)
163
+ raise AuthException.new('name must be a hash of these fields: given_name, family_name, last_name') if !name.nil? && !name.is_a?(Hash)
164
+
165
+ body = {}
166
+ body[:userId] = user_id unless user_id.nil?
167
+ body[:displayName] = display_name unless display_name.nil?
168
+ body[:emails] = emails unless emails.nil?
169
+ body[:phoneNumbers] = phone_numbers unless phone_numbers.nil?
170
+ body[:active] = active unless active.nil?
171
+ body[:name] = {} unless name.nil?
172
+ body[:name][:givenName] = name[:given_name] unless name[:given_name].nil?
173
+ body[:name][:familyName] = name[:family_name] unless name[:family_name].nil?
174
+ body[:name][:middleName] = name[:middle_name] unless name[:middle_name].nil?
175
+ body[:userName] = user_name unless user_name.nil?
176
+ body
177
+ end
178
+
179
+ def compose_operations_param(operations)
180
+ operations_params = []
181
+ if operations.is_a?(Array)
182
+ operations.each do |op|
183
+ operations_params << {
184
+ op: op[:op],
185
+ path: op[:path],
186
+ valueString: op[:value_string],
187
+ valueBoolean: op[:value_boolean],
188
+ valueArray: op[:value_array]
189
+ }
190
+ end
191
+ end
192
+ operations_params
193
+ end
194
+
195
+ def compose_scim_patch_user_body(user_id, group_id, operations)
196
+ body = {}
197
+ body[:userId] = user_id unless user_id.nil?
198
+ body[:groupId] = group_id unless group_id.nil?
199
+ body[:operations] = operations unless operations.nil?
200
+ body
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Descope
4
+ module Api
5
+ module V1
6
+ module Management
7
+ # Management API calls
8
+ module SSOSettings
9
+ include Descope::Api::V1::Management::Common
10
+
11
+ def get_sso_settings(tenant_id)
12
+ # Get SSO settings for the provided tenant id.
13
+ get(SSO_SETTINGS_PATH, { tenantId: tenant_id })
14
+ end
15
+
16
+ def delete_sso_settings(tenant_id)
17
+ # Delete SSO settings for the provided tenant id.
18
+ delete(SSO_SETTINGS_PATH, { tenantId: tenant_id })
19
+ end
20
+
21
+ def create_sso_oidc_app(id: nil, name: nil, description: nil, enabled: nil, logo: nil, login_page_url: nil)
22
+ body = {}
23
+ body[:id] = id if id
24
+ body[:name] = name if name
25
+ body[:description] = description if description
26
+ body[:enabled] = enabled if enabled
27
+ body[:logo] = logo if logo
28
+ body[:loginPageUrl] = login_page_url if login_page_url
29
+ post(SSO_OIDC_CREATE_APP_PATH, body)
30
+ end
31
+
32
+ def update_sso_oidc_app(id: nil, name: nil, description: nil, enabled: nil, logo: nil, login_page_url: nil)
33
+ body = {}
34
+ body[:id] = id if id
35
+ body[:name] = name if name
36
+ body[:description] = description if description
37
+ body[:enabled] = enabled if enabled
38
+ body[:logo] = logo if logo
39
+ body[:loginPageUrl] = login_page_url if login_page_url
40
+ put(SSO_OIDC_UPDATE_APP_PATH, body)
41
+ end
42
+
43
+ def configure_sso_oidc(tenant_id: nil, settings: nil, redirect_url: nil, domain: nil)
44
+ raise Descope::ArgumentException.new('SSO settings must be a Hash', code: 400) unless settings.is_a?(Hash)
45
+
46
+ # Configure tenant SSO OIDC Settings, using a valid management key.
47
+ request_params = {
48
+ tenantId: tenant_id,
49
+ settings: compose_settings_body(settings),
50
+ redirectUrl: redirect_url,
51
+ domain:
52
+ }
53
+ post(SSO_OIDC_PATH, request_params)
54
+ end
55
+
56
+ def configure_sso_saml(tenant_id: nil, settings: nil, redirect_url: nil, domain: nil)
57
+ raise Descope::ArgumentException.new('SSO SAML settings must be a Hash', code: 400) unless settings.is_a?(Hash)
58
+
59
+ # Configure tenant SSO SAML Settings, using a valid management key.
60
+ request_params = {
61
+ tenantId: tenant_id,
62
+ settings: compose_settings_body(settings),
63
+ redirectUrl: redirect_url,
64
+ domain:
65
+ }
66
+ post(SSO_SAML_PATH, request_params)
67
+ end
68
+
69
+ def configure_sso_saml_metadata(tenant_id: nil, settings: nil, redirect_url: nil, domain: nil)
70
+ # Configure tenant SSO SAML Metadata, using a valid management key.
71
+ post(SSO_SAML_METADATA_PATH, compose_metadata_body(tenant_id, settings, redirect_url, domain))
72
+ end
73
+
74
+ private
75
+
76
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
77
+ def compose_settings_body(settings)
78
+
79
+ body = {}
80
+ body[:name] = settings[:name] if settings.key?(:name)
81
+ body[:clientId] = settings[:client_id] if settings.key?(:client_id)
82
+ body[:clientSecret] = settings[:client_secret] if settings.key?(:client_secret)
83
+ body[:redirectUrl] = settings[:redirect_url] if settings.key?(:redirect_url)
84
+ body[:authUrl] = settings[:auth_url] if settings.key?(:auth_url)
85
+ body[:tokenUrl] = settings[:token_url] if settings.key?(:token_url)
86
+ body[:userDataUrl] = settings[:user_data_url] if settings.key?(:user_data_url)
87
+ body[:scope] = settings[:scope] if settings.key?(:scope)
88
+ body[:JWKsUrl] = settings[:jwks_url] if settings.key?(:jwks_url)
89
+ user_mappings = settings[:user_attr_mapping] if settings.key?(:user_attr_mapping)
90
+
91
+ # rubocop:disable Metrics/LineLength
92
+ unless user_mappings.nil? || user_mappings.empty?
93
+ body[:userAttrMapping] = {}
94
+ body[:userAttrMapping][:loginId] = user_mappings[:login_id] if settings[:user_attr_mapping].key?(:login_id)
95
+ body[:userAttrMapping][:username] = user_mappings[:username] if settings[:user_attr_mapping].key?(:username)
96
+ body[:userAttrMapping][:name] = user_mappings[:name] if settings[:user_attr_mapping].key?(:name)
97
+ body[:userAttrMapping][:email] = user_mappings[:email] if settings[:user_attr_mapping].key?(:email)
98
+ body[:userAttrMapping][:phoneNumber] = user_mappings[:phone_number] if settings[:user_attr_mapping].key?(:phone_number)
99
+ body[:userAttrMapping][:verifiedEmail] = user_mappings[:verified_email] if settings[:user_attr_mapping].key?(:verified_email)
100
+ body[:userAttrMapping][:verifiedPhone] = user_mappings[:verified_phone] if settings[:user_attr_mapping].key?(:verified_phone)
101
+ body[:userAttrMapping][:picture] = user_mappings[:picture] if settings[:user_attr_mapping].key?(:picture)
102
+ body[:userAttrMapping][:givenName] = user_mappings[:given_name] if settings[:user_attr_mapping].key?(:given_name)
103
+ body[:userAttrMapping][:middleName] = user_mappings[:middle_name] if settings[:user_attr_mapping].key?(:middle_name)
104
+ body[:userAttrMapping][:familyName] = user_mappings[:family_name] if settings[:user_attr_mapping].key?(:family_name)
105
+ end
106
+
107
+ body[:manageProviderTokens] = settings[:manage_provider_tokens] if settings.key?(:manage_provider_tokens)
108
+ body[:callbackDomain] = settings[:callback_domain] if settings.key?(:callback_domain)
109
+ body[:prompt] = settings[:prompt] if settings.key?(:prompt)
110
+ body[:grantType] = settings[:grant_type] if settings.key?(:grant_type)
111
+ body[:issuer] = settings[:issuer] if settings.key?(:issuer)
112
+
113
+ body
114
+ end
115
+
116
+ def compose_metadata_body(tenant_id, settings, redirect_url, domain)
117
+ {
118
+ tenantId: tenant_id,
119
+ settings: compose_settings_body(settings),
120
+ redirectUrl: redirect_url,
121
+ domain:
122
+ }
123
+ end
124
+
125
+ def role_mapping_to_hash(role_mapping)
126
+ role_mapping ||= []
127
+ role_mapping_list = []
128
+ role_mapping.each do |mapping|
129
+ role_mapping_list << {
130
+ groups: mapping['groups'],
131
+ roleName: mapping['role_name']
132
+ }
133
+ end
134
+ role_mapping_list
135
+ end
136
+
137
+ def attribute_mapping_to_hash(attribute_mapping)
138
+ if attribute_mapping.nil?
139
+ raise Descope::ArgumentException.new('SSO Attribute mapping cannot be None', code: 400)
140
+ end
141
+
142
+ {
143
+ name: attribute_mapping['name'],
144
+ email: attribute_mapping['email'],
145
+ phoneNumber: attribute_mapping['phone_number'],
146
+ groups: attribute_mapping['groups']
147
+ }
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Descope
4
+ module Api
5
+ module V1
6
+ module Management
7
+ # Management API calls
8
+ module Tenant
9
+ include Descope::Mixins::Validation
10
+ include Descope::Api::V1::Management::Common
11
+
12
+
13
+ def create_tenant(name: nil, id: nil, self_provisioning_domains: nil, custom_attributes: nil)
14
+ # Create a new tenant with the given name. Tenant IDs are provisioned automatically, but can be provided
15
+ # explicitly if needed. Both the name and ID must be unique per project.
16
+ # @see https://docs.descope.com/api/openapi/tenantmanagement/operation/CreateTenant/
17
+
18
+ self_provisioning_domains ||= []
19
+ custom_attributes ||= {}
20
+ post(TENANT_CREATE_PATH, compose_tenant_create_update_body(name, id, self_provisioning_domains, custom_attributes))
21
+ end
22
+
23
+ def update_tenant(name: nil, id: nil, self_provisioning_domains: nil, custom_attributes: nil)
24
+ # Update an existing tenant with the given name and domains. IMPORTANT: All parameters are used as overrides
25
+ # to the existing tenant. Empty fields will override populated fields. Use carefully.
26
+ # @see https://docs.descope.com/api/openapi/tenantmanagement/operation/UpdateTenant/
27
+ self_provisioning_domains ||= []
28
+ custom_attributes ||= {}
29
+ post(TENANT_UPDATE_PATH, compose_tenant_create_update_body(name, id, self_provisioning_domains, custom_attributes))
30
+ end
31
+
32
+ def delete_tenant(id = nil)
33
+ # Delete an existing tenant. IMPORTANT: This action is irreversible. Use carefully.
34
+ post(TENANT_DELETE_PATH, { id: })
35
+ end
36
+
37
+ def load_tenant(id = nil)
38
+ # Load tenant by id.
39
+ get(TENANT_LOAD_PATH, { id: })
40
+ end
41
+
42
+ def load_all_tenants
43
+ # Load all tenants.
44
+ get(TENANT_LOAD_ALL_PATH)
45
+ end
46
+
47
+ def search_all_tenants(ids: nil, names: nil, self_provisioning_domains: nil, custom_attributes: nil)
48
+ # Search all tenants.
49
+ request_params = {
50
+ ids:,
51
+ names:,
52
+ selfProvisioningDomains: self_provisioning_domains,
53
+ customAttributes: custom_attributes
54
+ }
55
+ post(TENANT_SEARCH_ALL_PATH, request_params)
56
+ end
57
+
58
+ private
59
+
60
+ def compose_tenant_create_update_body(name, id, self_provisioning_domains, custom_attributes)
61
+ body = { name:, id: }
62
+ body[:selfProvisioningDomains] = self_provisioning_domains unless self_provisioning_domains.empty?
63
+ body[:customAttributes] = custom_attributes unless custom_attributes.empty?
64
+
65
+ body
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end