gitea/tests/integration/user_settings_test.go
Rowan Bohde 16a7d343d7
Validate OAuth Redirect URIs (#32643)
This fixes a TODO in the code to validate the RedirectURIs when adding
or editing an OAuth application in user settings.

This also includes a refactor of the user settings tests to only create
the DB once per top-level test to avoid reloading fixtures.
2024-11-28 10:50:27 +08:00

475 lines
14 KiB
Go

// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"net/http"
"testing"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
// Validate that each navbar setting is correct. This checks that the
// appropriate context is passed everywhere the navbar is rendered
func assertNavbar(t *testing.T, doc *HTMLDoc) {
// Only show the account page if users can change their email notifications, delete themselves, or manage credentials
if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureDeletion, setting.UserFeatureManageCredentials) && !setting.Service.EnableNotifyMail {
doc.AssertElement(t, ".menu a[href='/user/settings/account']", false)
} else {
doc.AssertElement(t, ".menu a[href='/user/settings/account']", true)
}
if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureManageMFA, setting.UserFeatureManageCredentials) {
doc.AssertElement(t, ".menu a[href='/user/settings/security']", false)
} else {
doc.AssertElement(t, ".menu a[href='/user/settings/security']", true)
}
if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureManageSSHKeys, setting.UserFeatureManageGPGKeys) {
doc.AssertElement(t, ".menu a[href='/user/settings/keys']", false)
} else {
doc.AssertElement(t, ".menu a[href='/user/settings/keys']", true)
}
}
func WithDisabledFeatures(t *testing.T, features ...string) {
t.Helper()
global := setting.Admin.UserDisabledFeatures
user := setting.Admin.ExternalUserDisableFeatures
setting.Admin.UserDisabledFeatures = container.SetOf(features...)
setting.Admin.ExternalUserDisableFeatures = setting.Admin.UserDisabledFeatures
t.Cleanup(func() {
setting.Admin.UserDisabledFeatures = global
setting.Admin.ExternalUserDisableFeatures = user
})
}
func TestUserSettingsAccount(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("all features enabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/account")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
// account navbar should display
doc.AssertElement(t, ".menu a[href='/user/settings/account']", true)
doc.AssertElement(t, "#password", true)
doc.AssertElement(t, "#email", true)
doc.AssertElement(t, "#delete-form", true)
})
t.Run("credentials disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageCredentials)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/account")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
doc.AssertElement(t, "#password", false)
doc.AssertElement(t, "#email", false)
doc.AssertElement(t, "#delete-form", true)
})
t.Run("deletion disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureDeletion)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/account")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
doc.AssertElement(t, "#password", true)
doc.AssertElement(t, "#email", true)
doc.AssertElement(t, "#delete-form", false)
})
t.Run("deletion, credentials and email notifications are disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
mail := setting.Service.EnableNotifyMail
setting.Service.EnableNotifyMail = false
defer func() {
setting.Service.EnableNotifyMail = mail
}()
WithDisabledFeatures(t, setting.UserFeatureDeletion, setting.UserFeatureManageCredentials)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/account")
session.MakeRequest(t, req, http.StatusNotFound)
})
}
func TestUserSettingsUpdatePassword(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("enabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/account")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
req = NewRequestWithValues(t, "POST", "/user/settings/account", map[string]string{
"_csrf": doc.GetCSRF(),
"old_password": "password",
"password": "password",
"retype": "password",
})
session.MakeRequest(t, req, http.StatusSeeOther)
})
t.Run("credentials disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageCredentials)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/account")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
req = NewRequestWithValues(t, "POST", "/user/settings/account", map[string]string{
"_csrf": doc.GetCSRF(),
})
session.MakeRequest(t, req, http.StatusNotFound)
})
}
func TestUserSettingsUpdateEmail(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("credentials disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageCredentials)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/account")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
req = NewRequestWithValues(t, "POST", "/user/settings/account/email", map[string]string{
"_csrf": doc.GetCSRF(),
})
session.MakeRequest(t, req, http.StatusNotFound)
})
}
func TestUserSettingsDeleteEmail(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("credentials disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageCredentials)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/account")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
req = NewRequestWithValues(t, "POST", "/user/settings/account/email/delete", map[string]string{
"_csrf": doc.GetCSRF(),
})
session.MakeRequest(t, req, http.StatusNotFound)
})
}
func TestUserSettingsDelete(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("deletion disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureDeletion)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/account")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
req = NewRequestWithValues(t, "POST", "/user/settings/account/delete", map[string]string{
"_csrf": doc.GetCSRF(),
})
session.MakeRequest(t, req, http.StatusNotFound)
})
}
func TestUserSettingsAppearance(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/appearance")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
}
func TestUserSettingsSecurity(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("credentials disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageCredentials)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/security")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
doc.AssertElement(t, "#register-webauthn", true)
})
t.Run("mfa disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageMFA)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/security")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
doc.AssertElement(t, "#register-webauthn", false)
})
t.Run("credentials and mfa disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageCredentials, setting.UserFeatureManageMFA)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/security")
session.MakeRequest(t, req, http.StatusNotFound)
})
}
func TestUserSettingsApplications(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("Applications", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/applications")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
})
t.Run("OAuth2", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
t.Run("OAuth2ApplicationShow", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/user/settings/applications/oauth2/2")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
})
t.Run("OAuthApplicationsEdit", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/user/settings/applications/oauth2/2")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
t.Run("Invalid URL", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequestWithValues(t, "POST", "/user/settings/applications/oauth2/2", map[string]string{
"_csrf": doc.GetCSRF(),
"application_name": "Test native app",
"redirect_uris": "ftp://127.0.0.1",
"confidential_client": "false",
})
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
msg := doc.Find(".flash-error p").Text()
assert.Equal(t, `form.RedirectURIs"ftp://127.0.0.1" is not a valid URL.`, msg)
})
t.Run("OK", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequestWithValues(t, "POST", "/user/settings/applications/oauth2/2", map[string]string{
"_csrf": doc.GetCSRF(),
"application_name": "Test native app",
"redirect_uris": "http://127.0.0.1",
"confidential_client": "false",
})
session.MakeRequest(t, req, http.StatusSeeOther)
})
})
})
}
func TestUserSettingsKeys(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("all enabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/keys")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
doc.AssertElement(t, "#add-ssh-button", true)
doc.AssertElement(t, "#add-gpg-key-panel", true)
})
t.Run("ssh keys disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageSSHKeys)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/keys")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
doc.AssertElement(t, "#add-ssh-button", false)
doc.AssertElement(t, "#add-gpg-key-panel", true)
})
t.Run("gpg keys disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageGPGKeys)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/keys")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
doc.AssertElement(t, "#add-ssh-button", true)
doc.AssertElement(t, "#add-gpg-key-panel", false)
})
t.Run("ssh & gpg keys disabled", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
WithDisabledFeatures(t, setting.UserFeatureManageSSHKeys, setting.UserFeatureManageGPGKeys)
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/keys")
_ = session.MakeRequest(t, req, http.StatusNotFound)
})
}
func TestUserSettingsSecrets(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/actions/secrets")
if setting.Actions.Enabled {
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
} else {
session.MakeRequest(t, req, http.StatusNotFound)
}
}
func TestUserSettingsPackages(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/packages")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
}
func TestUserSettingsPackagesRulesAdd(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/packages/rules/add")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
}
func TestUserSettingsOrganization(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/organization")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
}
func TestUserSettingsRepos(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/repos")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
}
func TestUserSettingsBlockedUsers(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user/settings/blocked_users")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
assertNavbar(t, doc)
}