mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-15 12:27:59 +00:00
693e27b906
# Which Problems Are Solved The default terms of service and privacy policy links are applied to all new ZITADEL instances, also for self hosters. However, the links contents don't apply to self-hosters. # How the Problems Are Solved The links are removed from the DefaultInstance section in the *defaults.yaml* file. By default, the links are not shown anymore in the hosted login pages. They can still be configured using the privacy policy. # Additional Context - Found because of a support request
260 lines
11 KiB
Go
260 lines
11 KiB
Go
//go:build integration
|
|
|
|
package admin_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/text/language"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"github.com/zitadel/zitadel/pkg/grpc/admin"
|
|
"github.com/zitadel/zitadel/pkg/grpc/management"
|
|
"github.com/zitadel/zitadel/pkg/grpc/text"
|
|
"github.com/zitadel/zitadel/pkg/grpc/user"
|
|
)
|
|
|
|
func TestServer_Restrictions_AllowedLanguages(t *testing.T) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
|
|
defer cancel()
|
|
|
|
var (
|
|
defaultAndAllowedLanguage = language.German
|
|
supportedLanguagesStr = []string{language.German.String(), language.English.String(), language.Japanese.String()}
|
|
disallowedLanguage = language.Spanish
|
|
unsupportedLanguage = language.Afrikaans
|
|
)
|
|
|
|
domain, _, _, iamOwnerCtx := Tester.UseIsolatedInstance(t, ctx, SystemCTX)
|
|
t.Run("assumed defaults are correct", func(tt *testing.T) {
|
|
tt.Run("languages are not restricted by default", func(ttt *testing.T) {
|
|
restrictions, err := Tester.Client.Admin.GetRestrictions(iamOwnerCtx, &admin.GetRestrictionsRequest{})
|
|
require.NoError(ttt, err)
|
|
require.Len(ttt, restrictions.AllowedLanguages, 0)
|
|
})
|
|
tt.Run("default language is English by default", func(ttt *testing.T) {
|
|
defaultLang, err := Tester.Client.Admin.GetDefaultLanguage(iamOwnerCtx, &admin.GetDefaultLanguageRequest{})
|
|
require.NoError(ttt, err)
|
|
require.Equal(ttt, language.Make(defaultLang.Language), language.English)
|
|
})
|
|
tt.Run("the discovery endpoint returns all supported languages", func(ttt *testing.T) {
|
|
awaitDiscoveryEndpoint(ttt, domain, supportedLanguagesStr, nil)
|
|
})
|
|
})
|
|
t.Run("restricting the default language fails", func(tt *testing.T) {
|
|
_, err := Tester.Client.Admin.SetRestrictions(iamOwnerCtx, &admin.SetRestrictionsRequest{AllowedLanguages: &admin.SelectLanguages{List: []string{defaultAndAllowedLanguage.String()}}})
|
|
expectStatus, ok := status.FromError(err)
|
|
require.True(tt, ok)
|
|
require.Equal(tt, codes.FailedPrecondition, expectStatus.Code())
|
|
})
|
|
t.Run("not defining any restrictions throws an error", func(tt *testing.T) {
|
|
_, err := Tester.Client.Admin.SetRestrictions(iamOwnerCtx, &admin.SetRestrictionsRequest{})
|
|
expectStatus, ok := status.FromError(err)
|
|
require.True(tt, ok)
|
|
require.Equal(tt, codes.InvalidArgument, expectStatus.Code())
|
|
})
|
|
t.Run("setting the default language works", func(tt *testing.T) {
|
|
setAndAwaitDefaultLanguage(iamOwnerCtx, tt, defaultAndAllowedLanguage)
|
|
})
|
|
t.Run("restricting allowed languages works", func(tt *testing.T) {
|
|
setAndAwaitAllowedLanguages(iamOwnerCtx, tt, []string{defaultAndAllowedLanguage.String()})
|
|
})
|
|
t.Run("GetAllowedLanguage returns only the allowed languages", func(tt *testing.T) {
|
|
expectContains, expectNotContains := []string{defaultAndAllowedLanguage.String()}, []string{disallowedLanguage.String()}
|
|
adminResp, err := Tester.Client.Admin.GetAllowedLanguages(iamOwnerCtx, &admin.GetAllowedLanguagesRequest{})
|
|
require.NoError(t, err)
|
|
langs := adminResp.GetLanguages()
|
|
assert.Condition(t, contains(langs, expectContains))
|
|
assert.Condition(t, not(contains(langs, expectNotContains)))
|
|
})
|
|
t.Run("setting the default language to a disallowed language fails", func(tt *testing.T) {
|
|
_, err := Tester.Client.Admin.SetDefaultLanguage(iamOwnerCtx, &admin.SetDefaultLanguageRequest{Language: disallowedLanguage.String()})
|
|
expectStatus, ok := status.FromError(err)
|
|
require.True(tt, ok)
|
|
require.Equal(tt, codes.FailedPrecondition, expectStatus.Code())
|
|
})
|
|
t.Run("the list of supported languages includes the disallowed languages", func(tt *testing.T) {
|
|
supported, err := Tester.Client.Admin.GetSupportedLanguages(iamOwnerCtx, &admin.GetSupportedLanguagesRequest{})
|
|
require.NoError(tt, err)
|
|
require.Condition(tt, contains(supported.GetLanguages(), supportedLanguagesStr))
|
|
})
|
|
t.Run("the disallowed language is not listed in the discovery endpoint", func(tt *testing.T) {
|
|
awaitDiscoveryEndpoint(tt, domain, []string{defaultAndAllowedLanguage.String()}, []string{disallowedLanguage.String()})
|
|
})
|
|
t.Run("the login ui is rendered in the default language", func(tt *testing.T) {
|
|
awaitLoginUILanguage(tt, domain, disallowedLanguage, defaultAndAllowedLanguage, "Passwort")
|
|
})
|
|
t.Run("preferred languages are not restricted by the supported languages", func(tt *testing.T) {
|
|
tt.Run("change user profile", func(ttt *testing.T) {
|
|
resp, err := Tester.Client.Mgmt.ListUsers(iamOwnerCtx, &management.ListUsersRequest{Queries: []*user.SearchQuery{{Query: &user.SearchQuery_UserNameQuery{UserNameQuery: &user.UserNameQuery{
|
|
UserName: "zitadel-admin@zitadel.localhost"}},
|
|
}}})
|
|
require.NoError(ttt, err)
|
|
require.Len(ttt, resp.GetResult(), 1)
|
|
humanAdmin := resp.GetResult()[0]
|
|
profile := humanAdmin.GetHuman().GetProfile()
|
|
require.NotEqual(ttt, unsupportedLanguage.String(), profile.GetPreferredLanguage())
|
|
_, updateErr := Tester.Client.Mgmt.UpdateHumanProfile(iamOwnerCtx, &management.UpdateHumanProfileRequest{
|
|
PreferredLanguage: unsupportedLanguage.String(),
|
|
UserId: humanAdmin.GetId(),
|
|
FirstName: profile.GetFirstName(),
|
|
LastName: profile.GetLastName(),
|
|
NickName: profile.GetNickName(),
|
|
DisplayName: profile.GetDisplayName(),
|
|
Gender: profile.GetGender(),
|
|
})
|
|
require.NoError(ttt, updateErr)
|
|
})
|
|
})
|
|
t.Run("custom texts are only restricted by the supported languages", func(tt *testing.T) {
|
|
_, err := Tester.Client.Admin.SetCustomLoginText(iamOwnerCtx, &admin.SetCustomLoginTextsRequest{
|
|
Language: disallowedLanguage.String(),
|
|
EmailVerificationText: &text.EmailVerificationScreenText{
|
|
Description: "hodor",
|
|
},
|
|
})
|
|
assert.NoError(tt, err)
|
|
_, err = Tester.Client.Mgmt.SetCustomLoginText(iamOwnerCtx, &management.SetCustomLoginTextsRequest{
|
|
Language: disallowedLanguage.String(),
|
|
EmailVerificationText: &text.EmailVerificationScreenText{
|
|
Description: "hodor",
|
|
},
|
|
})
|
|
assert.NoError(tt, err)
|
|
_, err = Tester.Client.Mgmt.SetCustomInitMessageText(iamOwnerCtx, &management.SetCustomInitMessageTextRequest{
|
|
Language: disallowedLanguage.String(),
|
|
Text: "hodor",
|
|
})
|
|
assert.NoError(tt, err)
|
|
_, err = Tester.Client.Admin.SetDefaultInitMessageText(iamOwnerCtx, &admin.SetDefaultInitMessageTextRequest{
|
|
Language: disallowedLanguage.String(),
|
|
Text: "hodor",
|
|
})
|
|
assert.NoError(tt, err)
|
|
})
|
|
t.Run("allowing all languages works", func(tt *testing.T) {
|
|
tt.Run("restricting allowed languages works", func(ttt *testing.T) {
|
|
setAndAwaitAllowedLanguages(iamOwnerCtx, ttt, make([]string, 0))
|
|
})
|
|
})
|
|
|
|
t.Run("allowing the language makes it usable again", func(tt *testing.T) {
|
|
tt.Run("the previously disallowed language is listed in the discovery endpoint again", func(ttt *testing.T) {
|
|
awaitDiscoveryEndpoint(ttt, domain, []string{disallowedLanguage.String()}, nil)
|
|
})
|
|
tt.Run("the login ui is rendered in the previously disallowed language", func(ttt *testing.T) {
|
|
awaitLoginUILanguage(ttt, domain, disallowedLanguage, disallowedLanguage, "Contraseña")
|
|
})
|
|
})
|
|
}
|
|
|
|
func setAndAwaitAllowedLanguages(ctx context.Context, t *testing.T, selectLanguages []string) {
|
|
_, err := Tester.Client.Admin.SetRestrictions(ctx, &admin.SetRestrictionsRequest{AllowedLanguages: &admin.SelectLanguages{List: selectLanguages}})
|
|
require.NoError(t, err)
|
|
awaitCtx, awaitCancel := context.WithTimeout(ctx, 10*time.Second)
|
|
defer awaitCancel()
|
|
await(t, awaitCtx, func(tt *assert.CollectT) {
|
|
restrictions, getErr := Tester.Client.Admin.GetRestrictions(awaitCtx, &admin.GetRestrictionsRequest{})
|
|
expectLanguages := selectLanguages
|
|
if len(selectLanguages) == 0 {
|
|
expectLanguages = nil
|
|
}
|
|
assert.NoError(tt, getErr)
|
|
assert.Equal(tt, expectLanguages, restrictions.GetAllowedLanguages())
|
|
})
|
|
}
|
|
|
|
func setAndAwaitDefaultLanguage(ctx context.Context, t *testing.T, lang language.Tag) {
|
|
_, err := Tester.Client.Admin.SetDefaultLanguage(ctx, &admin.SetDefaultLanguageRequest{Language: lang.String()})
|
|
require.NoError(t, err)
|
|
awaitCtx, awaitCancel := context.WithTimeout(ctx, 10*time.Second)
|
|
defer awaitCancel()
|
|
await(t, awaitCtx, func(tt *assert.CollectT) {
|
|
defaultLang, getErr := Tester.Client.Admin.GetDefaultLanguage(awaitCtx, &admin.GetDefaultLanguageRequest{})
|
|
assert.NoError(tt, getErr)
|
|
assert.Equal(tt, lang.String(), defaultLang.GetLanguage())
|
|
})
|
|
}
|
|
|
|
func awaitDiscoveryEndpoint(t *testing.T, domain string, containsUILocales, notContainsUILocales []string) {
|
|
awaitCtx, awaitCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer awaitCancel()
|
|
await(t, awaitCtx, func(tt *assert.CollectT) {
|
|
req, err := http.NewRequestWithContext(awaitCtx, http.MethodGet, "http://"+domain+":8080/.well-known/openid-configuration", nil)
|
|
require.NoError(tt, err)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(tt, err)
|
|
require.Equal(tt, http.StatusOK, resp.StatusCode)
|
|
body, err := io.ReadAll(resp.Body)
|
|
defer func() {
|
|
require.NoError(tt, resp.Body.Close())
|
|
}()
|
|
require.NoError(tt, err)
|
|
doc := struct {
|
|
UILocalesSupported []string `json:"ui_locales_supported"`
|
|
}{}
|
|
require.NoError(tt, json.Unmarshal(body, &doc))
|
|
if containsUILocales != nil {
|
|
assert.Condition(tt, contains(doc.UILocalesSupported, containsUILocales))
|
|
}
|
|
if notContainsUILocales != nil {
|
|
assert.Condition(tt, not(contains(doc.UILocalesSupported, notContainsUILocales)))
|
|
}
|
|
})
|
|
}
|
|
|
|
func awaitLoginUILanguage(t *testing.T, domain string, acceptLanguage language.Tag, expectLang language.Tag, containsText string) {
|
|
awaitCtx, awaitCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer awaitCancel()
|
|
await(t, awaitCtx, func(tt *assert.CollectT) {
|
|
req, err := http.NewRequestWithContext(awaitCtx, http.MethodGet, "http://"+domain+":8080/ui/login/register", nil)
|
|
req.Header.Set("Accept-Language", acceptLanguage.String())
|
|
require.NoError(t, err)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
body, err := io.ReadAll(resp.Body)
|
|
defer func() {
|
|
require.NoError(t, resp.Body.Close())
|
|
}()
|
|
require.NoError(t, err)
|
|
assert.Containsf(t, string(body), containsText, "login ui language is in "+expectLang.String())
|
|
})
|
|
}
|
|
|
|
// We would love to use assert.Contains here, but it doesn't work with slices of strings
|
|
func contains(container []string, subset []string) assert.Comparison {
|
|
return func() bool {
|
|
if subset == nil {
|
|
return true
|
|
}
|
|
for _, str := range subset {
|
|
var found bool
|
|
for _, containerStr := range container {
|
|
if str == containerStr {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
func not(cmp assert.Comparison) assert.Comparison {
|
|
return func() bool {
|
|
return !cmp()
|
|
}
|
|
}
|