descope 1.0.5 → 1.0.7
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yaml +2 -2
- data/.github/workflows/publish-gem.yaml +39 -7
- data/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/Gemfile +7 -7
- data/Gemfile.lock +70 -65
- data/README.md +175 -52
- data/descope.gemspec +25 -20
- data/examples/ruby/.ruby-version +1 -0
- data/examples/ruby/access_key_app.rb +4 -3
- data/examples/ruby/enchantedlink_app.rb +1 -0
- data/examples/ruby/magiclink_app.rb +1 -0
- data/examples/ruby/management/.ruby-version +1 -0
- data/examples/ruby/management/Gemfile +2 -2
- data/examples/ruby/management/access_key_app.rb +2 -0
- data/examples/ruby/management/audit_app.rb +32 -8
- data/examples/ruby/management/authz_app.rb +1 -0
- data/examples/ruby/management/flow_app.rb +1 -0
- data/examples/ruby/management/permission_app.rb +3 -2
- data/examples/ruby/management/role_app.rb +3 -2
- data/examples/ruby/management/tenant_app.rb +1 -0
- data/examples/ruby/management/user_app.rb +1 -0
- data/examples/ruby/oauth_app.rb +1 -0
- data/examples/ruby/otp_app.rb +38 -12
- data/examples/ruby/password_app.rb +8 -7
- data/examples/ruby/saml_app.rb +1 -0
- data/examples/ruby/version_check.rb +17 -0
- data/examples/ruby-on-rails-api/descope/Gemfile +9 -7
- data/examples/ruby-on-rails-api/descope/Gemfile.lock +121 -90
- data/examples/ruby-on-rails-api/descope/README.md +18 -18
- data/examples/ruby-on-rails-api/descope/app/assets/builds/application.css +20092 -23
- data/examples/ruby-on-rails-api/descope/app/assets/builds/application.js +0 -1
- data/examples/ruby-on-rails-api/descope/app/assets/builds/components/index.js +0 -14
- data/examples/ruby-on-rails-api/descope/package-lock.json +1073 -19302
- data/examples/ruby-on-rails-api/descope/package.json +8 -16
- data/examples/ruby-on-rails-api/descope/yarn.lock +557 -10641
- data/lib/descope/api/v1/auth/enchantedlink.rb +3 -1
- data/lib/descope/api/v1/auth/magiclink.rb +3 -1
- data/lib/descope/api/v1/auth/otp.rb +24 -15
- data/lib/descope/api/v1/auth/password.rb +6 -2
- data/lib/descope/api/v1/auth/totp.rb +3 -1
- data/lib/descope/api/v1/auth.rb +64 -32
- data/lib/descope/api/v1/management/audit.rb +24 -0
- data/lib/descope/api/v1/management/common.rb +21 -5
- data/lib/descope/api/v1/management/sso_application.rb +236 -0
- data/lib/descope/api/v1/management/sso_settings.rb +2 -24
- data/lib/descope/api/v1/management/user.rb +151 -13
- data/lib/descope/api/v1/management.rb +2 -0
- data/lib/descope/api/v1/session.rb +37 -4
- data/lib/descope/mixins/common.rb +6 -2
- data/lib/descope/mixins/http.rb +60 -9
- data/lib/descope/mixins/initializer.rb +2 -1
- data/lib/descope/mixins/logging.rb +12 -4
- data/lib/descope/mixins/validation.rb +21 -6
- data/lib/descope/version.rb +1 -1
- data/spec/descope/api/v1/auth_spec.rb +29 -0
- data/spec/descope/api/v1/auth_token_extraction_spec.rb +126 -0
- data/spec/descope/api/v1/session_refresh_spec.rb +98 -0
- data/spec/factories/user.rb +1 -1
- data/spec/integration/lib.descope/api/v1/auth/enchantedlink_spec.rb +1 -1
- data/spec/integration/lib.descope/api/v1/auth/magiclink_spec.rb +1 -1
- data/spec/integration/lib.descope/api/v1/auth/otp_spec.rb +73 -8
- data/spec/integration/lib.descope/api/v1/auth/session_spec.rb +49 -0
- data/spec/integration/lib.descope/api/v1/auth/totp_spec.rb +1 -1
- data/spec/integration/lib.descope/api/v1/management/access_key_spec.rb +3 -0
- data/spec/integration/lib.descope/api/v1/management/audit_spec.rb +38 -0
- data/spec/integration/lib.descope/api/v1/management/authz_spec.rb +2 -0
- data/spec/integration/lib.descope/api/v1/management/flow_spec.rb +3 -1
- data/spec/integration/lib.descope/api/v1/management/permissions_spec.rb +4 -2
- data/spec/integration/lib.descope/api/v1/management/project_spec.rb +2 -0
- data/spec/integration/lib.descope/api/v1/management/roles_spec.rb +3 -1
- data/spec/integration/lib.descope/api/v1/management/user_spec.rb +55 -6
- data/spec/lib.descope/api/v1/auth/enchantedlink_spec.rb +11 -2
- data/spec/lib.descope/api/v1/auth/otp_spec.rb +176 -18
- data/spec/lib.descope/api/v1/auth/password_spec.rb +10 -1
- data/spec/lib.descope/api/v1/auth_spec.rb +168 -6
- data/spec/lib.descope/api/v1/cookie_domain_fix_integration_spec.rb +245 -0
- data/spec/lib.descope/api/v1/management/audit_spec.rb +92 -0
- data/spec/lib.descope/api/v1/management/sso_application_spec.rb +217 -0
- data/spec/lib.descope/api/v1/management/sso_settings_spec.rb +2 -2
- data/spec/lib.descope/api/v1/management/user_spec.rb +134 -46
- data/spec/lib.descope/api/v1/session_spec.rb +119 -6
- data/spec/lib.descope/mixins/http_spec.rb +218 -0
- data/spec/support/client_config.rb +0 -1
- data/spec/support/utils.rb +6 -0
- metadata +34 -137
- data/examples/ruby-on-rails-api/descope/app/assets/builds/reportWebVitals.js +0 -211
- data/examples/ruby-on-rails-api/descope/app/assets/builds/reportWebVitals.js.map +0 -7
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Descope::Api::V1::Management::SSOApplication do
|
|
6
|
+
before(:all) do
|
|
7
|
+
dummy_instance = DummyClass.new
|
|
8
|
+
dummy_instance.extend(Descope::Api::V1::Management::SSOApplication)
|
|
9
|
+
@instance = dummy_instance
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
context('.create_sso_oidc_application') do
|
|
13
|
+
it 'should respond to .create_saml_application' do
|
|
14
|
+
expect(@instance).to respond_to :create_saml_application
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'is expected to create SAML application' do
|
|
18
|
+
expect(@instance).to receive(:post).with(
|
|
19
|
+
SSO_APPLICATION_OIDC_CREATE_PATH, {
|
|
20
|
+
id: 'tenant1',
|
|
21
|
+
name: 'test',
|
|
22
|
+
description: 'awesome tenant',
|
|
23
|
+
enabled: true,
|
|
24
|
+
logo: 'https://logo.com',
|
|
25
|
+
loginPageUrl: 'https://dummy.com/login'
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
expect do
|
|
29
|
+
@instance.create_sso_oidc_app(
|
|
30
|
+
id: 'tenant1',
|
|
31
|
+
name: 'test',
|
|
32
|
+
description: 'awesome tenant',
|
|
33
|
+
enabled: true,
|
|
34
|
+
logo: 'https://logo.com',
|
|
35
|
+
login_page_url: 'https://dummy.com/login'
|
|
36
|
+
)
|
|
37
|
+
end.not_to raise_error
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context('.create_saml_application') do
|
|
42
|
+
it 'should respond to .create_saml_application' do
|
|
43
|
+
expect(@instance).to respond_to :create_saml_application
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'is expected to create SAML application' do
|
|
47
|
+
expect(@instance).to receive(:post).with(
|
|
48
|
+
SSO_APPLICATION_SAML_CREATE_PATH, {
|
|
49
|
+
name: 'test',
|
|
50
|
+
description: 'awesome tenant',
|
|
51
|
+
id: 'tenant1',
|
|
52
|
+
loginPageUrl: 'https://dummy.com/login',
|
|
53
|
+
logo: 'https://logo.com',
|
|
54
|
+
enabled: true,
|
|
55
|
+
useMetadataInfo: true,
|
|
56
|
+
metadataUrl: 'https://dummy.com/metadata',
|
|
57
|
+
entityId: 'ent1234',
|
|
58
|
+
acsUrl: 'https://dummy.com/acs',
|
|
59
|
+
certificate: 'something',
|
|
60
|
+
attributeMapping: [
|
|
61
|
+
{
|
|
62
|
+
'abc': '123'
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
groupsMapping: [
|
|
66
|
+
{
|
|
67
|
+
'abc': '123'
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
acsAllowedCallbacks: true,
|
|
71
|
+
subjectNameIdType: 'test',
|
|
72
|
+
subjectNameIdFormat: 'test',
|
|
73
|
+
defaultRelayState: 'test',
|
|
74
|
+
forceAuthentication: true,
|
|
75
|
+
logoutRedirectUrl: 'https://dummy.com/logout'
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
expect do
|
|
79
|
+
@instance.create_saml_application(
|
|
80
|
+
name: 'test',
|
|
81
|
+
login_page_url: 'https://dummy.com/login',
|
|
82
|
+
id: 'tenant1',
|
|
83
|
+
description: 'awesome tenant',
|
|
84
|
+
logo: 'https://logo.com',
|
|
85
|
+
enabled: true,
|
|
86
|
+
use_metadata_info: true,
|
|
87
|
+
metadata_url: 'https://dummy.com/metadata',
|
|
88
|
+
entity_id: 'ent1234',
|
|
89
|
+
acs_url: 'https://dummy.com/acs',
|
|
90
|
+
certificate: 'something',
|
|
91
|
+
attribute_mapping: [
|
|
92
|
+
{
|
|
93
|
+
'abc': '123'
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
groups_mapping: [
|
|
97
|
+
{
|
|
98
|
+
'abc': '123'
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
acs_allowed_callbacks: true,
|
|
102
|
+
subject_name_id_type: 'test',
|
|
103
|
+
subject_name_id_format: 'test',
|
|
104
|
+
default_relay_state: 'test',
|
|
105
|
+
force_authentication: true,
|
|
106
|
+
logout_redirect_url: 'https://dummy.com/logout'
|
|
107
|
+
)
|
|
108
|
+
end.not_to raise_error
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'is expected to raise error if metadata_url is empty' do
|
|
112
|
+
expect do
|
|
113
|
+
@instance.create_saml_application(
|
|
114
|
+
name: 'test',
|
|
115
|
+
login_page_url: 'https://dummy.com/login',
|
|
116
|
+
id: 'tenant1',
|
|
117
|
+
description: 'awesome tenant',
|
|
118
|
+
logo: 'https://logo.com',
|
|
119
|
+
enabled: true,
|
|
120
|
+
use_metadata_info: true,
|
|
121
|
+
entity_id: 'ent1234',
|
|
122
|
+
acs_url: 'https://dummy.com/acs',
|
|
123
|
+
certificate: 'something',
|
|
124
|
+
attribute_mapping: [
|
|
125
|
+
{
|
|
126
|
+
'abc': '123'
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
groups_mapping: [
|
|
130
|
+
{
|
|
131
|
+
'abc': '123'
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
acs_allowed_callbacks: true,
|
|
135
|
+
subject_name_id_type: 'test',
|
|
136
|
+
subject_name_id_format: 'test',
|
|
137
|
+
default_relay_state: 'test',
|
|
138
|
+
force_authentication: true,
|
|
139
|
+
logout_redirect_url: 'https://dummy.com/logout'
|
|
140
|
+
)
|
|
141
|
+
end.to raise_error(Descope::ArgumentException, 'metadata_url argument must be set')
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it 'is expected to raise error if entity_id acs_url and certificate arguments are missing' do
|
|
146
|
+
expect do
|
|
147
|
+
@instance.create_saml_application(
|
|
148
|
+
name: 'test',
|
|
149
|
+
login_page_url: 'https://dummy.com/login',
|
|
150
|
+
id: 'tenant1',
|
|
151
|
+
description: 'awesome tenant',
|
|
152
|
+
logo: 'https://logo.com',
|
|
153
|
+
enabled: true,
|
|
154
|
+
attribute_mapping: [
|
|
155
|
+
{
|
|
156
|
+
'abc': '123'
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
groups_mapping: [
|
|
160
|
+
{
|
|
161
|
+
'abc': '123'
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
acs_allowed_callbacks: true,
|
|
165
|
+
subject_name_id_type: 'test',
|
|
166
|
+
subject_name_id_format: 'test',
|
|
167
|
+
default_relay_state: 'test',
|
|
168
|
+
force_authentication: true,
|
|
169
|
+
logout_redirect_url: 'https://dummy.com/logout'
|
|
170
|
+
)
|
|
171
|
+
end.to raise_error(Descope::ArgumentException, 'entity_id, acs_url, certificate arguments must be set')
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'is expected to update sso oidc application' do
|
|
175
|
+
expect(@instance).to receive(:post).with(
|
|
176
|
+
SSO_APPLICATION_OIDC_UPDATE_PATH, {
|
|
177
|
+
id: 'tenant1',
|
|
178
|
+
name: 'test',
|
|
179
|
+
description: 'awesome tenant',
|
|
180
|
+
enabled: true,
|
|
181
|
+
logo: 'https://logo.com',
|
|
182
|
+
loginPageUrl: 'https://dummy.com/login'
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
expect do
|
|
186
|
+
@instance.update_sso_oidc_app(
|
|
187
|
+
id: 'tenant1',
|
|
188
|
+
name: 'test',
|
|
189
|
+
description: 'awesome tenant',
|
|
190
|
+
enabled: true,
|
|
191
|
+
logo: 'https://logo.com',
|
|
192
|
+
login_page_url: 'https://dummy.com/login'
|
|
193
|
+
)
|
|
194
|
+
end.not_to raise_error
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it 'is expected to delete sso app' do
|
|
198
|
+
expect(@instance).to receive(:delete).with(
|
|
199
|
+
SSO_APPLICATION_DELETE_PATH, { id: 'tenant1' }
|
|
200
|
+
)
|
|
201
|
+
expect { @instance.delete_sso_app('tenant1') }.not_to raise_error
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it 'is expected to load sso app' do
|
|
205
|
+
expect(@instance).to receive(:get).with(
|
|
206
|
+
SSO_APPLICATION_LOAD_PATH, { id: 'tenant1' }
|
|
207
|
+
)
|
|
208
|
+
expect { @instance.load_sso_app('tenant1') }.not_to raise_error
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it 'is expected to load all sso apps' do
|
|
212
|
+
expect(@instance).to receive(:get).with(
|
|
213
|
+
SSO_APPLICATION_LOAD_ALL_PATH, {}
|
|
214
|
+
)
|
|
215
|
+
expect { @instance.load_all_sso_apps }.not_to raise_error
|
|
216
|
+
end
|
|
217
|
+
end
|
|
@@ -87,7 +87,7 @@ describe Descope::Api::V1::Management::SSOSettings do
|
|
|
87
87
|
|
|
88
88
|
it 'is expected to configure SSO settings' do
|
|
89
89
|
expect(@instance).to receive(:post).with(
|
|
90
|
-
|
|
90
|
+
SSO_SETTINGS_PATH, {
|
|
91
91
|
tenantId: '123',
|
|
92
92
|
settings: {
|
|
93
93
|
name: 'test',
|
|
@@ -132,7 +132,7 @@ describe Descope::Api::V1::Management::SSOSettings do
|
|
|
132
132
|
|
|
133
133
|
it 'is expected to configure SAML metadata' do
|
|
134
134
|
expect(@instance).to receive(:post).with(
|
|
135
|
-
|
|
135
|
+
SSO_METADATA_PATH, {
|
|
136
136
|
tenantId: '123',
|
|
137
137
|
settings: {
|
|
138
138
|
name: 'test',
|
|
@@ -9,55 +9,69 @@ describe Descope::Api::V1::Management::User do
|
|
|
9
9
|
@instance = dummy_instance
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
context '.
|
|
12
|
+
context '.create_user_and_test_user' do
|
|
13
13
|
it 'is expected to respond to a user create method' do
|
|
14
14
|
expect(@instance).to respond_to(:create_user)
|
|
15
|
+
expect(@instance).to respond_to(:create_test_user)
|
|
15
16
|
end
|
|
16
17
|
|
|
18
|
+
user_tenants_args = [
|
|
19
|
+
{
|
|
20
|
+
tenant_id: 'tenant1'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
tenant_id: 'tenant2',
|
|
24
|
+
role_names: %w[role1 role2]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
params = {
|
|
29
|
+
loginId: 'name@mail.com',
|
|
30
|
+
email: 'name@mail.com',
|
|
31
|
+
phone: '+1-212-669-2542',
|
|
32
|
+
name: 'name',
|
|
33
|
+
givenName: 'name',
|
|
34
|
+
familyName: 'Ruby SDK',
|
|
35
|
+
userTenants: associated_tenants_to_hash_array(user_tenants_args),
|
|
36
|
+
test: false,
|
|
37
|
+
picture: 'https://www.example.com/picture.png',
|
|
38
|
+
customAttributes: { 'attr1' => 'value1', 'attr2' => 'value2' },
|
|
39
|
+
additionalIdentifiers: %w[id-1 id-2],
|
|
40
|
+
password: 's3cr3t',
|
|
41
|
+
ssoAppIds: %w[app1 app2],
|
|
42
|
+
invite: false
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
args = {
|
|
46
|
+
login_id: 'name@mail.com',
|
|
47
|
+
email: 'name@mail.com',
|
|
48
|
+
phone: '+1-212-669-2542',
|
|
49
|
+
name: 'name',
|
|
50
|
+
given_name: 'name',
|
|
51
|
+
family_name: 'Ruby SDK',
|
|
52
|
+
user_tenants: user_tenants_args,
|
|
53
|
+
picture: 'https://www.example.com/picture.png',
|
|
54
|
+
custom_attributes: { 'attr1' => 'value1', 'attr2' => 'value2' },
|
|
55
|
+
additional_identifiers: %w[id-1 id-2],
|
|
56
|
+
password: 's3cr3t',
|
|
57
|
+
sso_app_ids: %w[app1 app2]
|
|
58
|
+
}
|
|
59
|
+
|
|
17
60
|
it 'is expected to create a user with user data' do
|
|
18
|
-
|
|
19
|
-
{
|
|
20
|
-
tenant_id: 'tenant1'
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
tenant_id: 'tenant2',
|
|
24
|
-
role_names: %w[role1 role2]
|
|
25
|
-
}
|
|
26
|
-
]
|
|
27
|
-
expect(@instance).to receive(:post).with(
|
|
28
|
-
USER_CREATE_PATH, {
|
|
29
|
-
loginId: 'name@mail.com',
|
|
30
|
-
email: 'name@mail.com',
|
|
31
|
-
phone: '+1-212-669-2542',
|
|
32
|
-
name: 'name',
|
|
33
|
-
givenName: 'name',
|
|
34
|
-
familyName: 'Ruby SDK',
|
|
35
|
-
userTenants: associated_tenants_to_hash_array(user_tenants_args),
|
|
36
|
-
test: false,
|
|
37
|
-
picture: 'https://www.example.com/picture.png',
|
|
38
|
-
customAttributes: { 'attr1' => 'value1', 'attr2' => 'value2' },
|
|
39
|
-
additionalIdentifiers: %w[id-1 id-2],
|
|
40
|
-
password: 's3cr3t',
|
|
41
|
-
ssoAppIds: %w[app1 app2],
|
|
42
|
-
invite: false
|
|
43
|
-
}
|
|
44
|
-
)
|
|
61
|
+
expect(@instance).to receive(:post).with(USER_CREATE_PATH, params)
|
|
45
62
|
|
|
46
63
|
expect do
|
|
47
|
-
@instance.create_user(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
password: 's3cr3t',
|
|
59
|
-
sso_app_ids: %w[app1 app2]
|
|
60
|
-
)
|
|
64
|
+
@instance.create_user(**args)
|
|
65
|
+
end.not_to raise_error
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'is expected to create a test user with user data' do
|
|
69
|
+
params[:test] = true
|
|
70
|
+
expect(@instance).to receive(:post).with(TEST_USER_CREATE_PATH, params)
|
|
71
|
+
|
|
72
|
+
expect do
|
|
73
|
+
args[:test] = true
|
|
74
|
+
@instance.create_test_user(**args)
|
|
61
75
|
end.not_to raise_error
|
|
62
76
|
end
|
|
63
77
|
end
|
|
@@ -108,14 +122,16 @@ describe Descope::Api::V1::Management::User do
|
|
|
108
122
|
loginId: 'name@mail.com',
|
|
109
123
|
email: 'name@mail.com',
|
|
110
124
|
test: false,
|
|
111
|
-
invite: true
|
|
125
|
+
invite: true,
|
|
126
|
+
templateId: "tid",
|
|
112
127
|
}
|
|
113
128
|
)
|
|
114
129
|
|
|
115
130
|
expect do
|
|
116
131
|
@instance.invite_user(
|
|
117
132
|
login_id: 'name@mail.com',
|
|
118
|
-
email: 'name@mail.com'
|
|
133
|
+
email: 'name@mail.com',
|
|
134
|
+
template_id: "tid",
|
|
119
135
|
)
|
|
120
136
|
end.not_to raise_error
|
|
121
137
|
end
|
|
@@ -223,6 +239,8 @@ describe Descope::Api::V1::Management::User do
|
|
|
223
239
|
it 'is expected to respond to a search_all method' do
|
|
224
240
|
expect(@instance).to respond_to(:search_all_users)
|
|
225
241
|
|
|
242
|
+
tenant_role_ids = { 'tenant1' => ['roleA', 'roleB'] }
|
|
243
|
+
tenant_role_names = { 'tenant1' => ['roleName1', 'roleName2'] }
|
|
226
244
|
expect(@instance).to receive(:post).with(
|
|
227
245
|
USERS_SEARCH_PATH, {
|
|
228
246
|
loginId: 'someone@example.com',
|
|
@@ -234,7 +252,13 @@ describe Descope::Api::V1::Management::User do
|
|
|
234
252
|
ssoOnly: false,
|
|
235
253
|
text: 'some text',
|
|
236
254
|
testUsersOnly: false,
|
|
237
|
-
withTestUser: false
|
|
255
|
+
withTestUser: false,
|
|
256
|
+
tenantRoleIds: {
|
|
257
|
+
'tenant1' => { values: ['roleA', 'roleB'] }
|
|
258
|
+
},
|
|
259
|
+
tenantRoleNames: {
|
|
260
|
+
'tenant1' => { values: ['roleName1', 'roleName2'] }
|
|
261
|
+
}
|
|
238
262
|
}
|
|
239
263
|
)
|
|
240
264
|
|
|
@@ -248,7 +272,9 @@ describe Descope::Api::V1::Management::User do
|
|
|
248
272
|
page: 1,
|
|
249
273
|
sso_app_ids: [],
|
|
250
274
|
test_users_only: false,
|
|
251
|
-
with_test_user: false
|
|
275
|
+
with_test_user: false,
|
|
276
|
+
tenant_role_ids: tenant_role_ids,
|
|
277
|
+
tenant_role_names: tenant_role_names
|
|
252
278
|
)
|
|
253
279
|
end.not_to raise_error
|
|
254
280
|
end
|
|
@@ -704,4 +730,66 @@ describe Descope::Api::V1::Management::User do
|
|
|
704
730
|
end.not_to raise_error
|
|
705
731
|
end
|
|
706
732
|
end
|
|
733
|
+
|
|
734
|
+
context '.patch_user' do
|
|
735
|
+
it 'is expected to respond to a patch user method' do
|
|
736
|
+
expect(@instance).to respond_to(:patch_user)
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
it 'is expected to respond to a user patch method' do
|
|
740
|
+
expect(@instance).to receive(:patch).with(
|
|
741
|
+
USER_PATCH_PATH, {
|
|
742
|
+
loginId: 'name@mail.com',
|
|
743
|
+
email: 'name@mail.com',
|
|
744
|
+
givenName: 'mister',
|
|
745
|
+
name: 'something else',
|
|
746
|
+
test: false,
|
|
747
|
+
invite: false
|
|
748
|
+
}
|
|
749
|
+
)
|
|
750
|
+
|
|
751
|
+
expect do
|
|
752
|
+
@instance.patch_user(
|
|
753
|
+
login_id: 'name@mail.com',
|
|
754
|
+
email: 'name@mail.com',
|
|
755
|
+
given_name: 'mister',
|
|
756
|
+
name: 'something else'
|
|
757
|
+
)
|
|
758
|
+
end.not_to raise_error
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
context '.search_all_test_users' do
|
|
763
|
+
it 'is expected to respond to a search_all_test_users method' do
|
|
764
|
+
expect(@instance).to respond_to(:search_all_test_users)
|
|
765
|
+
|
|
766
|
+
tenant_role_ids = { 'tenant1' => ['roleA', 'roleB'] }
|
|
767
|
+
tenant_role_names = { 'tenant1' => ['roleName1', 'roleName2'] }
|
|
768
|
+
expect(@instance).to receive(:post).with(
|
|
769
|
+
TEST_USERS_SEARCH_PATH, {
|
|
770
|
+
tenantIds: %w[t1 t2],
|
|
771
|
+
roleNames: %w[r1 r2],
|
|
772
|
+
limit: 0,
|
|
773
|
+
page: 0,
|
|
774
|
+
testUsersOnly: true,
|
|
775
|
+
withTestUser: true,
|
|
776
|
+
tenantRoleIds: {
|
|
777
|
+
'tenant1' => { values: ['roleA', 'roleB'] }
|
|
778
|
+
},
|
|
779
|
+
tenantRoleNames: {
|
|
780
|
+
'tenant1' => { values: ['roleName1', 'roleName2'] }
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
)
|
|
784
|
+
|
|
785
|
+
expect do
|
|
786
|
+
@instance.search_all_test_users(
|
|
787
|
+
tenant_ids: %w[t1 t2],
|
|
788
|
+
role_names: %w[r1 r2],
|
|
789
|
+
tenant_role_ids: tenant_role_ids,
|
|
790
|
+
tenant_role_names: tenant_role_names
|
|
791
|
+
)
|
|
792
|
+
end.not_to raise_error
|
|
793
|
+
end
|
|
794
|
+
end
|
|
707
795
|
end
|
|
@@ -31,12 +31,32 @@ describe Descope::Api::V1::Session do
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
it 'is expected to post refresh session' do
|
|
34
|
-
jwt_response = {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
jwt_response = {
|
|
35
|
+
'sessionJwt' => 'fake_session_jwt',
|
|
36
|
+
'refreshJwt' => 'fake_refresh_jwt',
|
|
37
|
+
'cookies' => {
|
|
38
|
+
'refresh_token' => 'fake_refresh_cookie'
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
refresh_token = 'refresh_token'
|
|
42
|
+
audience = nil
|
|
43
|
+
|
|
44
|
+
allow(@instance).to receive(:validate_refresh_token_not_nil).with(refresh_token).and_return(true)
|
|
45
|
+
allow(@instance).to receive(:validate_token).with(refresh_token, audience).and_return(true)
|
|
46
|
+
allow(@instance).to receive(:post).with(REFRESH_TOKEN_PATH, {}, {}, refresh_token).and_return(jwt_response)
|
|
47
|
+
refresh_cookie = jwt_response['cookies'][REFRESH_SESSION_COOKIE_NAME] || jwt_response['refreshJwt']
|
|
48
|
+
|
|
49
|
+
allow(@instance).to receive(:generate_jwt_response).with(
|
|
50
|
+
response_body: jwt_response,
|
|
51
|
+
refresh_cookie:,
|
|
52
|
+
audience:
|
|
53
|
+
).and_return(jwt_response)
|
|
54
|
+
|
|
55
|
+
expect { @instance.refresh_session(refresh_token:, audience:) }.not_to raise_error
|
|
56
|
+
|
|
57
|
+
# Optionally verify the response if needed
|
|
58
|
+
result = @instance.refresh_session(refresh_token:, audience:)
|
|
59
|
+
expect(result).to eq(jwt_response)
|
|
40
60
|
end
|
|
41
61
|
end
|
|
42
62
|
|
|
@@ -114,4 +134,97 @@ describe Descope::Api::V1::Session do
|
|
|
114
134
|
expect { @instance.validate_and_refresh_session(session_token: 'session_token', refresh_token: 'refresh_token') }.to_not raise_error
|
|
115
135
|
end
|
|
116
136
|
end
|
|
137
|
+
|
|
138
|
+
context 'cookie domain fix for refresh_session' do
|
|
139
|
+
let(:refresh_token) { 'test_refresh_token' }
|
|
140
|
+
let(:session_jwt) { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ0ZXN0In0.signature' }
|
|
141
|
+
let(:refresh_jwt) { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ0ZXN0In0.refresh_sig' }
|
|
142
|
+
|
|
143
|
+
context 'when using cookie-only tokens with custom domain' do
|
|
144
|
+
let(:cookie_only_response) do
|
|
145
|
+
{
|
|
146
|
+
'userId' => 'test123',
|
|
147
|
+
'cookieExpiration' => 1640704758,
|
|
148
|
+
'cookieDomain' => 'dev.lulukuku.com',
|
|
149
|
+
'cookies' => {
|
|
150
|
+
'DS' => session_jwt,
|
|
151
|
+
'DSR' => refresh_jwt
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it 'extracts tokens from cookies when not in response body' do
|
|
157
|
+
allow(@instance).to receive(:validate_refresh_token_not_nil).and_return(true)
|
|
158
|
+
allow(@instance).to receive(:validate_token).and_return({})
|
|
159
|
+
allow(@instance).to receive(:post).and_return(cookie_only_response)
|
|
160
|
+
allow(@instance).to receive(:generate_jwt_response).and_return(cookie_only_response)
|
|
161
|
+
|
|
162
|
+
expect { @instance.refresh_session(refresh_token: refresh_token) }.not_to raise_error
|
|
163
|
+
|
|
164
|
+
result = @instance.refresh_session(refresh_token: refresh_token)
|
|
165
|
+
expect(result).to eq(cookie_only_response)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it 'passes correct refresh_cookie to generate_jwt_response' do
|
|
169
|
+
allow(@instance).to receive(:validate_refresh_token_not_nil).and_return(true)
|
|
170
|
+
allow(@instance).to receive(:validate_token).and_return({})
|
|
171
|
+
allow(@instance).to receive(:post).and_return(cookie_only_response)
|
|
172
|
+
|
|
173
|
+
# Verify that refresh_cookie is extracted correctly from cookies
|
|
174
|
+
expected_refresh_cookie = refresh_jwt
|
|
175
|
+
expect(@instance).to receive(:generate_jwt_response).with(
|
|
176
|
+
response_body: cookie_only_response,
|
|
177
|
+
refresh_cookie: expected_refresh_cookie,
|
|
178
|
+
audience: nil
|
|
179
|
+
).and_return(cookie_only_response)
|
|
180
|
+
|
|
181
|
+
@instance.refresh_session(refresh_token: refresh_token)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
context 'when using mixed configuration (some tokens in body, some in cookies)' do
|
|
186
|
+
let(:mixed_response) do
|
|
187
|
+
{
|
|
188
|
+
'sessionJwt' => session_jwt, # Session token in response body
|
|
189
|
+
'userId' => 'test123',
|
|
190
|
+
'cookies' => {
|
|
191
|
+
'DSR' => refresh_jwt # Refresh token in cookies only
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it 'handles mixed token locations correctly' do
|
|
197
|
+
allow(@instance).to receive(:validate_refresh_token_not_nil).and_return(true)
|
|
198
|
+
allow(@instance).to receive(:validate_token).and_return({})
|
|
199
|
+
allow(@instance).to receive(:post).and_return(mixed_response)
|
|
200
|
+
allow(@instance).to receive(:generate_jwt_response).and_return(mixed_response)
|
|
201
|
+
|
|
202
|
+
expect { @instance.refresh_session(refresh_token: refresh_token) }.not_to raise_error
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
context 'backward compatibility with traditional response body tokens' do
|
|
207
|
+
let(:traditional_response) do
|
|
208
|
+
{
|
|
209
|
+
'sessionJwt' => session_jwt,
|
|
210
|
+
'refreshJwt' => refresh_jwt,
|
|
211
|
+
'userId' => 'test123'
|
|
212
|
+
}
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it 'continues to work with response body tokens' do
|
|
216
|
+
allow(@instance).to receive(:validate_refresh_token_not_nil).and_return(true)
|
|
217
|
+
allow(@instance).to receive(:validate_token).and_return({})
|
|
218
|
+
allow(@instance).to receive(:post).and_return(traditional_response)
|
|
219
|
+
|
|
220
|
+
expect(@instance).to receive(:generate_jwt_response).with(
|
|
221
|
+
response_body: traditional_response,
|
|
222
|
+
refresh_cookie: refresh_jwt, # Should use refreshJwt from response body
|
|
223
|
+
audience: nil
|
|
224
|
+
).and_return(traditional_response)
|
|
225
|
+
|
|
226
|
+
@instance.refresh_session(refresh_token: refresh_token)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
117
230
|
end
|