sefrone-api-e2e 1.2.7__tar.gz → 1.2.8__tar.gz

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 (33) hide show
  1. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/PKG-INFO +1 -1
  2. sefrone_api_e2e-1.2.8/sefrone_api_e2e/e2e/Scenarios/Oidc/1_relying_party_admin.yaml +84 -0
  3. sefrone_api_e2e-1.2.8/sefrone_api_e2e/e2e/Scenarios/Oidc/2_authorization_code_flow.yaml +257 -0
  4. sefrone_api_e2e-1.2.8/sefrone_api_e2e/e2e/Scenarios/Oidc/3_disable_propagation_flow.yaml +208 -0
  5. sefrone_api_e2e-1.2.8/sefrone_api_e2e/e2e/Scenarios/Oidc/4_multi_project_isolation.yaml +156 -0
  6. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e_scenarios_manager.py +10 -0
  7. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e.egg-info/PKG-INFO +1 -1
  8. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e.egg-info/SOURCES.txt +5 -1
  9. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/setup.py +2 -2
  10. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/README.md +0 -0
  11. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/__init__.py +0 -0
  12. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/api_e2e_manager.py +0 -0
  13. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e/Scenarios/Auth/0_check_features.yaml +0 -0
  14. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e/Scenarios/Auth/1_normal_auth_flow.yaml +0 -0
  15. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e/Scenarios/Auth/2_account_endpoints.yaml +0 -0
  16. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e/Scenarios/Auth/3_admin_account_endpoints.yaml +0 -0
  17. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e/Scenarios/Auth/4_workspace_endpoints.yaml +0 -0
  18. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e/Scenarios/Auth/5_apikey_endpoints.yaml +0 -0
  19. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e/Scenarios/Auth/6_project_endpoints.yaml +0 -0
  20. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e/Scenarios/Auth/7_email_2fa_flow.yaml +0 -0
  21. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/e2e/Scenarios/Auth/8_temporary_passwords_flow.yaml +0 -0
  22. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/env_patch.py +0 -0
  23. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/json_mock_server.py +0 -0
  24. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/runner_assets.py +0 -0
  25. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/runner_email_mock.py +0 -0
  26. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/runner_rest_api.py +0 -0
  27. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/runner_satim_mock.py +0 -0
  28. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/runner_webhook_mock.py +0 -0
  29. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e/step_runner.py +0 -0
  30. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e.egg-info/dependency_links.txt +0 -0
  31. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e.egg-info/requires.txt +0 -0
  32. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/sefrone_api_e2e.egg-info/top_level.txt +0 -0
  33. {sefrone_api_e2e-1.2.7 → sefrone_api_e2e-1.2.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sefrone_api_e2e
3
- Version: 1.2.7
3
+ Version: 1.2.8
4
4
  Summary: A Python package to provide e2e testing helpers for sefrone API projects
5
5
  Home-page: https://bitbucket.org/sefrone/sefrone_pypi
6
6
  Author: Sefrone
@@ -0,0 +1,84 @@
1
+ name: "Oidc - Relying Party Admin CRUD"
2
+ base_url: "http://localhost:$var(API_PUBLIC_PORT)"
3
+ skip_if:
4
+ - "OidcIdentityProvider not in {$stored.0_check_features.enabled_features}"
5
+
6
+ steps:
7
+ - name: "Login admin"
8
+ retry:
9
+ attempts: 10
10
+ delay_seconds: 5
11
+ method: "POST"
12
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/login"
13
+ send_as: "json"
14
+ body:
15
+ device: "e2e_oidc_admin_device"
16
+ pseudo: "$var(DEFAULT_USERNAME)"
17
+ password: "$var(DEFAULT_PASSWORD)"
18
+ expect:
19
+ status: 200
20
+ body:
21
+ response:
22
+ token: string
23
+ save:
24
+ admin_token: "{{body.response.token}}"
25
+
26
+ - name: "Generate unique client id"
27
+ randomize:
28
+ client_suffix: 8
29
+
30
+ - name: "Register a relying party"
31
+ method: "POST"
32
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties"
33
+ request_headers:
34
+ - x-api-token: "{$stored.admin_token}"
35
+ send_as: "json"
36
+ body:
37
+ clientId: "e2e-rp-{$stored.client_suffix}"
38
+ clientSecret: "e2e-secret-{$stored.client_suffix}"
39
+ displayName: "E2E Relying Party {$stored.client_suffix}"
40
+ redirectUris:
41
+ - "http://localhost:9999/callback"
42
+ postLogoutRedirectUris: []
43
+ requiresConsent: false
44
+ expect:
45
+ status: 200
46
+ body:
47
+ response:
48
+ id: string
49
+ clientId: string
50
+ save:
51
+ relying_party_db_id: "{{body.response.id}}"
52
+ assertions:
53
+ - "{{body.response.clientId}} == 'e2e-rp-{$stored.client_suffix}'"
54
+ - "{{body.response.requiresConsent}} == False"
55
+
56
+ - name: "List relying parties — the new one is present"
57
+ method: "GET"
58
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties"
59
+ request_headers:
60
+ - x-api-token: "{$stored.admin_token}"
61
+ expect:
62
+ status: 200
63
+ body:
64
+ response: []
65
+ assertions:
66
+ - "{{body.response.count()}} >= 1"
67
+
68
+ - name: "Delete the relying party (cleanup)"
69
+ method: "DELETE"
70
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties/e2e-rp-{$stored.client_suffix}"
71
+ request_headers:
72
+ - x-api-token: "{$stored.admin_token}"
73
+ expect:
74
+ status: 200
75
+ body:
76
+ errorCode: number
77
+
78
+ - name: "Deleting again returns not found"
79
+ method: "DELETE"
80
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties/e2e-rp-{$stored.client_suffix}"
81
+ request_headers:
82
+ - x-api-token: "{$stored.admin_token}"
83
+ expect:
84
+ status: 404
@@ -0,0 +1,257 @@
1
+ name: "Oidc - Discovery, JWKS and Full Authorization Code Flow"
2
+ base_url: "http://localhost:$var(API_PUBLIC_PORT)"
3
+ skip_if:
4
+ - "OidcIdentityProvider not in {$stored.0_check_features.enabled_features}"
5
+
6
+ steps:
7
+ - name: "Login admin"
8
+ retry:
9
+ attempts: 10
10
+ delay_seconds: 5
11
+ method: "POST"
12
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/login"
13
+ send_as: "json"
14
+ body:
15
+ device: "e2e_oidc_authorize_device"
16
+ pseudo: "$var(DEFAULT_USERNAME)"
17
+ password: "$var(DEFAULT_PASSWORD)"
18
+ expect:
19
+ status: 200
20
+ body:
21
+ response:
22
+ token: string
23
+ save:
24
+ admin_token: "{{body.response.token}}"
25
+
26
+ - name: "Generate unique ids and PKCE verifier"
27
+ randomize:
28
+ client_suffix: 8
29
+ account_suffix: 8
30
+ pkce_verifier:
31
+ type: string
32
+ length: 64
33
+
34
+ - name: "Register a relying party for this flow (pre-trusted, no consent)"
35
+ method: "POST"
36
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties"
37
+ request_headers:
38
+ - x-api-token: "{$stored.admin_token}"
39
+ send_as: "json"
40
+ body:
41
+ clientId: "e2e-authz-{$stored.client_suffix}"
42
+ clientSecret: "e2e-secret-{$stored.client_suffix}"
43
+ displayName: "E2E Authorize Flow Client"
44
+ redirectUris:
45
+ - "http://localhost:9999/callback"
46
+ postLogoutRedirectUris: []
47
+ requiresConsent: false
48
+ expect:
49
+ status: 200
50
+ body:
51
+ response:
52
+ clientId: string
53
+
54
+ - name: "Create a standard test account for this flow"
55
+ method: "POST"
56
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/create?accountType=standard"
57
+ request_headers:
58
+ - x-api-token: "{$stored.admin_token}"
59
+ send_as: "json"
60
+ body:
61
+ username: "e2e_oidc_user_{$stored.account_suffix}"
62
+ password: "E2eTestPass{$stored.account_suffix}"
63
+ expect:
64
+ status: 200
65
+ body:
66
+ response:
67
+ accountId: string
68
+ isActive: boolean
69
+ save:
70
+ test_account_id: "{{body.response.accountId}}"
71
+ assertions:
72
+ - "{{body.response.isActive}} == True"
73
+
74
+ - name: "Discovery document exposes the expected endpoints"
75
+ method: "GET"
76
+ endpoint: "/.well-known/openid-configuration"
77
+ expect:
78
+ status: 200
79
+ body:
80
+ issuer: string
81
+ authorization_endpoint: string
82
+ token_endpoint: string
83
+ userinfo_endpoint: string
84
+ jwks_uri: string
85
+ grant_types_supported: []
86
+ scopes_supported: []
87
+ assertions:
88
+ - "{{body.authorization_endpoint}} include /account/oidc/authorize"
89
+ - "{{body.token_endpoint}} include /account/oidc/token"
90
+ - "{{body.userinfo_endpoint}} include /account/oidc/userinfo"
91
+ - "{{body.grant_types_supported}} include authorization_code"
92
+ - "{{body.grant_types_supported}} include refresh_token"
93
+ - "{{body.scopes_supported}} include openid"
94
+
95
+ - name: "JWKS exposes at least one RSA signing key"
96
+ method: "GET"
97
+ endpoint: "/.well-known/jwks"
98
+ expect:
99
+ status: 200
100
+ body:
101
+ keys: []
102
+ assertions:
103
+ - "{{body.keys.count()}} >= 1"
104
+ - "{{body.keys[0].kty}} == 'RSA'"
105
+
106
+ - name: "GET authorize without credentials renders the login page"
107
+ method: "GET"
108
+ endpoint: "/account/oidc/authorize"
109
+ request_query_params:
110
+ client_id: "e2e-authz-{$stored.client_suffix}"
111
+ redirect_uri: "http://localhost:9999/callback"
112
+ response_type: "code"
113
+ scope: "openid profile email"
114
+ state: "e2e-state-{$stored.client_suffix}"
115
+ code_challenge: "{$stored.pkce_verifier}"
116
+ code_challenge_method: "plain"
117
+ expect:
118
+ status: 200
119
+ content_type: "text/html"
120
+
121
+ - name: "POST authorize with wrong password re-renders the login page (not a crash)"
122
+ method: "POST"
123
+ endpoint: "/account/oidc/authorize"
124
+ send_as: "form"
125
+ body:
126
+ client_id: "e2e-authz-{$stored.client_suffix}"
127
+ redirect_uri: "http://localhost:9999/callback"
128
+ response_type: "code"
129
+ scope: "openid profile email"
130
+ state: "e2e-state-{$stored.client_suffix}"
131
+ code_challenge: "{$stored.pkce_verifier}"
132
+ code_challenge_method: "plain"
133
+ sefrone_username: "e2e_oidc_user_{$stored.account_suffix}"
134
+ sefrone_password: "definitely-the-wrong-password"
135
+ expect:
136
+ status: 200
137
+ content_type: "text/html"
138
+
139
+ - name: "POST authorize with valid credentials redirects with an authorization code"
140
+ method: "POST"
141
+ endpoint: "/account/oidc/authorize"
142
+ send_as: "form"
143
+ allow_redirects: false
144
+ body:
145
+ client_id: "e2e-authz-{$stored.client_suffix}"
146
+ redirect_uri: "http://localhost:9999/callback"
147
+ response_type: "code"
148
+ scope: "openid profile email"
149
+ state: "e2e-state-{$stored.client_suffix}"
150
+ code_challenge: "{$stored.pkce_verifier}"
151
+ code_challenge_method: "plain"
152
+ sefrone_username: "e2e_oidc_user_{$stored.account_suffix}"
153
+ sefrone_password: "E2eTestPass{$stored.account_suffix}"
154
+ expect:
155
+ status: 302
156
+ headers:
157
+ Location: "include:http://localhost:9999/callback?code="
158
+ save:
159
+ auth_code:
160
+ from: "{{headers.Location}}"
161
+ regex: "code=([^&]+)"
162
+
163
+ - name: "Exchange the authorization code for tokens"
164
+ method: "POST"
165
+ endpoint: "/account/oidc/token"
166
+ send_as: "form"
167
+ body:
168
+ grant_type: "authorization_code"
169
+ code: "{$stored.auth_code}"
170
+ redirect_uri: "http://localhost:9999/callback"
171
+ client_id: "e2e-authz-{$stored.client_suffix}"
172
+ client_secret: "e2e-secret-{$stored.client_suffix}"
173
+ code_verifier: "{$stored.pkce_verifier}"
174
+ expect:
175
+ status: 200
176
+ body:
177
+ access_token: string
178
+ token_type: string
179
+ id_token: string
180
+ save:
181
+ access_token: "{{body.access_token}}"
182
+ assertions:
183
+ - "{{body.token_type}} == 'Bearer'"
184
+
185
+ - name: "Userinfo returns the authenticated account's claims"
186
+ method: "GET"
187
+ endpoint: "/account/oidc/userinfo"
188
+ request_headers:
189
+ - Authorization: "Bearer {$stored.access_token}"
190
+ expect:
191
+ status: 200
192
+ body:
193
+ sub: string
194
+ preferred_username: string
195
+ assertions:
196
+ - "{{body.sub}} == '{$stored.test_account_id}'"
197
+ - "{{body.preferred_username}} == 'e2e_oidc_user_{$stored.account_suffix}'"
198
+
199
+ - name: "Replaying the same authorization code is rejected"
200
+ method: "POST"
201
+ endpoint: "/account/oidc/token"
202
+ send_as: "form"
203
+ body:
204
+ grant_type: "authorization_code"
205
+ code: "{$stored.auth_code}"
206
+ redirect_uri: "http://localhost:9999/callback"
207
+ client_id: "e2e-authz-{$stored.client_suffix}"
208
+ client_secret: "e2e-secret-{$stored.client_suffix}"
209
+ code_verifier: "{$stored.pkce_verifier}"
210
+ expect:
211
+ status: 400
212
+ body:
213
+ error: string
214
+ assertions:
215
+ - "{{body.error}} == 'invalid_grant'"
216
+
217
+ - name: "Token endpoint rejects a bogus authorization code"
218
+ method: "POST"
219
+ endpoint: "/account/oidc/token"
220
+ send_as: "form"
221
+ body:
222
+ grant_type: "authorization_code"
223
+ code: "this-code-does-not-exist"
224
+ redirect_uri: "http://localhost:9999/callback"
225
+ client_id: "e2e-authz-{$stored.client_suffix}"
226
+ client_secret: "e2e-secret-{$stored.client_suffix}"
227
+ code_verifier: "{$stored.pkce_verifier}"
228
+ expect:
229
+ status: 400
230
+ body:
231
+ error: string
232
+ assertions:
233
+ - "{{body.error}} == 'invalid_grant'"
234
+
235
+ - name: "Userinfo rejects a garbage bearer token"
236
+ method: "GET"
237
+ endpoint: "/account/oidc/userinfo"
238
+ request_headers:
239
+ - Authorization: "Bearer this-is-not-a-real-token"
240
+ expect:
241
+ status: 401
242
+
243
+ - name: "Cleanup: delete relying party"
244
+ method: "DELETE"
245
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties/e2e-authz-{$stored.client_suffix}"
246
+ request_headers:
247
+ - x-api-token: "{$stored.admin_token}"
248
+ expect:
249
+ status: 200
250
+
251
+ - name: "Cleanup: delete test account"
252
+ method: "DELETE"
253
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/delete/{$stored.test_account_id}"
254
+ request_headers:
255
+ - x-api-token: "{$stored.admin_token}"
256
+ expect:
257
+ status: 200
@@ -0,0 +1,208 @@
1
+ name: "Oidc - Account Disable Propagation"
2
+ base_url: "http://localhost:$var(API_PUBLIC_PORT)"
3
+ skip_if:
4
+ - "OidcIdentityProvider not in {$stored.0_check_features.enabled_features}"
5
+
6
+ # This is the core safety requirement of the OIDC identity provider: deactivating an
7
+ # account here must cut off that user's access to every downstream relying party.
8
+ # - userinfo re-checks IsActive on every call -> cut off immediately.
9
+ # - a refresh grant is NOT automatically rejected just because IsActive flipped
10
+ # (best-effort v1 design) -- it keeps working until the admin explicitly calls
11
+ # the revoke-access endpoint, after which OpenIddict's own token-status check
12
+ # rejects it natively.
13
+
14
+ steps:
15
+ - name: "Login admin"
16
+ retry:
17
+ attempts: 10
18
+ delay_seconds: 5
19
+ method: "POST"
20
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/login"
21
+ send_as: "json"
22
+ body:
23
+ device: "e2e_oidc_disable_device"
24
+ pseudo: "$var(DEFAULT_USERNAME)"
25
+ password: "$var(DEFAULT_PASSWORD)"
26
+ expect:
27
+ status: 200
28
+ body:
29
+ response:
30
+ token: string
31
+ save:
32
+ admin_token: "{{body.response.token}}"
33
+
34
+ - name: "Generate unique ids and PKCE verifier"
35
+ randomize:
36
+ client_suffix: 8
37
+ account_suffix: 8
38
+ pkce_verifier:
39
+ type: string
40
+ length: 64
41
+
42
+ - name: "Register a relying party for this flow"
43
+ method: "POST"
44
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties"
45
+ request_headers:
46
+ - x-api-token: "{$stored.admin_token}"
47
+ send_as: "json"
48
+ body:
49
+ clientId: "e2e-disable-{$stored.client_suffix}"
50
+ clientSecret: "e2e-secret-{$stored.client_suffix}"
51
+ displayName: "E2E Disable Propagation Client"
52
+ redirectUris:
53
+ - "http://localhost:9999/callback"
54
+ postLogoutRedirectUris: []
55
+ requiresConsent: false
56
+ expect:
57
+ status: 200
58
+
59
+ - name: "Create a standard test account"
60
+ method: "POST"
61
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/create?accountType=standard"
62
+ request_headers:
63
+ - x-api-token: "{$stored.admin_token}"
64
+ send_as: "json"
65
+ body:
66
+ username: "e2e_oidc_disable_{$stored.account_suffix}"
67
+ password: "E2eTestPass{$stored.account_suffix}"
68
+ expect:
69
+ status: 200
70
+ body:
71
+ response:
72
+ accountId: string
73
+ save:
74
+ test_account_id: "{{body.response.accountId}}"
75
+
76
+ - name: "Sign in, requesting offline_access for a refresh token"
77
+ method: "POST"
78
+ endpoint: "/account/oidc/authorize"
79
+ send_as: "form"
80
+ allow_redirects: false
81
+ body:
82
+ client_id: "e2e-disable-{$stored.client_suffix}"
83
+ redirect_uri: "http://localhost:9999/callback"
84
+ response_type: "code"
85
+ scope: "openid profile email offline_access"
86
+ state: "e2e-state-{$stored.client_suffix}"
87
+ code_challenge: "{$stored.pkce_verifier}"
88
+ code_challenge_method: "plain"
89
+ sefrone_username: "e2e_oidc_disable_{$stored.account_suffix}"
90
+ sefrone_password: "E2eTestPass{$stored.account_suffix}"
91
+ expect:
92
+ status: 302
93
+ headers:
94
+ Location: "include:http://localhost:9999/callback?code="
95
+ save:
96
+ auth_code:
97
+ from: "{{headers.Location}}"
98
+ regex: "code=([^&]+)"
99
+
100
+ - name: "Exchange the code for an access token and a refresh token"
101
+ method: "POST"
102
+ endpoint: "/account/oidc/token"
103
+ send_as: "form"
104
+ body:
105
+ grant_type: "authorization_code"
106
+ code: "{$stored.auth_code}"
107
+ redirect_uri: "http://localhost:9999/callback"
108
+ client_id: "e2e-disable-{$stored.client_suffix}"
109
+ client_secret: "e2e-secret-{$stored.client_suffix}"
110
+ code_verifier: "{$stored.pkce_verifier}"
111
+ expect:
112
+ status: 200
113
+ body:
114
+ access_token: string
115
+ refresh_token: string
116
+ save:
117
+ access_token: "{{body.access_token}}"
118
+ refresh_token: "{{body.refresh_token}}"
119
+
120
+ - name: "Sanity check: userinfo works before deactivation"
121
+ method: "GET"
122
+ endpoint: "/account/oidc/userinfo"
123
+ request_headers:
124
+ - Authorization: "Bearer {$stored.access_token}"
125
+ expect:
126
+ status: 200
127
+ body:
128
+ sub: string
129
+ assertions:
130
+ - "{{body.sub}} == '{$stored.test_account_id}'"
131
+
132
+ - name: "Deactivate the account"
133
+ method: "POST"
134
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/activationState/{$stored.test_account_id}?isActive=false"
135
+ request_headers:
136
+ - x-api-token: "{$stored.admin_token}"
137
+ expect:
138
+ status: 200
139
+ body:
140
+ errorCode: number
141
+ assertions:
142
+ - "{{body.errorCode}} == 0"
143
+
144
+ - name: "Userinfo is cut off immediately after deactivation"
145
+ method: "GET"
146
+ endpoint: "/account/oidc/userinfo"
147
+ request_headers:
148
+ - Authorization: "Bearer {$stored.access_token}"
149
+ expect:
150
+ status: 401
151
+
152
+ - name: "Refresh grant still succeeds before the explicit revoke-access call (documented best-effort gap)"
153
+ method: "POST"
154
+ endpoint: "/account/oidc/token"
155
+ send_as: "form"
156
+ body:
157
+ grant_type: "refresh_token"
158
+ refresh_token: "{$stored.refresh_token}"
159
+ client_id: "e2e-disable-{$stored.client_suffix}"
160
+ client_secret: "e2e-secret-{$stored.client_suffix}"
161
+ expect:
162
+ status: 200
163
+ body:
164
+ access_token: string
165
+
166
+ - name: "Admin explicitly revokes all OIDC access for the account"
167
+ method: "POST"
168
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/accounts/{$stored.test_account_id}/revoke-access"
169
+ request_headers:
170
+ - x-api-token: "{$stored.admin_token}"
171
+ expect:
172
+ status: 200
173
+ body:
174
+ errorCode: number
175
+ assertions:
176
+ - "{{body.errorCode}} == 0"
177
+
178
+ - name: "Refresh grant now fails after the explicit revoke"
179
+ method: "POST"
180
+ endpoint: "/account/oidc/token"
181
+ send_as: "form"
182
+ body:
183
+ grant_type: "refresh_token"
184
+ refresh_token: "{$stored.refresh_token}"
185
+ client_id: "e2e-disable-{$stored.client_suffix}"
186
+ client_secret: "e2e-secret-{$stored.client_suffix}"
187
+ expect:
188
+ status: 400
189
+ body:
190
+ error: string
191
+ assertions:
192
+ - "{{body.error}} == 'invalid_grant'"
193
+
194
+ - name: "Cleanup: delete relying party"
195
+ method: "DELETE"
196
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties/e2e-disable-{$stored.client_suffix}"
197
+ request_headers:
198
+ - x-api-token: "{$stored.admin_token}"
199
+ expect:
200
+ status: 200
201
+
202
+ - name: "Cleanup: delete test account"
203
+ method: "DELETE"
204
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/delete/{$stored.test_account_id}"
205
+ request_headers:
206
+ - x-api-token: "{$stored.admin_token}"
207
+ expect:
208
+ status: 200
@@ -0,0 +1,156 @@
1
+ name: "Oidc - Relying Parties Are Isolated Per Project"
2
+ base_url: "http://localhost:$var(API_PUBLIC_PORT)"
3
+ skip_if:
4
+ - "OidcIdentityProvider not in {$stored.0_check_features.enabled_features}"
5
+ - "Projects not in {$stored.0_check_features.enabled_features}"
6
+
7
+ # Relying parties are scoped per-project (stored on the OpenIddict application's own
8
+ # Properties dictionary, not a global registry) so that an admin in one project never
9
+ # sees or can delete another project's relying parties.
10
+
11
+ steps:
12
+ - name: "Login admin"
13
+ retry:
14
+ attempts: 10
15
+ delay_seconds: 5
16
+ method: "POST"
17
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/login"
18
+ send_as: "json"
19
+ body:
20
+ device: "e2e_oidc_multiproject_device"
21
+ pseudo: "$var(DEFAULT_USERNAME)"
22
+ password: "$var(DEFAULT_PASSWORD)"
23
+ expect:
24
+ status: 200
25
+ body:
26
+ response:
27
+ token: string
28
+ save:
29
+ admin_token: "{{body.response.token}}"
30
+
31
+ - name: "Generate unique ids"
32
+ randomize:
33
+ project_suffix: 8
34
+ client_a_suffix: 8
35
+ client_b_suffix: 8
36
+
37
+ - name: "Create a second project"
38
+ method: "POST"
39
+ endpoint: "/api/v1/apiAuth/project"
40
+ request_headers:
41
+ - x-api-token: "{$stored.admin_token}"
42
+ send_as: "json"
43
+ body:
44
+ name: "e2e_oidc_proj_{$stored.project_suffix}"
45
+ description: "E2E OIDC multi-project isolation test"
46
+ expect:
47
+ status: 200
48
+ body:
49
+ response:
50
+ id: string
51
+ name: string
52
+ save:
53
+ second_project_id: "{{body.response.id}}"
54
+ second_project_name: "{{body.response.name}}"
55
+
56
+ - name: "Register a relying party under the default project"
57
+ method: "POST"
58
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties"
59
+ request_headers:
60
+ - x-api-token: "{$stored.admin_token}"
61
+ send_as: "json"
62
+ body:
63
+ clientId: "e2e-isoA-{$stored.client_a_suffix}"
64
+ clientSecret: "e2e-secret-{$stored.client_a_suffix}"
65
+ displayName: "E2E Isolation Client A"
66
+ redirectUris:
67
+ - "http://localhost:9999/callback"
68
+ postLogoutRedirectUris: []
69
+ requiresConsent: false
70
+ expect:
71
+ status: 200
72
+ body:
73
+ response:
74
+ project: string
75
+ assertions:
76
+ - "{{body.response.project}} == '$var(AUTH_PROJECT_NAME)'"
77
+
78
+ - name: "Register a relying party under the second project"
79
+ method: "POST"
80
+ endpoint: "/api/v1/apiAuth/account/{$stored.second_project_name}/oidc/admin/relying-parties"
81
+ request_headers:
82
+ - x-api-token: "{$stored.admin_token}"
83
+ send_as: "json"
84
+ body:
85
+ clientId: "e2e-isoB-{$stored.client_b_suffix}"
86
+ clientSecret: "e2e-secret-{$stored.client_b_suffix}"
87
+ displayName: "E2E Isolation Client B"
88
+ redirectUris:
89
+ - "http://localhost:9999/callback"
90
+ postLogoutRedirectUris: []
91
+ requiresConsent: false
92
+ expect:
93
+ status: 200
94
+ body:
95
+ response:
96
+ project: string
97
+ assertions:
98
+ - "{{body.response.project}} == '{$stored.second_project_name}'"
99
+
100
+ - name: "Listing under the default project only shows client A"
101
+ method: "GET"
102
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties"
103
+ request_headers:
104
+ - x-api-token: "{$stored.admin_token}"
105
+ expect:
106
+ status: 200
107
+ body:
108
+ response: []
109
+ assertions:
110
+ - "{{body.response.count()}} == 1"
111
+ - "{{body.response[0].clientId}} == 'e2e-isoA-{$stored.client_a_suffix}'"
112
+
113
+ - name: "Listing under the second project only shows client B"
114
+ method: "GET"
115
+ endpoint: "/api/v1/apiAuth/account/{$stored.second_project_name}/oidc/admin/relying-parties"
116
+ request_headers:
117
+ - x-api-token: "{$stored.admin_token}"
118
+ expect:
119
+ status: 200
120
+ body:
121
+ response: []
122
+ assertions:
123
+ - "{{body.response.count()}} == 1"
124
+ - "{{body.response[0].clientId}} == 'e2e-isoB-{$stored.client_b_suffix}'"
125
+
126
+ - name: "Cannot delete client B through the default project's route"
127
+ method: "DELETE"
128
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties/e2e-isoB-{$stored.client_b_suffix}"
129
+ request_headers:
130
+ - x-api-token: "{$stored.admin_token}"
131
+ expect:
132
+ status: 404
133
+
134
+ - name: "Cleanup: delete client A"
135
+ method: "DELETE"
136
+ endpoint: "/api/v1/apiAuth/account/$var(AUTH_PROJECT_NAME)/oidc/admin/relying-parties/e2e-isoA-{$stored.client_a_suffix}"
137
+ request_headers:
138
+ - x-api-token: "{$stored.admin_token}"
139
+ expect:
140
+ status: 200
141
+
142
+ - name: "Cleanup: delete client B through its own project's route"
143
+ method: "DELETE"
144
+ endpoint: "/api/v1/apiAuth/account/{$stored.second_project_name}/oidc/admin/relying-parties/e2e-isoB-{$stored.client_b_suffix}"
145
+ request_headers:
146
+ - x-api-token: "{$stored.admin_token}"
147
+ expect:
148
+ status: 200
149
+
150
+ - name: "Cleanup: delete second project"
151
+ method: "DELETE"
152
+ endpoint: "/api/v1/apiAuth/project/{$stored.second_project_id}"
153
+ request_headers:
154
+ - x-api-token: "{$stored.admin_token}"
155
+ expect:
156
+ status: 200
@@ -8,6 +8,7 @@ class E2EScenariosManager:
8
8
 
9
9
  # Path to bundled e2e resources relative to this file
10
10
  _BUNDLED_AUTH_SCENARIOS_DIR = Path(__file__).parent / "e2e" / "Scenarios" / "Auth"
11
+ _BUNDLED_OIDC_SCENARIOS_DIR = Path(__file__).parent / "e2e" / "Scenarios" / "Oidc"
11
12
 
12
13
  @staticmethod
13
14
  def __export_scenarios(src, destination_dir, overwrite=False):
@@ -45,6 +46,15 @@ class E2EScenariosManager:
45
46
  destination_dir,
46
47
  overwrite
47
48
  )
