mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-22 15:23:14 -05:00
Refactor CSRF protector (#32057) (fix forgejo tests)
Fix the tests unique to Forgejo that are impacted by the refactor.
(cherry picked from commit 6275d1bc50
)
This commit is contained in:
parent
d26b7902ec
commit
5b6d8a303d
3 changed files with 59 additions and 38 deletions
|
@ -30,8 +30,9 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
CsrfHeaderName = "X-Csrf-Token"
|
||||
CsrfFormName = "_csrf"
|
||||
CsrfHeaderName = "X-Csrf-Token"
|
||||
CsrfFormName = "_csrf"
|
||||
CsrfErrorString = "Invalid CSRF token."
|
||||
)
|
||||
|
||||
// CSRFProtector represents a CSRF protector and is used to get the current token and validate the token.
|
||||
|
@ -144,7 +145,7 @@ func (c *csrfProtector) validateToken(ctx *Context, token string) {
|
|||
c.DeleteCookie(ctx)
|
||||
// currently, there should be no access to the APIPath with CSRF token. because templates shouldn't use the `/api/` endpoints.
|
||||
// FIXME: distinguish what the response is for: HTML (web page) or JSON (fetch)
|
||||
http.Error(ctx.Resp, "Invalid CSRF token.", http.StatusBadRequest)
|
||||
http.Error(ctx.Resp, CsrfErrorString, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
forgejo_context "code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -190,11 +191,6 @@ func TestRedirectsWebhooks(t *testing.T) {
|
|||
{from: "/user/settings/hooks/" + kind + "/new", to: "/user/login", verb: "GET"},
|
||||
{from: "/admin/system-hooks/" + kind + "/new", to: "/user/login", verb: "GET"},
|
||||
{from: "/admin/default-hooks/" + kind + "/new", to: "/user/login", verb: "GET"},
|
||||
{from: "/user2/repo1/settings/hooks/" + kind + "/new", to: "/", verb: "POST"},
|
||||
{from: "/admin/system-hooks/" + kind + "/new", to: "/", verb: "POST"},
|
||||
{from: "/admin/default-hooks/" + kind + "/new", to: "/", verb: "POST"},
|
||||
{from: "/user2/repo1/settings/hooks/1", to: "/", verb: "POST"},
|
||||
{from: "/admin/hooks/1", to: "/", verb: "POST"},
|
||||
}
|
||||
for _, info := range redirects {
|
||||
req := NewRequest(t, info.verb, info.from)
|
||||
|
@ -202,6 +198,24 @@ func TestRedirectsWebhooks(t *testing.T) {
|
|||
assert.EqualValues(t, path.Join(setting.AppSubURL, info.to), test.RedirectURL(resp), info.from)
|
||||
}
|
||||
}
|
||||
|
||||
for _, kind := range []string{"forgejo", "gitea"} {
|
||||
csrf := []struct {
|
||||
from string
|
||||
verb string
|
||||
}{
|
||||
{from: "/user2/repo1/settings/hooks/" + kind + "/new", verb: "POST"},
|
||||
{from: "/admin/hooks/1", verb: "POST"},
|
||||
{from: "/admin/system-hooks/" + kind + "/new", verb: "POST"},
|
||||
{from: "/admin/default-hooks/" + kind + "/new", verb: "POST"},
|
||||
{from: "/user2/repo1/settings/hooks/1", verb: "POST"},
|
||||
}
|
||||
for _, info := range csrf {
|
||||
req := NewRequest(t, info.verb, info.from)
|
||||
resp := MakeRequest(t, req, http.StatusBadRequest)
|
||||
assert.Contains(t, resp.Body.String(), forgejo_context.CsrfErrorString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoLinks(t *testing.T) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -24,6 +25,7 @@ import (
|
|||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/routers/web/auth"
|
||||
forgejo_context "code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
|
@ -803,6 +805,16 @@ func TestOAuthIntrospection(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func requireCookieCSRF(t *testing.T, resp http.ResponseWriter) string {
|
||||
for _, c := range resp.(*httptest.ResponseRecorder).Result().Cookies() {
|
||||
if c.Name == "_csrf" {
|
||||
return c.Value
|
||||
}
|
||||
}
|
||||
require.True(t, false, "_csrf not found in cookies")
|
||||
return ""
|
||||
}
|
||||
|
||||
func TestOAuth_GrantScopesReadUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
|
@ -840,19 +852,18 @@ func TestOAuth_GrantScopesReadUser(t *testing.T) {
|
|||
authorizeResp := ctx.MakeRequest(t, authorizeReq, http.StatusSeeOther)
|
||||
|
||||
authcode := strings.Split(strings.Split(authorizeResp.Body.String(), "?code=")[1], "&")[0]
|
||||
htmlDoc := NewHTMLParser(t, authorizeResp.Body)
|
||||
grantReq := NewRequestWithValues(t, "POST", "/login/oauth/grant", map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"client_id": app.ClientID,
|
||||
"redirect_uri": "a",
|
||||
"state": "thestate",
|
||||
"granted": "true",
|
||||
})
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusSeeOther)
|
||||
htmlDocGrant := NewHTMLParser(t, grantResp.Body)
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusBadRequest)
|
||||
assert.NotContains(t, grantResp.Body.String(), forgejo_context.CsrfErrorString)
|
||||
|
||||
accessTokenReq := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
|
||||
"_csrf": htmlDocGrant.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"grant_type": "authorization_code",
|
||||
"client_id": app.ClientID,
|
||||
"client_secret": app.ClientSecret,
|
||||
|
@ -921,19 +932,18 @@ func TestOAuth_GrantScopesFailReadRepository(t *testing.T) {
|
|||
authorizeResp := ctx.MakeRequest(t, authorizeReq, http.StatusSeeOther)
|
||||
|
||||
authcode := strings.Split(strings.Split(authorizeResp.Body.String(), "?code=")[1], "&")[0]
|
||||
htmlDoc := NewHTMLParser(t, authorizeResp.Body)
|
||||
grantReq := NewRequestWithValues(t, "POST", "/login/oauth/grant", map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"client_id": app.ClientID,
|
||||
"redirect_uri": "a",
|
||||
"state": "thestate",
|
||||
"granted": "true",
|
||||
})
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusSeeOther)
|
||||
htmlDocGrant := NewHTMLParser(t, grantResp.Body)
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusBadRequest)
|
||||
assert.NotContains(t, grantResp.Body.String(), forgejo_context.CsrfErrorString)
|
||||
|
||||
accessTokenReq := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
|
||||
"_csrf": htmlDocGrant.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"grant_type": "authorization_code",
|
||||
"client_id": app.ClientID,
|
||||
"client_secret": app.ClientSecret,
|
||||
|
@ -1000,19 +1010,18 @@ func TestOAuth_GrantScopesReadRepository(t *testing.T) {
|
|||
authorizeResp := ctx.MakeRequest(t, authorizeReq, http.StatusSeeOther)
|
||||
|
||||
authcode := strings.Split(strings.Split(authorizeResp.Body.String(), "?code=")[1], "&")[0]
|
||||
htmlDoc := NewHTMLParser(t, authorizeResp.Body)
|
||||
grantReq := NewRequestWithValues(t, "POST", "/login/oauth/grant", map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"client_id": app.ClientID,
|
||||
"redirect_uri": "a",
|
||||
"state": "thestate",
|
||||
"granted": "true",
|
||||
})
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusSeeOther)
|
||||
htmlDocGrant := NewHTMLParser(t, grantResp.Body)
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusBadRequest)
|
||||
assert.NotContains(t, grantResp.Body.String(), forgejo_context.CsrfErrorString)
|
||||
|
||||
accessTokenReq := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
|
||||
"_csrf": htmlDocGrant.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"grant_type": "authorization_code",
|
||||
"client_id": app.ClientID,
|
||||
"client_secret": app.ClientSecret,
|
||||
|
@ -1082,19 +1091,18 @@ func TestOAuth_GrantScopesReadPrivateGroups(t *testing.T) {
|
|||
authorizeResp := ctx.MakeRequest(t, authorizeReq, http.StatusSeeOther)
|
||||
|
||||
authcode := strings.Split(strings.Split(authorizeResp.Body.String(), "?code=")[1], "&")[0]
|
||||
htmlDoc := NewHTMLParser(t, authorizeResp.Body)
|
||||
grantReq := NewRequestWithValues(t, "POST", "/login/oauth/grant", map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"client_id": app.ClientID,
|
||||
"redirect_uri": "a",
|
||||
"state": "thestate",
|
||||
"granted": "true",
|
||||
})
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusSeeOther)
|
||||
htmlDocGrant := NewHTMLParser(t, grantResp.Body)
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusBadRequest)
|
||||
assert.NotContains(t, grantResp.Body.String(), forgejo_context.CsrfErrorString)
|
||||
|
||||
accessTokenReq := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
|
||||
"_csrf": htmlDocGrant.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"grant_type": "authorization_code",
|
||||
"client_id": app.ClientID,
|
||||
"client_secret": app.ClientSecret,
|
||||
|
@ -1164,19 +1172,18 @@ func TestOAuth_GrantScopesReadOnlyPublicGroups(t *testing.T) {
|
|||
authorizeResp := ctx.MakeRequest(t, authorizeReq, http.StatusSeeOther)
|
||||
|
||||
authcode := strings.Split(strings.Split(authorizeResp.Body.String(), "?code=")[1], "&")[0]
|
||||
htmlDoc := NewHTMLParser(t, authorizeResp.Body)
|
||||
grantReq := NewRequestWithValues(t, "POST", "/login/oauth/grant", map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"client_id": app.ClientID,
|
||||
"redirect_uri": "a",
|
||||
"state": "thestate",
|
||||
"granted": "true",
|
||||
})
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusSeeOther)
|
||||
htmlDocGrant := NewHTMLParser(t, grantResp.Body)
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusBadRequest)
|
||||
assert.NotContains(t, grantResp.Body.String(), forgejo_context.CsrfErrorString)
|
||||
|
||||
accessTokenReq := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
|
||||
"_csrf": htmlDocGrant.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"grant_type": "authorization_code",
|
||||
"client_id": app.ClientID,
|
||||
"client_secret": app.ClientSecret,
|
||||
|
@ -1260,19 +1267,18 @@ func TestOAuth_GrantScopesReadPublicGroupsWithTheReadScope(t *testing.T) {
|
|||
authorizeResp := ctx.MakeRequest(t, authorizeReq, http.StatusSeeOther)
|
||||
|
||||
authcode := strings.Split(strings.Split(authorizeResp.Body.String(), "?code=")[1], "&")[0]
|
||||
htmlDoc := NewHTMLParser(t, authorizeResp.Body)
|
||||
grantReq := NewRequestWithValues(t, "POST", "/login/oauth/grant", map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"client_id": app.ClientID,
|
||||
"redirect_uri": "a",
|
||||
"state": "thestate",
|
||||
"granted": "true",
|
||||
})
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusSeeOther)
|
||||
htmlDocGrant := NewHTMLParser(t, grantResp.Body)
|
||||
grantResp := ctx.MakeRequest(t, grantReq, http.StatusBadRequest)
|
||||
assert.NotContains(t, grantResp.Body.String(), forgejo_context.CsrfErrorString)
|
||||
|
||||
accessTokenReq := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
|
||||
"_csrf": htmlDocGrant.GetCSRF(),
|
||||
"_csrf": requireCookieCSRF(t, authorizeResp),
|
||||
"grant_type": "authorization_code",
|
||||
"client_id": app.ClientID,
|
||||
"client_secret": app.ClientSecret,
|
||||
|
|
Loading…
Reference in a new issue