Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use HTTP 303 instead of 302 for selfservice redirects #2215

Merged
merged 9 commits into from
Feb 16, 2022

Conversation

maurice-freitag
Copy link
Contributor

The issue mentions a discrepancy between the documented response code and the actual response code sent by Kratos during selfservice flow redirects. Upon further inspection I noticed that some handlers actually did return 302 which I have changed to 303 where appropriate. Fixed docs & rebuilt sdk as well.

Related issue(s)

#1969

Checklist

  • I have read the contributing guidelines.
  • I have referenced an issue containing the design document if my change
    introduces a new feature.
  • I am following the
    contributing code guidelines.
  • I have read the security policy.
  • I confirm that this pull request does not address a security
    vulnerability. If this pull request addresses a security. vulnerability, I
    confirm that I got green light (please contact
    [email protected]) from the maintainers to push
    the changes.
  • I have added adjusted tests that prove my fix is effective or that my feature
    works.
  • I have added or changed the documentation.

@codecov
Copy link

codecov bot commented Feb 11, 2022

Codecov Report

Merging #2215 (44a6298) into master (1eb3f18) will increase coverage by 0.04%.
The diff coverage is 60.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2215      +/-   ##
==========================================
+ Coverage   75.84%   75.88%   +0.04%     
==========================================
  Files         297      297              
  Lines       15905    15905              
==========================================
+ Hits        12063    12070       +7     
+ Misses       2984     2977       -7     
  Partials      858      858              
Impacted Files Coverage Δ
selfservice/flow/login/handler.go 80.36% <ø> (ø)
selfservice/flow/logout/handler.go 83.58% <ø> (ø)
selfservice/flow/recovery/handler.go 61.81% <ø> (ø)
selfservice/flow/registration/handler.go 78.22% <0.00%> (ø)
selfservice/flow/settings/handler.go 69.93% <0.00%> (ø)
selfservice/errorx/manager.go 63.63% <100.00%> (ø)
selfservice/flow/login/error.go 72.88% <100.00%> (ø)
selfservice/flow/verification/handler.go 64.42% <100.00%> (ø)
cmd/courier/watch.go 72.41% <0.00%> (+12.06%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1eb3f18...44a6298. Read the comment docs.

@maurice-freitag
Copy link
Contributor Author

The end-to-end tests failing seems to be an issue with the current version of yq. Running yq merge ../test/e2e/profiles/kratos.base.yml ../test/e2e/profiles/email/.kratos.yml with a local installation (v3.4.1) works fine and gives the expected output. Running the same command with the version build via make .bin/yq (v4.19.1) produces the error visible in the logs here:

Error: Parsing expression: Lexer error: could not match text starting at 1:1 failing at 1:3.
unmatched text: "me"

:/

Copy link
Member

@zepatrik zepatrik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yq seems to be broken since #2206, so blame @aeneasr 😉
This looks very good, now all redirects seem consistent. Is it expected that anyone depends on a 302 code and we need to mark this as a breaking change? I would assume not...
It would be nice if you could add some tests (or probably just extend existing ones) that ensure no regression will happen.

@maurice-freitag
Copy link
Contributor Author

yq seems to be broken since #2206, so blame @aeneasr wink This looks very good, now all redirects seem consistent. Is it expected that anyone depends on a 302 code and we need to mark this as a breaking change? I would assume not... It would be nice if you could add some tests (or probably just extend existing ones) that ensure no regression will happen.

Handling the 302/303 redirect is the user agent's responsibility. According to MDN, both are supported by all browsers but 302 handling seems to be inconsistently implemented, whereas with 303 the subsequent request method is always GET, which is probably what we want when redirecting to the application UI. So if anything there is a very slim chance this could fix otherwise broken redirects if some obscure browser decides to handle 302 weirdly. In any case it makes user agent behavior more predictable I guess. I'll look into writing tests, I guess this would be a case for the e2e tests, right?

@Benehiko
Copy link
Contributor

Benehiko commented Feb 14, 2022

@maurice-freitag I agree, the response code should be 303.

I believe you can write some tests in each flow handler_test.go file. I did take a quick look and it seems we are mocking some of the calls which don't test the redirect (just something I saw when I did a quick look at the codebase this morning). In the e2e tests, we can also ensure that the response code is 303 and that the behaviour is correct.

I can take a look today to direct you properly on this :)

Copy link
Member

