workos 0.10.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.ruby-version +1 -1
- data/.semaphore/semaphore.yml +8 -2
- data/Gemfile.lock +49 -36
- data/LICENSE +1 -1
- data/README.md +13 -230
- data/lib/workos.rb +5 -0
- data/lib/workos/client.rb +21 -4
- data/lib/workos/connection.rb +12 -1
- data/lib/workos/directory.rb +53 -0
- data/lib/workos/directory_group.rb +44 -0
- data/lib/workos/directory_sync.rb +63 -7
- data/lib/workos/directory_user.rb +63 -0
- data/lib/workos/organizations.rb +150 -0
- data/lib/workos/passwordless.rb +4 -0
- data/lib/workos/portal.rb +0 -80
- data/lib/workos/profile.rb +1 -2
- data/lib/workos/profile_and_token.rb +28 -0
- data/lib/workos/sso.rb +37 -104
- data/lib/workos/types.rb +3 -0
- data/lib/workos/types/connection_struct.rb +3 -0
- data/lib/workos/types/directory_group_struct.rb +13 -0
- data/lib/workos/types/directory_struct.rb +16 -0
- data/lib/workos/types/directory_user_struct.rb +19 -0
- data/lib/workos/version.rb +1 -1
- data/sorbet/rbi/gems/addressable.rbi +199 -0
- data/sorbet/rbi/gems/ast.rbi +49 -0
- data/sorbet/rbi/gems/codecov.rbi +37 -0
- data/sorbet/rbi/gems/crack.rbi +62 -0
- data/sorbet/rbi/gems/docile.rbi +36 -0
- data/sorbet/rbi/gems/hashdiff.rbi +66 -0
- data/sorbet/rbi/gems/parallel.rbi +83 -0
- data/sorbet/rbi/gems/parser.rbi +1429 -0
- data/sorbet/rbi/gems/public_suffix.rbi +104 -0
- data/sorbet/rbi/gems/rainbow.rbi +118 -0
- data/sorbet/rbi/gems/rake.rbi +644 -0
- data/sorbet/rbi/gems/regexp_parser.rbi +926 -0
- data/sorbet/rbi/gems/rexml.rbi +628 -0
- data/sorbet/rbi/gems/rspec-core.rbi +1898 -0
- data/sorbet/rbi/gems/rspec-expectations.rbi +1127 -0
- data/sorbet/rbi/gems/rspec-mocks.rbi +1099 -0
- data/sorbet/rbi/gems/rspec-support.rbi +280 -0
- data/sorbet/rbi/gems/rspec.rbi +15 -0
- data/sorbet/rbi/gems/rubocop-ast.rbi +1355 -0
- data/sorbet/rbi/gems/rubocop.rbi +7253 -0
- data/sorbet/rbi/gems/ruby-progressbar.rbi +304 -0
- data/sorbet/rbi/gems/simplecov-html.rbi +35 -0
- data/sorbet/rbi/gems/simplecov.rbi +406 -0
- data/sorbet/rbi/gems/unicode-display_width.rbi +17 -0
- data/sorbet/rbi/gems/vcr.rbi +572 -0
- data/sorbet/rbi/gems/webmock.rbi +556 -0
- data/sorbet/rbi/gems/yard.rbi +1165 -0
- data/sorbet/rbi/sorbet-typed/lib/rake/all/rake.rbi +645 -0
- data/sorbet/rbi/sorbet-typed/lib/rspec-core/all/rspec-core.rbi +1891 -0
- data/sorbet/rbi/sorbet-typed/lib/rubocop/~>0.85/rubocop.rbi +2072 -0
- data/sorbet/rbi/sorbet-typed/lib/yard/all/yard.rbi +1214 -0
- data/sorbet/rbi/todo.rbi +1 -3
- data/spec/lib/workos/audit_trail_spec.rb +0 -8
- data/spec/lib/workos/directory_sync_spec.rb +347 -40
- data/spec/lib/workos/organizations_spec.rb +164 -0
- data/spec/lib/workos/passwordless_spec.rb +0 -8
- data/spec/lib/workos/portal_spec.rb +0 -121
- data/spec/lib/workos/sso_spec.rb +141 -187
- data/spec/spec_helper.rb +2 -1
- data/spec/support/fixtures/vcr_cassettes/directory_sync/delete_directory.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/{sso/list_connections.yml → directory_sync/list_directories/with_after.yml} +7 -7
- data/spec/support/fixtures/vcr_cassettes/{sso/list_connections_with_limit_param.yml → directory_sync/list_directories/with_before.yml} +8 -8
- data/spec/support/fixtures/vcr_cassettes/{sso/list_connections_with_connection_type_param.yml → directory_sync/list_directories/with_domain.yml} +11 -10
- data/spec/support/fixtures/vcr_cassettes/{sso/list_connections_with_after_param.yml → directory_sync/list_directories/with_limit.yml} +12 -10
- data/spec/support/fixtures/vcr_cassettes/directory_sync/{list_directories.yml → list_directories/with_no_options.yml} +1 -1
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_search.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_after.yml +76 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_before.yml +74 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_directory.yml +78 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_limit.yml +74 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/{list_groups.yml → list_groups/with_no_options.yml} +16 -6
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_user.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_after.yml +86 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_before.yml +75 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_directory.yml +93 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_group.yml +76 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_limit.yml +75 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/{list_users.yml → list_users/with_no_options.yml} +16 -6
- data/spec/support/fixtures/vcr_cassettes/organization/get.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/organization/get_invalid.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/organization/update.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/organization/update_invalid.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_after.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_before.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_connection_type.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/sso/{list_connections_with_domain_param.yml → list_connections/with_domain.yml} +6 -6
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_limit.yml +74 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_no_options.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/sso/{list_connections_with_organization_id_param.yml → list_connections/with_organization_id.yml} +6 -6
- data/workos.gemspec +2 -0
- metadata +109 -44
- data/sorbet/rbi/hidden-definitions/errors.txt +0 -24896
- data/sorbet/rbi/hidden-definitions/hidden.rbi +0 -38411
- data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +0 -8684
- data/sorbet/rbi/sorbet-typed/lib/ruby/all/gem.rbi +0 -4222
- data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +0 -111
- data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +0 -543
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories_with_domain_param.yml +0 -63
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups_with_directory_param.yml +0 -62
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users_with_directory_param.yml +0 -62
- data/spec/support/fixtures/vcr_cassettes/sso/create_connection_with_invalid_source.yml +0 -58
- data/spec/support/fixtures/vcr_cassettes/sso/create_connection_with_valid_source.yml +0 -63
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections_with_before_param.yml +0 -73
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# typed: false
|
|
3
|
+
|
|
4
|
+
describe WorkOS::Organizations do
|
|
5
|
+
describe '.create_organization' do
|
|
6
|
+
context 'with valid payload' do
|
|
7
|
+
it 'creates an organization' do
|
|
8
|
+
VCR.use_cassette 'organization/create' do
|
|
9
|
+
organization = described_class.create_organization(
|
|
10
|
+
domains: ['example.com'],
|
|
11
|
+
name: 'Test Organization',
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
expect(organization.id).to eq('org_01EHT88Z8J8795GZNQ4ZP1J81T')
|
|
15
|
+
expect(organization.name).to eq('Test Organization')
|
|
16
|
+
expect(organization.domains.first[:domain]).to eq('example.com')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'with an invalid payload' do
|
|
22
|
+
it 'returns an error' do
|
|
23
|
+
VCR.use_cassette 'organization/create_invalid' do
|
|
24
|
+
expect do
|
|
25
|
+
described_class.create_organization(
|
|
26
|
+
domains: ['example.com'],
|
|
27
|
+
name: 'Test Organization 2',
|
|
28
|
+
)
|
|
29
|
+
end.to raise_error(
|
|
30
|
+
WorkOS::APIError,
|
|
31
|
+
/An Organization with the domain example.com already exists/,
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '.list_organizations' do
|
|
39
|
+
context 'with no options' do
|
|
40
|
+
it 'returns organizations and metadata' do
|
|
41
|
+
expected_metadata = {
|
|
42
|
+
'after' => nil,
|
|
43
|
+
'before' => 'before-id',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
VCR.use_cassette 'organization/list' do
|
|
47
|
+
organizations = described_class.list_organizations
|
|
48
|
+
|
|
49
|
+
expect(organizations.data.size).to eq(7)
|
|
50
|
+
expect(organizations.list_metadata).to eq(expected_metadata)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context 'with the before option' do
|
|
56
|
+
it 'forms the proper request to the API' do
|
|
57
|
+
request_args = [
|
|
58
|
+
'/organizations?before=before-id',
|
|
59
|
+
'Content-Type' => 'application/json'
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
expected_request = Net::HTTP::Get.new(*request_args)
|
|
63
|
+
|
|
64
|
+
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
65
|
+
and_return(expected_request)
|
|
66
|
+
|
|
67
|
+
VCR.use_cassette 'organization/list', match_requests_on: [:path] do
|
|
68
|
+
organizations = described_class.list_organizations(
|
|
69
|
+
before: 'before-id',
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
expect(organizations.data.size).to eq(7)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context 'with the after option' do
|
|
78
|
+
it 'forms the proper request to the API' do
|
|
79
|
+
request_args = [
|
|
80
|
+
'/organizations?after=after-id',
|
|
81
|
+
'Content-Type' => 'application/json'
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
expected_request = Net::HTTP::Get.new(*request_args)
|
|
85
|
+
|
|
86
|
+
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
87
|
+
and_return(expected_request)
|
|
88
|
+
|
|
89
|
+
VCR.use_cassette 'organization/list', match_requests_on: [:path] do
|
|
90
|
+
organizations = described_class.list_organizations(after: 'after-id')
|
|
91
|
+
|
|
92
|
+
expect(organizations.data.size).to eq(7)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
context 'with the limit option' do
|
|
98
|
+
it 'forms the proper request to the API' do
|
|
99
|
+
request_args = [
|
|
100
|
+
'/organizations?limit=10',
|
|
101
|
+
'Content-Type' => 'application/json'
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
expected_request = Net::HTTP::Get.new(*request_args)
|
|
105
|
+
|
|
106
|
+
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
107
|
+
and_return(expected_request)
|
|
108
|
+
|
|
109
|
+
VCR.use_cassette 'organization/list', match_requests_on: [:path] do
|
|
110
|
+
organizations = described_class.list_organizations(limit: 10)
|
|
111
|
+
|
|
112
|
+
expect(organizations.data.size).to eq(7)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe '.get_organization' do
|
|
119
|
+
context 'with a valid id' do
|
|
120
|
+
it 'gets the organization details' do
|
|
121
|
+
VCR.use_cassette('organization/get') do
|
|
122
|
+
organization = described_class.get_organization(
|
|
123
|
+
id: 'org_01EZDF20TZEJXKPSX2BJRN6TV6',
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
expect(organization.id).to eq('org_01EZDF20TZEJXKPSX2BJRN6TV6')
|
|
127
|
+
expect(organization.name).to eq('Foo Corp')
|
|
128
|
+
expect(organization.domains.first[:domain]).to eq('foo-corp.com')
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
context 'with an invalid id' do
|
|
134
|
+
it 'raises an error' do
|
|
135
|
+
VCR.use_cassette('organization/get_invalid') do
|
|
136
|
+
expect do
|
|
137
|
+
described_class.get_organization(id: 'invalid')
|
|
138
|
+
end.to raise_error(
|
|
139
|
+
WorkOS::APIError,
|
|
140
|
+
'Status 404, Not Found - request ID: ',
|
|
141
|
+
)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
describe '.update_organization' do
|
|
148
|
+
context 'with valid payload' do
|
|
149
|
+
it 'creates an organization' do
|
|
150
|
+
VCR.use_cassette 'organization/update' do
|
|
151
|
+
organization = described_class.update_organization(
|
|
152
|
+
organization: 'org_01F29YJ068E52HGEB8ZQGC9MJG',
|
|
153
|
+
domains: ['example.me'],
|
|
154
|
+
name: 'Test Organization',
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
expect(organization.id).to eq('org_01F29YJ068E52HGEB8ZQGC9MJG')
|
|
158
|
+
expect(organization.name).to eq('Test Organization')
|
|
159
|
+
expect(organization.domains.first[:domain]).to eq('example.me')
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -2,47 +2,6 @@
|
|
|
2
2
|
# typed: false
|
|
3
3
|
|
|
4
4
|
describe WorkOS::Portal do
|
|
5
|
-
before :all do
|
|
6
|
-
WorkOS.key = 'test'
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
after :all do
|
|
10
|
-
WorkOS.key = nil
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
describe '.create_organization' do
|
|
14
|
-
context 'with valid payload' do
|
|
15
|
-
it 'creates an organization' do
|
|
16
|
-
VCR.use_cassette 'organization/create' do
|
|
17
|
-
organization = described_class.create_organization(
|
|
18
|
-
domains: ['example.com'],
|
|
19
|
-
name: 'Test Organization',
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
expect(organization.id).to eq('org_01EHT88Z8J8795GZNQ4ZP1J81T')
|
|
23
|
-
expect(organization.name).to eq('Test Organization')
|
|
24
|
-
expect(organization.domains.first[:domain]).to eq('example.com')
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
context 'with an invalid payload' do
|
|
30
|
-
it 'returns an error' do
|
|
31
|
-
VCR.use_cassette 'organization/create_invalid' do
|
|
32
|
-
expect do
|
|
33
|
-
described_class.create_organization(
|
|
34
|
-
domains: ['example.com'],
|
|
35
|
-
name: 'Test Organization 2',
|
|
36
|
-
)
|
|
37
|
-
end.to raise_error(
|
|
38
|
-
WorkOS::APIError,
|
|
39
|
-
/An Organization with the domain example.com already exists/,
|
|
40
|
-
)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
5
|
describe '.generate_link' do
|
|
47
6
|
let(:organization) { 'org_01EHQMYV6MBK39QC5PZXHY59C3' }
|
|
48
7
|
|
|
@@ -108,84 +67,4 @@ describe WorkOS::Portal do
|
|
|
108
67
|
end
|
|
109
68
|
end
|
|
110
69
|
end
|
|
111
|
-
|
|
112
|
-
describe '.list_organizations' do
|
|
113
|
-
context 'with no options' do
|
|
114
|
-
it 'returns organizations and metadata' do
|
|
115
|
-
expected_metadata = {
|
|
116
|
-
'after' => nil,
|
|
117
|
-
'before' => 'before-id',
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
VCR.use_cassette 'organization/list' do
|
|
121
|
-
organizations = described_class.list_organizations
|
|
122
|
-
|
|
123
|
-
expect(organizations.data.size).to eq(7)
|
|
124
|
-
expect(organizations.list_metadata).to eq(expected_metadata)
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
context 'with the before option' do
|
|
130
|
-
it 'forms the proper request to the API' do
|
|
131
|
-
request_args = [
|
|
132
|
-
'/organizations?before=before-id',
|
|
133
|
-
'Content-Type' => 'application/json'
|
|
134
|
-
]
|
|
135
|
-
|
|
136
|
-
expected_request = Net::HTTP::Get.new(*request_args)
|
|
137
|
-
|
|
138
|
-
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
139
|
-
and_return(expected_request)
|
|
140
|
-
|
|
141
|
-
VCR.use_cassette 'organization/list', match_requests_on: [:path] do
|
|
142
|
-
organizations = described_class.list_organizations(
|
|
143
|
-
before: 'before-id',
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
expect(organizations.data.size).to eq(7)
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
context 'with the after option' do
|
|
152
|
-
it 'forms the proper request to the API' do
|
|
153
|
-
request_args = [
|
|
154
|
-
'/organizations?after=after-id',
|
|
155
|
-
'Content-Type' => 'application/json'
|
|
156
|
-
]
|
|
157
|
-
|
|
158
|
-
expected_request = Net::HTTP::Get.new(*request_args)
|
|
159
|
-
|
|
160
|
-
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
161
|
-
and_return(expected_request)
|
|
162
|
-
|
|
163
|
-
VCR.use_cassette 'organization/list', match_requests_on: [:path] do
|
|
164
|
-
organizations = described_class.list_organizations(after: 'after-id')
|
|
165
|
-
|
|
166
|
-
expect(organizations.data.size).to eq(7)
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
context 'with the limit option' do
|
|
172
|
-
it 'forms the proper request to the API' do
|
|
173
|
-
request_args = [
|
|
174
|
-
'/organizations?limit=10',
|
|
175
|
-
'Content-Type' => 'application/json'
|
|
176
|
-
]
|
|
177
|
-
|
|
178
|
-
expected_request = Net::HTTP::Get.new(*request_args)
|
|
179
|
-
|
|
180
|
-
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
181
|
-
and_return(expected_request)
|
|
182
|
-
|
|
183
|
-
VCR.use_cassette 'organization/list', match_requests_on: [:path] do
|
|
184
|
-
organizations = described_class.list_organizations(limit: 10)
|
|
185
|
-
|
|
186
|
-
expect(organizations.data.size).to eq(7)
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
70
|
end
|
data/spec/lib/workos/sso_spec.rb
CHANGED
|
@@ -73,9 +73,10 @@ describe WorkOS::SSO do
|
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
context 'with
|
|
76
|
+
context 'with a connection' do
|
|
77
77
|
let(:args) do
|
|
78
78
|
{
|
|
79
|
+
connection: 'connection_123',
|
|
79
80
|
client_id: 'workos-proj-123',
|
|
80
81
|
redirect_uri: 'foo.com/auth/callback',
|
|
81
82
|
state: {
|
|
@@ -83,20 +84,32 @@ describe WorkOS::SSO do
|
|
|
83
84
|
}.to_s,
|
|
84
85
|
}
|
|
85
86
|
end
|
|
86
|
-
it '
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
it 'returns a valid URL' do
|
|
88
|
+
authorization_url = described_class.authorization_url(**args)
|
|
89
|
+
|
|
90
|
+
expect(URI.parse(authorization_url)).to be_a URI
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'returns the expected hostname' do
|
|
94
|
+
authorization_url = described_class.authorization_url(**args)
|
|
95
|
+
|
|
96
|
+
expect(URI.parse(authorization_url).host).to eq(WorkOS::API_HOSTNAME)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'returns the expected query string' do
|
|
100
|
+
authorization_url = described_class.authorization_url(**args)
|
|
101
|
+
|
|
102
|
+
expect(URI.parse(authorization_url).query).to eq(
|
|
103
|
+
'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
|
|
104
|
+
'&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
|
|
105
|
+
'edit%22%7D&connection=connection_123',
|
|
92
106
|
)
|
|
93
107
|
end
|
|
94
108
|
end
|
|
95
109
|
|
|
96
|
-
context 'with
|
|
110
|
+
context 'with neither connection, domain, or provider' do
|
|
97
111
|
let(:args) do
|
|
98
112
|
{
|
|
99
|
-
provider: 'Okta',
|
|
100
113
|
client_id: 'workos-proj-123',
|
|
101
114
|
redirect_uri: 'foo.com/auth/callback',
|
|
102
115
|
state: {
|
|
@@ -109,60 +122,34 @@ describe WorkOS::SSO do
|
|
|
109
122
|
described_class.authorization_url(**args)
|
|
110
123
|
end.to raise_error(
|
|
111
124
|
ArgumentError,
|
|
112
|
-
'
|
|
125
|
+
'Either connection, domain, or provider is required.',
|
|
113
126
|
)
|
|
114
127
|
end
|
|
115
128
|
end
|
|
116
129
|
|
|
117
|
-
context '
|
|
130
|
+
context 'with an invalid provider' do
|
|
118
131
|
let(:args) do
|
|
119
132
|
{
|
|
120
|
-
|
|
121
|
-
|
|
133
|
+
provider: 'Okta',
|
|
134
|
+
client_id: 'workos-proj-123',
|
|
122
135
|
redirect_uri: 'foo.com/auth/callback',
|
|
123
136
|
state: {
|
|
124
137
|
next_page: '/dashboard/edit',
|
|
125
138
|
}.to_s,
|
|
126
139
|
}
|
|
127
140
|
end
|
|
128
|
-
it 'raises
|
|
141
|
+
it 'raises an error' do
|
|
129
142
|
expect do
|
|
130
143
|
described_class.authorization_url(**args)
|
|
131
|
-
end.to
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
).to_stderr
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
it 'returns a valid URL' do
|
|
138
|
-
authorization_url = described_class.authorization_url(**args)
|
|
139
|
-
|
|
140
|
-
expect(URI.parse(authorization_url)).to be_a URI
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
it 'returns the expected hostname' do
|
|
144
|
-
authorization_url = described_class.authorization_url(**args)
|
|
145
|
-
|
|
146
|
-
expect(URI.parse(authorization_url).host).to eq(WorkOS::API_HOSTNAME)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
it 'returns the expected query string' do
|
|
150
|
-
authorization_url = described_class.authorization_url(**args)
|
|
151
|
-
|
|
152
|
-
expect(URI.parse(authorization_url).query).to eq(
|
|
153
|
-
'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
|
|
154
|
-
'&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
|
|
155
|
-
'edit%22%7D&domain=foo.com',
|
|
144
|
+
end.to raise_error(
|
|
145
|
+
ArgumentError,
|
|
146
|
+
'Okta is not a valid value. `provider` must be in ["GoogleOAuth"]',
|
|
156
147
|
)
|
|
157
148
|
end
|
|
158
149
|
end
|
|
159
150
|
end
|
|
160
151
|
|
|
161
|
-
describe '.
|
|
162
|
-
before do
|
|
163
|
-
WorkOS.key = 'api-key'
|
|
164
|
-
end
|
|
165
|
-
|
|
152
|
+
describe '.profile_and_token' do
|
|
166
153
|
let(:args) do
|
|
167
154
|
{
|
|
168
155
|
code: SecureRandom.hex(10),
|
|
@@ -195,15 +182,15 @@ describe WorkOS::SSO do
|
|
|
195
182
|
end
|
|
196
183
|
|
|
197
184
|
it 'includes the SDK Version header' do
|
|
198
|
-
described_class.
|
|
185
|
+
described_class.profile_and_token(**args)
|
|
199
186
|
|
|
200
187
|
expect(a_request(:post, 'https://api.workos.com/sso/token').
|
|
201
188
|
with(headers: headers, body: request_body)).to have_been_made
|
|
202
189
|
end
|
|
203
190
|
|
|
204
|
-
it 'returns a WorkOS::
|
|
205
|
-
|
|
206
|
-
expect(
|
|
191
|
+
it 'returns a WorkOS::ProfileAndToken' do
|
|
192
|
+
profile_and_token = described_class.profile_and_token(**args)
|
|
193
|
+
expect(profile_and_token).to be_a(WorkOS::ProfileAndToken)
|
|
207
194
|
|
|
208
195
|
expectation = {
|
|
209
196
|
connection_id: 'conn_01EMH8WAK20T42N2NBMNBCYHAG',
|
|
@@ -222,7 +209,8 @@ describe WorkOS::SSO do
|
|
|
222
209
|
},
|
|
223
210
|
}
|
|
224
211
|
|
|
225
|
-
expect(
|
|
212
|
+
expect(profile_and_token.access_token).to eq('01DVX6QBS3EG6FHY2ESAA5Q65X')
|
|
213
|
+
expect(profile_and_token.profile.to_json).to eq(expectation)
|
|
226
214
|
end
|
|
227
215
|
end
|
|
228
216
|
|
|
@@ -239,7 +227,7 @@ describe WorkOS::SSO do
|
|
|
239
227
|
|
|
240
228
|
it 'raises an exception with request ID' do
|
|
241
229
|
expect do
|
|
242
|
-
described_class.
|
|
230
|
+
described_class.profile_and_token(**args)
|
|
243
231
|
end.to raise_error(
|
|
244
232
|
WorkOS::APIError,
|
|
245
233
|
'some error message - request ID: request-id',
|
|
@@ -263,7 +251,7 @@ describe WorkOS::SSO do
|
|
|
263
251
|
|
|
264
252
|
it 'raises an exception' do
|
|
265
253
|
expect do
|
|
266
|
-
described_class.
|
|
254
|
+
described_class.profile_and_token(**args)
|
|
267
255
|
end.to raise_error(
|
|
268
256
|
WorkOS::APIError,
|
|
269
257
|
"The code '01DVX3C5Z367SFHR8QNDMK7V24'" \
|
|
@@ -273,138 +261,87 @@ describe WorkOS::SSO do
|
|
|
273
261
|
end
|
|
274
262
|
end
|
|
275
263
|
|
|
276
|
-
describe '.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
end
|
|
264
|
+
describe '.list_connections' do
|
|
265
|
+
context 'with no options' do
|
|
266
|
+
it 'returns connections and metadata' do
|
|
267
|
+
expected_metadata = {
|
|
268
|
+
'after' => nil,
|
|
269
|
+
'before' => 'before_id',
|
|
270
|
+
}
|
|
284
271
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
VCR.use_cassette('sso/create_connection_with_valid_source') do
|
|
288
|
-
connection = WorkOS::SSO.create_connection(
|
|
289
|
-
source: 'draft_conn_01E6PK87QP6NQ29RRX0G100YGV',
|
|
290
|
-
)
|
|
272
|
+
VCR.use_cassette 'sso/list_connections/with_no_options' do
|
|
273
|
+
connections = described_class.list_connections
|
|
291
274
|
|
|
292
|
-
expect(
|
|
293
|
-
expect(
|
|
294
|
-
expect(connection.name).to eq('Foo Corp')
|
|
295
|
-
expect(connection.domains.first[:domain]).to eq('example.com')
|
|
275
|
+
expect(connections.data.size).to eq(3)
|
|
276
|
+
expect(connections.list_metadata).to eq(expected_metadata)
|
|
296
277
|
end
|
|
297
278
|
end
|
|
298
279
|
end
|
|
299
280
|
|
|
300
|
-
context 'with
|
|
301
|
-
it '
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
WorkOS::APIError,
|
|
307
|
-
'Status 404, Not Found - request ID: ',
|
|
308
|
-
)
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
describe '.promote_draft_connection' do
|
|
315
|
-
before(:all) do
|
|
316
|
-
WorkOS.key = 'key'
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
after(:all) do
|
|
320
|
-
WorkOS.key = nil
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
let(:token) { 'draft_conn_id' }
|
|
324
|
-
let(:client_id) { 'proj_0239u590h' }
|
|
325
|
-
|
|
326
|
-
context 'with a valid request' do
|
|
327
|
-
before do
|
|
328
|
-
stub_request(
|
|
329
|
-
:post,
|
|
330
|
-
"https://api.workos.com/draft_connections/#{token}/activate",
|
|
331
|
-
).to_return(status: 200)
|
|
332
|
-
end
|
|
333
|
-
it 'returns true' do
|
|
334
|
-
response = described_class.promote_draft_connection(
|
|
335
|
-
token: token,
|
|
336
|
-
)
|
|
337
|
-
|
|
338
|
-
expect(response).to be(true)
|
|
339
|
-
end
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
context 'with an invalid request' do
|
|
343
|
-
before do
|
|
344
|
-
stub_request(
|
|
345
|
-
:post,
|
|
346
|
-
"https://api.workos.com/draft_connections/#{token}/activate",
|
|
347
|
-
).to_return(status: 403)
|
|
348
|
-
end
|
|
349
|
-
it 'returns true' do
|
|
350
|
-
response = described_class.promote_draft_connection(
|
|
351
|
-
token: token,
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
expect(response).to be(false)
|
|
355
|
-
end
|
|
356
|
-
end
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
describe '.list_connections' do
|
|
360
|
-
before(:all) do
|
|
361
|
-
WorkOS.key = 'key'
|
|
362
|
-
end
|
|
281
|
+
context 'with connection_type option' do
|
|
282
|
+
it 'forms the proper request to the API' do
|
|
283
|
+
request_args = [
|
|
284
|
+
'/connections?connection_type=OktaSAML',
|
|
285
|
+
'Content-Type' => 'application/json'
|
|
286
|
+
]
|
|
363
287
|
|
|
364
|
-
|
|
365
|
-
WorkOS.key = nil
|
|
366
|
-
end
|
|
288
|
+
expected_request = Net::HTTP::Get.new(*request_args)
|
|
367
289
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
VCR.use_cassette('sso/list_connections') do
|
|
371
|
-
connections = WorkOS::SSO.list_connections
|
|
372
|
-
expect(connections.size).to eq(1)
|
|
373
|
-
end
|
|
374
|
-
end
|
|
375
|
-
end
|
|
290
|
+
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
291
|
+
and_return(expected_request)
|
|
376
292
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
VCR.use_cassette('sso/list_connections_with_connection_type_param') do
|
|
380
|
-
connections = WorkOS::SSO.list_connections(
|
|
293
|
+
VCR.use_cassette 'sso/list_connections/with_connection_type' do
|
|
294
|
+
connections = described_class.list_connections(
|
|
381
295
|
connection_type: 'OktaSAML',
|
|
382
296
|
)
|
|
383
|
-
|
|
297
|
+
|
|
298
|
+
expect(connections.data.size).to eq(3)
|
|
299
|
+
expect(connections.data.first.connection_type).to eq('OktaSAML')
|
|
384
300
|
end
|
|
385
301
|
end
|
|
386
302
|
end
|
|
387
303
|
|
|
388
304
|
context 'with domain option' do
|
|
389
|
-
it '
|
|
390
|
-
|
|
391
|
-
connections
|
|
305
|
+
it 'forms the proper request to the API' do
|
|
306
|
+
request_args = [
|
|
307
|
+
'/connections?domain=foo-corp.com',
|
|
308
|
+
'Content-Type' => 'application/json'
|
|
309
|
+
]
|
|
310
|
+
|
|
311
|
+
expected_request = Net::HTTP::Get.new(*request_args)
|
|
312
|
+
|
|
313
|
+
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
314
|
+
and_return(expected_request)
|
|
315
|
+
|
|
316
|
+
VCR.use_cassette 'sso/list_connections/with_domain' do
|
|
317
|
+
connections = described_class.list_connections(
|
|
392
318
|
domain: 'foo-corp.com',
|
|
393
319
|
)
|
|
394
|
-
|
|
395
|
-
expect(
|
|
320
|
+
|
|
321
|
+
expect(connections.data.size).to eq(1)
|
|
396
322
|
end
|
|
397
323
|
end
|
|
398
324
|
end
|
|
399
325
|
|
|
400
326
|
context 'with organization_id option' do
|
|
401
|
-
it '
|
|
402
|
-
|
|
403
|
-
connections
|
|
327
|
+
it 'forms the proper request to the API' do
|
|
328
|
+
request_args = [
|
|
329
|
+
'/connections?organization_id=org_01EGS4P7QR31EZ4YWD1Z1XA176',
|
|
330
|
+
'Content-Type' => 'application/json'
|
|
331
|
+
]
|
|
332
|
+
|
|
333
|
+
expected_request = Net::HTTP::Get.new(*request_args)
|
|
334
|
+
|
|
335
|
+
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
336
|
+
and_return(expected_request)
|
|
337
|
+
|
|
338
|
+
VCR.use_cassette 'sso/list_connections/with_organization_id' do
|
|
339
|
+
connections = described_class.list_connections(
|
|
404
340
|
organization_id: 'org_01EGS4P7QR31EZ4YWD1Z1XA176',
|
|
405
341
|
)
|
|
406
|
-
|
|
407
|
-
expect(connections.
|
|
342
|
+
|
|
343
|
+
expect(connections.data.size).to eq(1)
|
|
344
|
+
expect(connections.data.first.organization_id).to eq(
|
|
408
345
|
'org_01EGS4P7QR31EZ4YWD1Z1XA176',
|
|
409
346
|
)
|
|
410
347
|
end
|
|
@@ -412,48 +349,73 @@ describe WorkOS::SSO do
|
|
|
412
349
|
end
|
|
413
350
|
|
|
414
351
|
context 'with limit option' do
|
|
415
|
-
it '
|
|
416
|
-
|
|
417
|
-
connections
|
|
418
|
-
|
|
352
|
+
it 'forms the proper request to the API' do
|
|
353
|
+
request_args = [
|
|
354
|
+
'/connections?limit=2',
|
|
355
|
+
'Content-Type' => 'application/json'
|
|
356
|
+
]
|
|
357
|
+
|
|
358
|
+
expected_request = Net::HTTP::Get.new(*request_args)
|
|
359
|
+
|
|
360
|
+
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
361
|
+
and_return(expected_request)
|
|
362
|
+
|
|
363
|
+
VCR.use_cassette 'sso/list_connections/with_limit' do
|
|
364
|
+
connections = described_class.list_connections(
|
|
365
|
+
limit: 2,
|
|
419
366
|
)
|
|
420
|
-
|
|
367
|
+
|
|
368
|
+
expect(connections.data.size).to eq(2)
|
|
421
369
|
end
|
|
422
370
|
end
|
|
423
371
|
end
|
|
424
372
|
|
|
425
373
|
context 'with before option' do
|
|
426
|
-
it '
|
|
427
|
-
|
|
428
|
-
connections
|
|
374
|
+
it 'forms the proper request to the API' do
|
|
375
|
+
request_args = [
|
|
376
|
+
'/connections?before=conn_01EQKPMQAPV02H270HKVNS4CTA',
|
|
377
|
+
'Content-Type' => 'application/json'
|
|
378
|
+
]
|
|
379
|
+
|
|
380
|
+
expected_request = Net::HTTP::Get.new(*request_args)
|
|
381
|
+
|
|
382
|
+
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
383
|
+
and_return(expected_request)
|
|
384
|
+
|
|
385
|
+
VCR.use_cassette 'sso/list_connections/with_before' do
|
|
386
|
+
connections = described_class.list_connections(
|
|
429
387
|
before: 'conn_01EQKPMQAPV02H270HKVNS4CTA',
|
|
430
388
|
)
|
|
431
|
-
|
|
389
|
+
|
|
390
|
+
expect(connections.data.size).to eq(3)
|
|
432
391
|
end
|
|
433
392
|
end
|
|
434
393
|
end
|
|
435
394
|
|
|
436
395
|
context 'with after option' do
|
|
437
|
-
it '
|
|
438
|
-
|
|
439
|
-
connections
|
|
396
|
+
it 'forms the proper request to the API' do
|
|
397
|
+
request_args = [
|
|
398
|
+
'/connections?after=conn_01EQKPMQAPV02H270HKVNS4CTA',
|
|
399
|
+
'Content-Type' => 'application/json'
|
|
400
|
+
]
|
|
401
|
+
|
|
402
|
+
expected_request = Net::HTTP::Get.new(*request_args)
|
|
403
|
+
|
|
404
|
+
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
|
405
|
+
and_return(expected_request)
|
|
406
|
+
|
|
407
|
+
VCR.use_cassette 'sso/list_connections/with_after' do
|
|
408
|
+
connections = described_class.list_connections(
|
|
440
409
|
after: 'conn_01EQKPMQAPV02H270HKVNS4CTA',
|
|
441
410
|
)
|
|
442
|
-
|
|
411
|
+
|
|
412
|
+
expect(connections.data.size).to eq(3)
|
|
443
413
|
end
|
|
444
414
|
end
|
|
445
415
|
end
|
|
446
416
|
end
|
|
447
417
|
|
|
448
418
|
describe '.get_connection' do
|
|
449
|
-
before(:all) do
|
|
450
|
-
WorkOS.key = 'key'
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
after(:all) do
|
|
454
|
-
WorkOS.key = nil
|
|
455
|
-
end
|
|
456
|
-
|
|
457
419
|
context 'with a valid id' do
|
|
458
420
|
it 'gets the connection details' do
|
|
459
421
|
VCR.use_cassette('sso/get_connection_with_valid_id') do
|
|
@@ -484,14 +446,6 @@ describe WorkOS::SSO do
|
|
|
484
446
|
end
|
|
485
447
|
|
|
486
448
|
describe '.delete_connection' do
|
|
487
|
-
before(:all) do
|
|
488
|
-
WorkOS.key = 'key'
|
|
489
|
-
end
|
|
490
|
-
|
|
491
|
-
after(:all) do
|
|
492
|
-
WorkOS.key = nil
|
|
493
|
-
end
|
|
494
|
-
|
|
495
449
|
context 'with a valid id' do
|
|
496
450
|
it 'returns true' do
|
|
497
451
|
VCR.use_cassette('sso/delete_connection_with_valid_id') do
|