mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-19 06:17:32 +00:00
76fe032b5f
* feat: return 404 or 409 if org reg disallowed * fix: system limit permissions * feat: add iam limits api * feat: disallow public org registrations on default instance * add integration test * test: integration * fix test * docs: describe public org registrations * avoid updating docs deps * fix system limits integration test * silence integration tests * fix linting * ignore strange linter complaints * review * improve reset properties naming * redefine the api * use restrictions aggregate * test query * simplify and test projection * test commands * fix unit tests * move integration test * support restrictions on default instance * also test GetRestrictions * self review * lint * abstract away resource owner * fix tests * lint
107 lines
3.9 KiB
Go
107 lines
3.9 KiB
Go
//go:build integration
|
|
|
|
package admin_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"github.com/muhlemmer/gu"
|
|
"io"
|
|
"net/http"
|
|
"net/http/cookiejar"
|
|
"net/url"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/zitadel/zitadel/pkg/grpc/admin"
|
|
)
|
|
|
|
func TestServer_Restrictions_DisallowPublicOrgRegistration(t *testing.T) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
|
defer cancel()
|
|
domain, _, iamOwnerCtx := Tester.UseIsolatedInstance(ctx, SystemCTX)
|
|
regOrgUrl, err := url.Parse("http://" + domain + ":8080/ui/login/register/org")
|
|
require.NoError(t, err)
|
|
// The CSRF cookie must be sent with every request.
|
|
// We can simulate a browser session using a cookie jar.
|
|
jar, err := cookiejar.New(nil)
|
|
require.NoError(t, err)
|
|
browserSession := &http.Client{Jar: jar}
|
|
// Default should be allowed
|
|
csrfToken := awaitAllowed(t, iamOwnerCtx, browserSession, regOrgUrl)
|
|
_, err = Tester.Client.Admin.SetRestrictions(iamOwnerCtx, &admin.SetRestrictionsRequest{DisallowPublicOrgRegistration: gu.Ptr(true)})
|
|
require.NoError(t, err)
|
|
awaitDisallowed(t, iamOwnerCtx, browserSession, regOrgUrl, csrfToken)
|
|
_, err = Tester.Client.Admin.SetRestrictions(iamOwnerCtx, &admin.SetRestrictionsRequest{DisallowPublicOrgRegistration: gu.Ptr(false)})
|
|
require.NoError(t, err)
|
|
awaitAllowed(t, iamOwnerCtx, browserSession, regOrgUrl)
|
|
}
|
|
|
|
// awaitAllowed doesn't accept a CSRF token, as we expected it to always produce a new one
|
|
func awaitAllowed(t *testing.T, ctx context.Context, client *http.Client, parsedURL *url.URL) string {
|
|
csrfToken := awaitGetResponse(t, ctx, client, parsedURL, http.StatusOK)
|
|
awaitPostFormResponse(t, ctx, client, parsedURL, http.StatusOK, csrfToken)
|
|
restrictions, err := Tester.Client.Admin.GetRestrictions(ctx, &admin.GetRestrictionsRequest{})
|
|
require.NoError(t, err)
|
|
require.False(t, restrictions.DisallowPublicOrgRegistration)
|
|
return csrfToken
|
|
}
|
|
|
|
// awaitDisallowed accepts an old CSRF token, as we don't expect to get a CSRF token from the GET request anymore
|
|
func awaitDisallowed(t *testing.T, ctx context.Context, client *http.Client, parsedURL *url.URL, reuseOldCSRFToken string) {
|
|
awaitGetResponse(t, ctx, client, parsedURL, http.StatusNotFound)
|
|
awaitPostFormResponse(t, ctx, client, parsedURL, http.StatusConflict, reuseOldCSRFToken)
|
|
restrictions, err := Tester.Client.Admin.GetRestrictions(ctx, &admin.GetRestrictionsRequest{})
|
|
require.NoError(t, err)
|
|
require.True(t, restrictions.DisallowPublicOrgRegistration)
|
|
}
|
|
|
|
// awaitGetResponse cuts the CSRF token from the response body if it exists
|
|
func awaitGetResponse(t *testing.T, ctx context.Context, client *http.Client, parsedURL *url.URL, expectCode int) string {
|
|
var csrfToken []byte
|
|
await(t, ctx, func() bool {
|
|
resp, err := client.Get(parsedURL.String())
|
|
require.NoError(t, err)
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
searchField := `<input type="hidden" name="gorilla.csrf.Token" value="`
|
|
_, after, hasCsrfToken := bytes.Cut(body, []byte(searchField))
|
|
if hasCsrfToken {
|
|
csrfToken, _, _ = bytes.Cut(after, []byte(`">`))
|
|
}
|
|
return resp.StatusCode == expectCode
|
|
})
|
|
return string(csrfToken)
|
|
}
|
|
|
|
// awaitPostFormResponse needs a valid CSRF token to make it to the actual endpoint implementation and get the expected status code
|
|
func awaitPostFormResponse(t *testing.T, ctx context.Context, client *http.Client, parsedURL *url.URL, expectCode int, csrfToken string) {
|
|
await(t, ctx, func() bool {
|
|
resp, err := client.PostForm(parsedURL.String(), url.Values{
|
|
"gorilla.csrf.Token": {csrfToken},
|
|
})
|
|
require.NoError(t, err)
|
|
return resp.StatusCode == expectCode
|
|
|
|
})
|
|
}
|
|
|
|
func await(t *testing.T, ctx context.Context, cb func() bool) {
|
|
deadline, ok := ctx.Deadline()
|
|
require.True(t, ok, "context must have deadline")
|
|
require.Eventuallyf(
|
|
t,
|
|
func() bool {
|
|
defer func() {
|
|
require.Nil(t, recover(), "panic in await callback")
|
|
}()
|
|
return cb()
|
|
},
|
|
time.Until(deadline),
|
|
100*time.Millisecond,
|
|
"awaiting successful callback failed",
|
|
)
|
|
}
|