@zepatrik zepatrik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also say ensuring the status code in the unit tests is enough. We can't test all weird browsers anyways, so no point in adding specific cases for this issue.

@Benehiko
Copy link
Contributor

So after looking at this a bit, we don't have any tests currently covering if the redirect takes place within the flows' handler_test.go.

So I wrote a quick sample for you to add and which you can reuse in the other flows.

under selfservice/flow/login/handler_test.go

t.Run("lifecycle=init", func(t *testing.T) {
...
  t.Run("flow=browser", func(t *testing.T) {
  ...
    t.Run("case=redirects with 303", func(t *testing.T) {
	    c := ts.Client()
	    // prevent the redirect
	    c.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		    return http.ErrUseLastResponse
	    }
	    req, err := http.NewRequest("GET", ts.URL+login.RouteInitBrowserFlow, nil)
	    require.NoError(t, err)
    
	    res, err := c.Do(req)
	    require.NoError(t, err)
	    // here we check that the redirect status is 303
	    require.Equal(t, http.StatusSeeOther, res.StatusCode)
	    defer res.Body.Close()
    })

@Benehiko
Copy link
Contributor

@maurice-freitag I have opened a PR against your branch implementing the login and logout handler tests.
You can merge it and continue with the rest of the tests :)
It should give you enough context to continue, if you get stuck don't be afraid to ping me or @zepatrik
maurice-freitag#1

@maurice-freitag
Copy link
Contributor Author

ests :)
It should give you enough context to continue, if you get stuck don't be afraid to ping me or @zepatrik
maurice-freitag#1

ty! I merged your changes and will get going with the other tests asap :)

@maurice-freitag
Copy link
Contributor Author

Seems the docs have moved 🙈 I'll look into it when I get the chance

@Benehiko
Copy link
Contributor

Ah yes @maurice-freitag you can add the docs to https://github.com/ory/docs

Sorry about that, we've been doing some major changes to the structure of our documentation.

Copy link
Contributor

@Benehiko Benehiko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks quite good :)
I think it's almost done, just a small change and the docs and this should be good to go!

Comment on lines 162 to 180

t.Run("case=redirects with 303", func(t *testing.T) {
c := http.DefaultClient
// don't get the reference, instead copy the values, so we don't alter the client directly.
*c = *publicTS.Client()
// prevent the redirect
c.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
req, err := http.NewRequest("GET", publicTS.URL+settings.RouteInitBrowserFlow, nil)
require.NoError(t, err)

res, err := c.Do(req)
require.NoError(t, err)
// here we check that the redirect status is 303
require.Equal(t, http.StatusSeeOther, res.StatusCode)
defer res.Body.Close()
})
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this will work, since we need a session first before we initialize a settings flow

https://www.ory.sh/kratos/docs/self-service/flows/user-settings#user-and-profile-settings-for-server-side-browser-clients

Also shown in one of the tests above:

t.Run("description=success", func(t *testing.T) {
	user1 := testhelpers.NewHTTPClientWithArbitrarySessionCookie(t, reg)
	res, body := initFlow(t, user1, false)
	assert.Contains(t, res.Request.URL.String(), reg.Config(context.Background()).SelfServiceFlowSettingsUI().String())
    assertion(t, body, false)
})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test ran through, I switched the default client with the one including the session cookie anyways since all other tests here use it as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also instantiated a new http client instead of using http.DefaultClient because some subsequent tests where failing due to the changed redirect behavior on the default instance.

@maurice-freitag
Copy link
Contributor Author

The PR for the docs is now open as well: ory/docs#598

@aeneasr
Copy link
Member

aeneasr commented Feb 16, 2022

Thank you! :)

@aeneasr aeneasr merged commit 50b6bd8 into ory:master Feb 16, 2022
@vinckr
Copy link
Member

vinckr commented Feb 16, 2022

Hello @maurice-freitag
Congrats on merging your first PR in Ory 🎉 !
Your contribution will soon be helping secure millions of identities around the globe 🌏.
As a small token of appreciation we send all our first time contributors a gift package to welcome them to the community.
Please drop me an email and I will forward you the form to claim your Ory swag!

@vinckr vinckr mentioned this pull request Mar 9, 2022
7 tasks
@vinckr vinckr mentioned this pull request Mar 10, 2022
7 tasks
@vinckr vinckr mentioned this pull request Mar 18, 2022
peturgeorgievv pushed a commit to senteca/kratos-fork that referenced this pull request Jun 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants