From caf2dc4fa7c6fb45a19edc5a025579d42d8db455 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Mon, 5 Jun 2023 11:29:07 +0200 Subject: [PATCH] [TESTS] auth LinkAccount test coverage (cherry picked from commit e11dcc60f291f1b882a993f60f8381fe4561d6d0) use backticks to avoid backslash (cherry picked from commit 34212791eef2031ef09ea118a2ee5b98082174dc) (cherry picked from commit bde9473c69eaf6306457b4218d9704af64cb6cc8) (cherry picked from commit d4deb43084eec4ce0de786a01acef52921a39b13) (cherry picked from commit 08e91649b0057258ea5d775447d84093c31ad523) (cherry picked from commit 2b988e5415b35e608726facb5d23a920334fda1c) [TESTS] auth LinkAccount test coverage (squash) (cherry picked from commit a2b2e3066bee46ca15ce66d0deb7ef3e89915248) (cherry picked from commit 841d1b50731a94b9330b6a623a40f8aa0a6befa8) (cherry picked from commit 35da630ad884a9ffff5bd873123687af169a6cac) --- models/auth/source.go | 12 +++ tests/integration/integration_test.go | 42 ++++++++ tests/integration/linkaccount_test.go | 141 ++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 tests/integration/linkaccount_test.go diff --git a/models/auth/source.go b/models/auth/source.go index 0a904b7772..8dd1cd4759 100644 --- a/models/auth/source.go +++ b/models/auth/source.go @@ -5,6 +5,7 @@ package auth import ( + "context" "fmt" "reflect" @@ -306,6 +307,17 @@ func GetSourceByID(id int64) (*Source, error) { return source, nil } +func GetSourceByName(ctx context.Context, name string) (*Source, error) { + source := &Source{} + has, err := db.GetEngine(ctx).Where("name = ?", name).Get(source) + if err != nil { + return nil, err + } else if !has { + return nil, ErrSourceNotExist{} + } + return source, nil +} + // UpdateSource updates a Source record in DB. func UpdateSource(source *Source) error { var originalSource *Source diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index b196533308..1f3d0902de 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -35,10 +35,12 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers" + "code.gitea.io/gitea/services/auth/source/oauth2" user_service "code.gitea.io/gitea/services/user" "code.gitea.io/gitea/tests" "github.com/PuerkitoBio/goquery" + goth_gitlab "github.com/markbates/goth/providers/gitlab" "github.com/stretchr/testify/assert" "github.com/xeipuuv/gojsonschema" ) @@ -242,6 +244,46 @@ func getUserToken(t testing.TB, userName string, scope ...auth.AccessTokenScope) return getTokenForLoggedInUser(t, loginUser(t, userName), scope...) } +func addAuthSource(t *testing.T, payload map[string]string) *auth.Source { + session := loginUser(t, "user1") + payload["_csrf"] = GetCSRF(t, session, "/admin/auths/new") + req := NewRequestWithValues(t, "POST", "/admin/auths/new", payload) + session.MakeRequest(t, req, http.StatusSeeOther) + source, err := auth.GetSourceByName(context.Background(), payload["name"]) + assert.NoError(t, err) + return source +} + +func authSourcePayloadOAuth2(name string) map[string]string { + return map[string]string{ + "type": fmt.Sprintf("%d", auth.OAuth2), + "name": name, + "is_active": "on", + } +} + +func authSourcePayloadGitLab(name string) map[string]string { + payload := authSourcePayloadOAuth2(name) + payload["oauth2_provider"] = "gitlab" + return payload +} + +func authSourcePayloadGitLabCustom(name string) map[string]string { + payload := authSourcePayloadGitLab(name) + payload["oauth2_use_custom_url"] = "on" + payload["oauth2_auth_url"] = goth_gitlab.AuthURL + payload["oauth2_token_url"] = goth_gitlab.TokenURL + payload["oauth2_profile_url"] = goth_gitlab.ProfileURL + return payload +} + +func authSourcePayloadOIDC(name string) map[string]string { + payload := authSourcePayloadOAuth2(name) + payload["oauth2_provider"] = (&oauth2.OpenIDProvider{}).Name() + payload["open_id_connect_auto_discovery_url"] = codebergURL + "/.well-known/openid-configuration" + return payload +} + func createUser(ctx context.Context, t testing.TB, user *user_model.User) func() { user.MustChangePassword = false user.LowerName = strings.ToLower(user.Name) diff --git a/tests/integration/linkaccount_test.go b/tests/integration/linkaccount_test.go new file mode 100644 index 0000000000..a951d79a60 --- /dev/null +++ b/tests/integration/linkaccount_test.go @@ -0,0 +1,141 @@ +// SPDX-FileCopyrightText: Copyright the Forgejo contributors +// SPDX-License-Identifier: MIT + +package integration + +import ( + "context" + "net/http" + "testing" + + auth_model "code.gitea.io/gitea/models/auth" + user_model "code.gitea.io/gitea/models/user" + gitea_context "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/tests" + + "github.com/markbates/goth" + "github.com/stretchr/testify/assert" +) + +const codebergURL = "https://codeberg.org" + +func TestLinkAccountChoose(t *testing.T) { + defer tests.PrepareTestEnv(t)() + ctx := context.Background() + + // Create a OIDC source and a known OAuth2 source + codebergName := "codeberg" + codeberg := addAuthSource(t, authSourcePayloadOIDC(codebergName)) + gitlabName := "gitlab" + gitlab := addAuthSource(t, authSourcePayloadGitLabCustom(gitlabName)) + + // + // A local user + // + localUser := &user_model.User{ + Name: "linkaccountuser", + Email: "linkaccountuser@example.com", + Passwd: "linkaccountuser", + Type: user_model.UserTypeIndividual, + } + defer createUser(ctx, t, localUser)() + + // + // A Codeberg user via OIDC + // + userCodebergUserID := "1234" + userCodeberg := &user_model.User{ + Name: "linkaccountcodeberguser", + Email: "linkaccountcodeberguser@example.com", + Passwd: "linkaccountcodeberguser", + Type: user_model.UserTypeIndividual, + LoginType: auth_model.OAuth2, + LoginSource: codeberg.ID, + LoginName: userCodebergUserID, + } + defer createUser(ctx, t, userCodeberg)() + + // + // A Gitlab user + // + userGitLabUserID := "5678" + userGitLab := &user_model.User{ + Name: "linkaccountgitlabuser", + Email: "linkaccountgitlabuser@example.com", + Passwd: "linkaccountgitlabuser", + Type: user_model.UserTypeIndividual, + LoginType: auth_model.OAuth2, + LoginSource: gitlab.ID, + LoginName: userGitLabUserID, + } + defer createUser(ctx, t, userGitLab)() + + defer func() { + testMiddlewareHook = nil + }() + + for _, testCase := range []struct { + title string + gothUser goth.User + signupTab string + signinTab string + }{ + { + title: "No existing user", + gothUser: goth.User{ + Provider: codebergName, + }, + signupTab: "item active", + signinTab: "item ", + }, + { + title: "Matched local user", + gothUser: goth.User{ + Provider: codebergName, + Email: localUser.Email, + }, + signupTab: "item ", + signinTab: "item active", + }, + { + title: "Matched Codeberg local user", + gothUser: goth.User{ + Provider: codebergName, + UserID: userCodebergUserID, + Email: userCodeberg.Email, + }, + signupTab: "item ", + signinTab: "item active", + }, + { + title: "Matched GitLab local user", + gothUser: goth.User{ + Provider: gitlabName, + UserID: userGitLabUserID, + Email: userGitLab.Email, + }, + signupTab: "item ", + signinTab: "item active", + }, + } { + t.Run(testCase.title, func(t *testing.T) { + testMiddlewareHook = func(ctx *gitea_context.Context) { + ctx.Session.Set("linkAccountGothUser", testCase.gothUser) + } + + req := NewRequest(t, "GET", "/user/link_account") + resp := MakeRequest(t, req, http.StatusOK) + if assert.Equal(t, resp.Code, http.StatusOK, resp.Body) { + doc := NewHTMLParser(t, resp.Body) + + class, exists := doc.Find(`.new-menu-inner .item[data-tab="auth-link-signup-tab"]`).Attr("class") + assert.True(t, exists, resp.Body) + assert.Equal(t, testCase.signupTab, class) + + class, exists = doc.Find(`.new-menu-inner .item[data-tab="auth-link-signin-tab"]`).Attr("class") + assert.True(t, exists) + assert.Equal(t, testCase.signinTab, class) + } + }) + } +}