Skip to content
This repository was archived by the owner on Oct 9, 2023. It is now read-only.

Commit b32a3d3

Browse files
Expire flyte_idt cookie at logout (#610)
* Expire flyte_idt cookie at logout
1 parent 6f49854 commit b32a3d3

6 files changed

Lines changed: 89 additions & 81 deletions

File tree

auth/cookie_manager.go

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -175,20 +175,9 @@ func (c CookieManager) SetTokenCookies(ctx context.Context, writer http.Response
175175
return nil
176176
}
177177

178-
func (c *CookieManager) getLogoutAccessCookie() *http.Cookie {
178+
func (c *CookieManager) getLogoutCookie(name string) *http.Cookie {
179179
return &http.Cookie{
180-
Name: accessTokenCookieName,
181-
Value: "",
182-
Domain: c.domain,
183-
MaxAge: 0,
184-
HttpOnly: true,
185-
Expires: time.Now().Add(-1 * time.Hour),
186-
}
187-
}
188-
189-
func (c *CookieManager) getLogoutRefreshCookie() *http.Cookie {
190-
return &http.Cookie{
191-
Name: refreshTokenCookieName,
180+
Name: name,
192181
Value: "",
193182
Domain: c.domain,
194183
MaxAge: 0,
@@ -198,8 +187,9 @@ func (c *CookieManager) getLogoutRefreshCookie() *http.Cookie {
198187
}
199188

200189
func (c CookieManager) DeleteCookies(_ context.Context, writer http.ResponseWriter) {
201-
http.SetCookie(writer, c.getLogoutAccessCookie())
202-
http.SetCookie(writer, c.getLogoutRefreshCookie())
190+
http.SetCookie(writer, c.getLogoutCookie(accessTokenCookieName))
191+
http.SetCookie(writer, c.getLogoutCookie(refreshTokenCookieName))
192+
http.SetCookie(writer, c.getLogoutCookie(idTokenCookieName))
203193
}
204194

205195
func (c CookieManager) getHTTPSameSitePolicy() http.SameSite {

auth/cookie_manager_test.go

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@ import (
1010
"testing"
1111
"time"
1212

13+
"github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service"
14+
1315
"github.com/stretchr/testify/assert"
1416
"github.com/stretchr/testify/require"
1517
"golang.org/x/oauth2"
1618

1719
"github.com/flyteorg/flyteadmin/auth/config"
1820
)
1921

20-
func TestCookieManager_SetTokenCookies(t *testing.T) {
22+
func TestCookieManager(t *testing.T) {
2123
ctx := context.Background()
2224
// These were generated for unit testing only.
2325
hashKeyEncoded := "wG4pE1ccdw/pHZ2ml8wrD5VJkOtLPmBpWbKHmezWXktGaFbRoAhXidWs8OpbA3y7N8vyZhz1B1E37+tShWC7gA" //nolint:goconst
@@ -61,6 +63,14 @@ func TestCookieManager_SetTokenCookies(t *testing.T) {
6163
assert.Equal(t, "flyte_rt", c[2].Name)
6264
})
6365

66+
t.Run("set_token_nil", func(t *testing.T) {
67+
w := httptest.NewRecorder()
68+
69+
err = manager.SetTokenCookies(ctx, w, nil)
70+
71+
assert.EqualError(t, err, "[EMPTY_OAUTH_TOKEN] Attempting to set cookies with nil token")
72+
})
73+
6474
t.Run("set_token_cookies_wrong_key", func(t *testing.T) {
6575
wrongKey := base64.RawStdEncoding.EncodeToString(bytes.Repeat([]byte("X"), 75))
6676
wrongManager, err := NewCookieManager(ctx, wrongKey, wrongKey, cookieSetting)
@@ -115,31 +125,22 @@ func TestCookieManager_SetTokenCookies(t *testing.T) {
115125
assert.EqualError(t, err, "[EMPTY_OAUTH_TOKEN] Error reading existing secure cookie [flyte_idt]. Error: [SECURE_COOKIE_ERROR] Error reading secure cookie flyte_idt, caused by: securecookie: error - caused by: crypto/aes: invalid key size 75")
116126
})
117127

118-
t.Run("logout_access_cookie", func(t *testing.T) {
119-
cookie := manager.getLogoutAccessCookie()
120-
121-
assert.True(t, time.Now().After(cookie.Expires))
122-
assert.Equal(t, cookieSetting.Domain, cookie.Domain)
123-
})
124-
125-
t.Run("logout_refresh_cookie", func(t *testing.T) {
126-
cookie := manager.getLogoutRefreshCookie()
127-
128-
assert.True(t, time.Now().After(cookie.Expires))
129-
assert.Equal(t, cookieSetting.Domain, cookie.Domain)
130-
})
131-
132128
t.Run("delete_cookies", func(t *testing.T) {
133129
w := httptest.NewRecorder()
134130

135131
manager.DeleteCookies(ctx, w)
136132

137133
cookies := w.Result().Cookies()
138-
require.Equal(t, 2, len(cookies))
134+
require.Equal(t, 3, len(cookies))
139135
assert.True(t, time.Now().After(cookies[0].Expires))
140136
assert.Equal(t, cookieSetting.Domain, cookies[0].Domain)
137+
assert.Equal(t, accessTokenCookieName, cookies[0].Name)
141138
assert.True(t, time.Now().After(cookies[1].Expires))
142139
assert.Equal(t, cookieSetting.Domain, cookies[1].Domain)
140+
assert.Equal(t, refreshTokenCookieName, cookies[1].Name)
141+
assert.True(t, time.Now().After(cookies[1].Expires))
142+
assert.Equal(t, cookieSetting.Domain, cookies[1].Domain)
143+
assert.Equal(t, idTokenCookieName, cookies[2].Name)
143144
})
144145

145146
t.Run("get_http_same_site_policy", func(t *testing.T) {
@@ -152,4 +153,30 @@ func TestCookieManager_SetTokenCookies(t *testing.T) {
152153
manager.sameSitePolicy = config.SameSiteNoneMode
153154
assert.Equal(t, http.SameSiteNoneMode, manager.getHTTPSameSitePolicy())
154155
})
156+
157+
t.Run("set_user_info", func(t *testing.T) {
158+
w := httptest.NewRecorder()
159+
info := &service.UserInfoResponse{
160+
Subject: "sub",
161+
Name: "foo",
162+
}
163+
164+
err := manager.SetUserInfoCookie(ctx, w, info)
165+
166+
assert.NoError(t, err)
167+
cookies := w.Result().Cookies()
168+
require.Len(t, cookies, 1)
169+
assert.Equal(t, "flyte_user_info", cookies[0].Name)
170+
})
171+
172+
t.Run("set_auth_code", func(t *testing.T) {
173+
w := httptest.NewRecorder()
174+
175+
err := manager.SetAuthCodeCookie(ctx, w, "foo.com")
176+
177+
assert.NoError(t, err)
178+
cookies := w.Result().Cookies()
179+
require.Len(t, cookies, 1)
180+
assert.Equal(t, "flyte_auth_code", cookies[0].Name)
181+
})
155182
}

boilerplate/flyte/end2end/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst
55

66
.PHONY: end2end_execute
7+
end2end_execute: export FLYTESNACKS_PRIORITIES ?= P0
8+
end2end_execute: export FLYTESNACKS_VERSION ?= $(shell curl --silent "https://api.github.com/repos/flyteorg/flytesnacks/releases/latest" | jq -r .tag_name)
79
end2end_execute:
810
./boilerplate/flyte/end2end/end2end.sh ./boilerplate/flyte/end2end/functional-test-config.yaml --return_non_zero_on_failure
911

boilerplate/flyte/end2end/end2end.sh

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,9 @@
44
# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY:
55
#
66
# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst
7-
set -e
7+
set -eu
88

99
CONFIG_FILE=$1; shift
1010
EXTRA_FLAGS=( "$@" )
1111

12-
# By default only execute `core` tests
13-
PRIORITIES="${PRIORITIES:-P0}"
14-
15-
LATEST_VERSION=$(curl --silent "https://api.github.com/repos/flyteorg/flytesnacks/releases/latest" | jq -r .tag_name)
16-
17-
python ./boilerplate/flyte/end2end/run-tests.py $LATEST_VERSION $PRIORITIES $CONFIG_FILE ${EXTRA_FLAGS[@]}
12+
python ./boilerplate/flyte/end2end/run-tests.py $FLYTESNACKS_VERSION $FLYTESNACKS_PRIORITIES $CONFIG_FILE ${EXTRA_FLAGS[@]}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
admin:
22
# For GRPC endpoints you might want to use dns:///flyte.myexample.com
3-
endpoint: localhost:30081
3+
endpoint: dns:///localhost:30080
44
authType: Pkce
55
insecure: true

boilerplate/flyte/end2end/run-tests.py

Lines changed: 36 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
#!/usr/bin/env python3
22

3-
import click
43
import datetime
54
import json
65
import sys
76
import time
87
import traceback
8+
from typing import Dict, List, Mapping, Tuple
9+
10+
import click
911
import requests
10-
from typing import List, Mapping, Tuple, Dict
11-
from flytekit.remote import FlyteRemote
12+
from flytekit.configuration import Config
1213
from flytekit.models.core.execution import WorkflowExecutionPhase
13-
from flytekit.configuration import Config, ImageConfig, SerializationSettings
14+
from flytekit.remote import FlyteRemote
1415
from flytekit.remote.executions import FlyteWorkflowExecution
1516

16-
1717
WAIT_TIME = 10
1818
MAX_ATTEMPTS = 200
1919

@@ -22,15 +22,14 @@
2222
# starting with "core".
2323
FLYTESNACKS_WORKFLOW_GROUPS: Mapping[str, List[Tuple[str, dict]]] = {
2424
"lite": [
25-
("basics.hello_world.my_wf", {}),
26-
("basics.lp.go_greet", {"day_of_week": "5", "number": 3, "am": True}),
25+
("basics.hello_world.hello_world_wf", {}),
2726
],
2827
"core": [
29-
("basics.deck.wf", {}),
28+
# ("development_lifecycle.decks.image_renderer_wf", {}),
3029
# The chain_workflows example in flytesnacks expects to be running in a sandbox.
31-
# ("control_flow.chain_entities.chain_workflows_wf", {}),
32-
("control_flow.dynamics.wf", {"s1": "Pear", "s2": "Earth"}),
33-
("control_flow.map_task.my_map_workflow", {"a": [1, 2, 3, 4, 5]}),
30+
("advanced_composition.chain_entities.chain_workflows_wf", {}),
31+
("advanced_composition.dynamics.wf", {"s1": "Pear", "s2": "Earth"}),
32+
("advanced_composition.map_task.my_map_workflow", {"a": [1, 2, 3, 4, 5]}),
3433
# Workflows that use nested executions cannot be launched via flyteremote.
3534
# This issue is being tracked in https://github.com/flyteorg/flyte/issues/1482.
3635
# ("control_flow.run_conditions.multiplier", {"my_input": 0.5}),
@@ -41,24 +40,22 @@
4140
# ("control_flow.run_conditions.nested_conditions", {"my_input": 0.4}),
4241
# ("control_flow.run_conditions.consume_outputs", {"my_input": 0.4, "seed": 7}),
4342
# ("control_flow.run_merge_sort.merge_sort", {"numbers": [5, 4, 3, 2, 1], "count": 5}),
44-
("control_flow.subworkflows.parent_wf", {"a": 3}),
45-
("control_flow.subworkflows.nested_parent_wf", {"a": 3}),
46-
("basics.basic_workflow.my_wf", {"a": 50, "b": "hello"}),
43+
("advanced_composition.subworkflows.parent_workflow", {"my_input1": "hello"}),
44+
("advanced_composition.subworkflows.nested_parent_wf", {"a": 3}),
45+
("basics.workflow.simple_wf", {"x": [1, 2, 3], "y": [1, 2, 3]}),
4746
# TODO: enable new files and folders workflows
4847
# ("basics.files.rotate_one_workflow", {"in_image": "https://upload.wikimedia.org/wikipedia/commons/d/d2/Julia_set_%28C_%3D_0.285%2C_0.01%29.jpg"}),
4948
# ("basics.folders.download_and_rotate", {}),
50-
("basics.hello_world.my_wf", {}),
51-
("basics.lp.my_wf", {"val": 4}),
52-
("basics.lp.go_greet", {"day_of_week": "5", "number": 3, "am": True}),
53-
("basics.named_outputs.my_wf", {}),
49+
("basics.hello_world.hello_world_wf", {}),
50+
("basics.named_outputs.simple_wf_with_named_outputs", {}),
5451
# # Getting a 403 for the wikipedia image
5552
# # ("basics.reference_task.wf", {}),
56-
("type_system.custom_objects.wf", {"x": 10, "y": 20}),
53+
("data_types_and_io.custom_objects.wf", {"x": 10, "y": 20}),
5754
# Enums are not supported in flyteremote
5855
# ("type_system.enums.enum_wf", {"c": "red"}),
59-
("type_system.schema.df_wf", {"a": 42}),
60-
("type_system.typed_schema.wf", {}),
61-
#("my.imperative.workflow.example", {"in1": "hello", "in2": "foo"}),
56+
("data_types_and_io.schema.df_wf", {"a": 42}),
57+
("data_types_and_io.typed_schema.wf", {}),
58+
# ("my.imperative.workflow.example", {"in1": "hello", "in2": "foo"}),
6259
],
6360
"integrations-k8s-spark": [
6461
("k8s_spark_plugin.pyspark_pi.my_spark", {"triggered_date": datetime.datetime.now()}),
@@ -97,19 +94,22 @@ def execute_workflow(remote, version, workflow_name, inputs):
9794
wf = remote.fetch_workflow(name=workflow_name, version=version)
9895
return remote.execute(wf, inputs=inputs, wait=False)
9996

97+
10098
def executions_finished(executions_by_wfgroup: Dict[str, List[FlyteWorkflowExecution]]) -> bool:
10199
for executions in executions_by_wfgroup.values():
102100
if not all([execution.is_done for execution in executions]):
103101
return False
104102
return True
105103

104+
106105
def sync_executions(remote: FlyteRemote, executions_by_wfgroup: Dict[str, List[FlyteWorkflowExecution]]):
107106
try:
108107
for executions in executions_by_wfgroup.values():
109108
for execution in executions:
110109
print(f"About to sync execution_id={execution.id.name}")
111110
remote.sync(execution)
112-
except:
111+
except Exception:
112+
print(traceback.format_exc())
113113
print("GOT TO THE EXCEPT")
114114
print("COUNT THIS!")
115115

@@ -119,6 +119,7 @@ def report_executions(executions_by_wfgroup: Dict[str, List[FlyteWorkflowExecuti
119119
for execution in executions:
120120
print(execution)
121121

122+
122123
def schedule_workflow_groups(
123124
tag: str,
124125
workflow_groups: List[str],
@@ -139,17 +140,12 @@ def schedule_workflow_groups(
139140

140141
# Wait for all executions to finish
141142
attempt = 0
142-
while attempt == 0 or (
143-
not executions_finished(executions_by_wfgroup) and attempt < MAX_ATTEMPTS
144-
):
143+
while attempt == 0 or (not executions_finished(executions_by_wfgroup) and attempt < MAX_ATTEMPTS):
145144
attempt += 1
146-
print(
147-
f"Not all executions finished yet. Sleeping for some time, will check again in {WAIT_TIME}s"
148-
)
145+
print(f"Not all executions finished yet. Sleeping for some time, will check again in {WAIT_TIME}s")
149146
time.sleep(WAIT_TIME)
150147
sync_executions(remote, executions_by_wfgroup)
151148

152-
153149
report_executions(executions_by_wfgroup)
154150

155151
results = {}
@@ -192,14 +188,17 @@ def run(
192188

193189
# For a given release tag and priority, this function filters the workflow groups from the flytesnacks
194190
# manifest file. For example, for the release tag "v0.2.224" and the priority "P0" it returns [ "core" ].
195-
manifest_url = "https://raw.githubusercontent.com/flyteorg/flytesnacks/" \
196-
f"{flytesnacks_release_tag}/flyte_tests_manifest.json"
191+
manifest_url = (
192+
"https://raw.githubusercontent.com/flyteorg/flytesnacks/" f"{flytesnacks_release_tag}/flyte_tests_manifest.json"
193+
)
197194
r = requests.get(manifest_url)
198195
parsed_manifest = r.json()
199196
workflow_groups = []
200-
workflow_groups = ["lite"] if "lite" in priorities else [
201-
group["name"] for group in parsed_manifest if group["priority"] in priorities
202-
]
197+
workflow_groups = (
198+
["lite"]
199+
if "lite" in priorities
200+
else [group["name"] for group in parsed_manifest if group["priority"] in priorities]
201+
)
203202

204203
results = []
205204
valid_workgroups = []
@@ -216,10 +215,7 @@ def run(
216215
valid_workgroups.append(workflow_group)
217216

218217
results_by_wfgroup = schedule_workflow_groups(
219-
flytesnacks_release_tag,
220-
valid_workgroups,
221-
remote,
222-
terminate_workflow_on_failure
218+
flytesnacks_release_tag, valid_workgroups, remote, terminate_workflow_on_failure
223219
)
224220

225221
for workflow_group, succeeded in results_by_wfgroup.items():
@@ -273,9 +269,7 @@ def cli(
273269
terminate_workflow_on_failure,
274270
):
275271
print(f"return_non_zero_on_failure={return_non_zero_on_failure}")
276-
results = run(
277-
flytesnacks_release_tag, priorities, config_file, terminate_workflow_on_failure
278-
)
272+
results = run(flytesnacks_release_tag, priorities, config_file, terminate_workflow_on_failure)
279273

280274
# Write a json object in its own line describing the result of this run to stdout
281275
print(f"Result of run:\n{json.dumps(results)}")

0 commit comments

Comments
 (0)