fix(handlers): send status 303 auth requests that are not get/head (#2184)

When a request occurs, if the browser is not performing a HTTP GET/HEAD request, the 302 status code is not valid. This commit resolves this. MDN: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302.
This commit is contained in:
James Elliott 2021-07-16 13:43:48 +10:00 committed by GitHub
parent 596346de1e
commit ddeb46b262
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 2 deletions

View File

@ -228,8 +228,15 @@ func handleUnauthorized(ctx *middlewares.AutheliaCtx, targetURL fmt.Stringer, is
}
ctx.Logger.Infof("Access to %s (method %s) is not authorized to user %s, redirecting to %s", targetURL.String(), friendlyMethod, friendlyUsername, redirectionURL)
switch rm {
case fasthttp.MethodGet, fasthttp.MethodHead, "":
ctx.Redirect(redirectionURL, 302)
ctx.SetBodyString(fmt.Sprintf("Found. Redirecting to %s", redirectionURL))
default:
ctx.Redirect(redirectionURL, 303)
ctx.SetBodyString(fmt.Sprintf("See Other. Redirecting to %s", redirectionURL))
}
} else {
ctx.Logger.Infof("Access to %s (method %s) is not authorized to user %s, sending 401 response", targetURL.String(), friendlyMethod, friendlyUsername)
ctx.ReplyUnauthorized()

View File

@ -730,6 +730,31 @@ func TestShouldRedirectWhenSessionInactiveForTooLongAndRDParamProvided(t *testin
assert.Equal(t, clock.Now().Unix(), newUserSession.LastActivity)
}
func TestShouldRedirectWithCorrectStatusCodeBasedOnRequestMethod(t *testing.T) {
mock := mocks.NewMockAutheliaCtx(t)
defer mock.Close()
mock.Ctx.QueryArgs().Add("rd", "https://login.example.com")
mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com")
mock.Ctx.Request.Header.Set("X-Forwarded-Method", "GET")
VerifyGet(verifyGetCfg)(mock.Ctx)
assert.Equal(t, "Found. Redirecting to https://login.example.com?rd=https%3A%2F%2Ftwo-factor.example.com&rm=GET",
string(mock.Ctx.Response.Body()))
assert.Equal(t, 302, mock.Ctx.Response.StatusCode())
mock.Ctx.QueryArgs().Add("rd", "https://login.example.com")
mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com")
mock.Ctx.Request.Header.Set("X-Forwarded-Method", "POST")
VerifyGet(verifyGetCfg)(mock.Ctx)
assert.Equal(t, "See Other. Redirecting to https://login.example.com?rd=https%3A%2F%2Ftwo-factor.example.com&rm=POST",
string(mock.Ctx.Response.Body()))
assert.Equal(t, 303, mock.Ctx.Response.StatusCode())
}
func TestShouldUpdateInactivityTimestampEvenWhenHittingForbiddenResources(t *testing.T) {
mock := mocks.NewMockAutheliaCtx(t)
defer mock.Close()

View File

@ -128,6 +128,36 @@ func (s *StandaloneSuite) TestShouldRespectMethodsACL() {
s.Assert().Equal(res.StatusCode, 200)
}
func (s *StandaloneSuite) TestShouldRespondWithCorrectStatusCode() {
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify?rd=%s", AutheliaBaseURL, GetLoginBaseURL()), nil)
s.Assert().NoError(err)
req.Header.Set("X-Forwarded-Method", "GET")
req.Header.Set("X-Forwarded-Proto", "https")
req.Header.Set("X-Forwarded-Host", fmt.Sprintf("secure.%s", BaseDomain))
req.Header.Set("X-Forwarded-URI", "/")
client := NewHTTPClient()
res, err := client.Do(req)
s.Assert().NoError(err)
s.Assert().Equal(res.StatusCode, 302)
body, err := ioutil.ReadAll(res.Body)
s.Assert().NoError(err)
urlEncodedAdminURL := url.QueryEscape(SecureBaseURL + "/")
s.Assert().Equal(fmt.Sprintf("Found. Redirecting to %s?rd=%s&rm=GET", GetLoginBaseURL(), urlEncodedAdminURL), string(body))
req.Header.Set("X-Forwarded-Method", "POST")
res, err = client.Do(req)
s.Assert().NoError(err)
s.Assert().Equal(res.StatusCode, 303)
body, err = ioutil.ReadAll(res.Body)
s.Assert().NoError(err)
urlEncodedAdminURL = url.QueryEscape(SecureBaseURL + "/")
s.Assert().Equal(fmt.Sprintf("See Other. Redirecting to %s?rd=%s&rm=POST", GetLoginBaseURL(), urlEncodedAdminURL), string(body))
}
// Standard case using nginx.
func (s *StandaloneSuite) TestShouldVerifyAPIVerifyUnauthorize() {
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify", AutheliaBaseURL), nil)