49
+
50
+ @staticmethod
51
+ def export_oidc_scenarios(destination_dir, overwrite=False):
52
+ """Export bundled OIDC scenario YAML files to *destination_dir*."""
53
+ return E2EScenariosManager.__export_scenarios(
54
+ E2EScenariosManager._BUNDLED_OIDC_SCENARIOS_DIR,
55
+ destination_dir,
56
+ overwrite
57
+ )
48
58
 
49
59
  @staticmethod
50
60
  def list_bundled_scenarios():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sefrone_api_e2e
3
- Version: 1.2.7
3
+ Version: 1.2.8
4
4
  Summary: A Python package to provide e2e testing helpers for sefrone API projects
5
5
  Home-page: https://bitbucket.org/sefrone/sefrone_pypi
6
6
  Author: Sefrone
@@ -24,4 +24,8 @@ sefrone_api_e2e/e2e/Scenarios/Auth/4_workspace_endpoints.yaml
24
24
  sefrone_api_e2e/e2e/Scenarios/Auth/5_apikey_endpoints.yaml
25
25
  sefrone_api_e2e/e2e/Scenarios/Auth/6_project_endpoints.yaml
26
26
  sefrone_api_e2e/e2e/Scenarios/Auth/7_email_2fa_flow.yaml
27
- sefrone_api_e2e/e2e/Scenarios/Auth/8_temporary_passwords_flow.yaml
27
+ sefrone_api_e2e/e2e/Scenarios/Auth/8_temporary_passwords_flow.yaml
28
+ sefrone_api_e2e/e2e/Scenarios/Oidc/1_relying_party_admin.yaml
29
+ sefrone_api_e2e/e2e/Scenarios/Oidc/2_authorization_code_flow.yaml
30
+ sefrone_api_e2e/e2e/Scenarios/Oidc/3_disable_propagation_flow.yaml
31
+ sefrone_api_e2e/e2e/Scenarios/Oidc/4_multi_project_isolation.yaml
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="sefrone_api_e2e",
8
- version="1.2.7",
8
+ version="1.2.8",
9
9
  author="Sefrone",
10
10
  author_email="contact@sefrone.com",
11
11
  description="A Python package to provide e2e testing helpers for sefrone API projects",
@@ -24,7 +24,7 @@ setup(
24
24
  "requests"
25
25
  ],
26
26
  package_data={
27
- "sefrone_api_e2e": ["e2e/Scenarios/Auth/*.yaml"]
27
+ "sefrone_api_e2e": ["e2e/Scenarios/Auth/*.yaml", "e2e/Scenarios/Oidc/*.yaml"]
28
28
  },
29
29
  include_package_data=True,
30
30
  )