diff options
Diffstat (limited to 'test/e2e_test.go')
| -rw-r--r-- | test/e2e_test.go | 329 |
1 files changed, 0 insertions, 329 deletions
diff --git a/test/e2e_test.go b/test/e2e_test.go deleted file mode 100644 index a36049e3..00000000 --- a/test/e2e_test.go +++ /dev/null @@ -1,329 +0,0 @@ -package main - -import ( - "bytes" - "context" - "encoding/base64" - "net/http" - "net/url" - "strings" - "testing" - "time" - - "github.com/playwright-community/playwright-go" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/xlgmokha/x/pkg/env" - "github.com/xlgmokha/x/pkg/serde" - "github.com/xlgmokha/x/pkg/x" - "golang.org/x/oauth2" -) - -func TestAuthx(t *testing.T) { - if env.Fetch("SKIP_E2E", "") != "" { - t.Skip() - } - - _ = playwright.Install() - - pw := x.Must(playwright.Run()) - browser := x.Must(pw.Firefox.Launch(playwright.BrowserTypeLaunchOptions{ - Headless: playwright.Bool(env.Fetch("HEADLESS", "true") == "true"), - SlowMo: playwright.Float(1000), - })) - page := x.Must(browser.NewPage()) - - client := &http.Client{Timeout: 2 * time.Second} - - defer func() { - x.Check(browser.Close()) - x.Check(pw.Stop()) - }() - - t.Run("SAML", func(t *testing.T) { - for _, url := range []string{"http://idp.example.com:8080/saml/metadata.xml", "http://ui.example.com:8080/saml/metadata.xml"} { - t.Run("GET "+url, func(t *testing.T) { - response := x.Must(http.Get(url)) - assert.Equal(t, http.StatusOK, response.StatusCode) - }) - } - - t.Run("GET http://ui.example.com:8080/saml/new", func(t *testing.T) { - assert.NoError(t, page.Context().ClearCookies()) - x.Must(page.Goto("http://ui.example.com:8080/saml/new")) - action := x.Must(page.Locator("#idp-form").GetAttribute("action")) - assert.Equal(t, "http://idp.example.com:8080/saml/new", action) - assert.NoError(t, page.Locator("#submit-button").Click()) - - page.Locator("#username").Fill("root") - page.Locator("#password").Fill("root") - assert.NoError(t, page.Locator("#login-button").Click()) - - action = x.Must(page.Locator("#postback-form").GetAttribute("action")) - assert.Equal(t, "http://ui.example.com:8080/saml/assertions", action) - assert.NoError(t, page.Locator("#submit-button").Click()) - assert.Contains(t, x.Must(page.Content()), "Received SAML Response") - - t.Run("generates a usable access token", func(t *testing.T) { - rawToken := x.Must(page.Locator("#access-token").TextContent()) - accessToken := strings.Replace(rawToken, "\"", "", -1) - assert.NotEmpty(t, accessToken) - - t.Run("GET http://api.example.com:8080/projects.json", func(t *testing.T) { - request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/projects.json", nil)) - request.Header.Add("Authorization", "Bearer "+accessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - projects := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, projects) - }) - }) - - t.Run("exchange SAML assertion for access token", func(t *testing.T) { - samlAssertion := x.Must(page.Locator("#raw-saml-response").TextContent()) - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{ - "assertion": samlAssertion, - "grant_type": "urn:ietf:params:oauth:grant-type:saml2-bearer", - })) - request := x.Must(http.NewRequestWithContext(t.Context(), "POST", "http://idp.example.com:8080/oauth/token", io)) - request.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("client_id:client_secret"))) - request.Header.Add("Content-Type", "application/json ") - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - }) - }) - }) - - t.Run("OIDC", func(t *testing.T) { - t.Run("GET http://ui.example.com:8080/oidc/new", func(t *testing.T) { - assert.NoError(t, page.Context().ClearCookies()) - x.Must(page.Goto("http://ui.example.com:8080/oidc/new")) - - assert.Contains(t, page.URL(), "http://idp.example.com:8080/sessions/new") - page.Locator("#username").Fill("root") - page.Locator("#password").Fill("root") - assert.NoError(t, page.Locator("#login-button").Click()) - - assert.Contains(t, page.URL(), "http://idp.example.com:8080/oauth/authorize/continue") - assert.NoError(t, page.Locator("#submit-button").Click()) - - assert.Contains(t, page.URL(), "http://ui.example.com:8080/oauth/callback") - content := x.Must(page.Locator("pre").First().InnerText()) - item := x.Must(serde.FromJSON[oauth2.Token](strings.NewReader(content))) - require.NotEmpty(t, item.AccessToken) - require.Equal(t, "Bearer", item.TokenType) - require.NotEmpty(t, item.RefreshToken) - - t.Run("GET http://api.example.com:8080/organizations.json", func(t *testing.T) { - response := x.Must(http.Get("http://api.example.com:8080/organizations.json")) - assert.Equal(t, http.StatusForbidden, response.StatusCode) - }) - - t.Run("GET http://api.example.com:8080/organizations.json with Authorization", func(t *testing.T) { - request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/organizations.json", nil)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - organizations := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, organizations) - }) - - t.Run("GET http://api.example.com:8080/groups.json", func(t *testing.T) { - response := x.Must(http.Get("http://api.example.com:8080/groups.json")) - assert.Equal(t, http.StatusForbidden, response.StatusCode) - }) - - t.Run("GET http://api.example.com:8080/groups.json with Authorization", func(t *testing.T) { - request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/groups.json", nil)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - groups := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, groups) - }) - - t.Run("GET http://api.example.com:8080/projects.json", func(t *testing.T) { - response := x.Must(http.Get("http://api.example.com:8080/projects.json")) - assert.Equal(t, http.StatusForbidden, response.StatusCode) - }) - - t.Run("GET http://api.example.com:8080/projects.json with Authorization", func(t *testing.T) { - request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/projects.json", nil)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - projects := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, projects) - }) - - t.Run("creates a new project", func(t *testing.T) { - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{"name": "example"})) - request := x.Must(http.NewRequestWithContext(t.Context(), "POST", "http://api.example.com:8080/projects", io)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusCreated, response.StatusCode) - project := x.Must(serde.FromJSON[map[string]string](response.Body)) - assert.Equal(t, "example", project["name"]) - }) - - t.Run("creates another project", func(t *testing.T) { - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{"name": "example2"})) - request := x.Must(http.NewRequestWithContext(t.Context(), "POST", "http://api.example.com:8080/projects.json", io)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusCreated, response.StatusCode) - project := x.Must(serde.FromJSON[map[string]string](response.Body)) - assert.Equal(t, "example2", project["name"]) - }) - }) - }) - - t.Run("OAuth", func(t *testing.T) { - t.Run("GET /.well-known/oauth-authorization-server", func(t *testing.T) { - response := x.Must(client.Get("http://idp.example.com:8080/.well-known/oauth-authorization-server")) - require.Equal(t, http.StatusOK, response.StatusCode) - metadata := x.Must(serde.FromJSON[map[string]interface{}](response.Body)) - assert.Equal(t, "http://idp.example.com:8080/.well-known/oauth-authorization-server", metadata["issuer"]) - assert.Equal(t, "http://idp.example.com:8080/oauth/authorize", metadata["authorization_endpoint"]) - assert.Equal(t, "http://idp.example.com:8080/oauth/token", metadata["token_endpoint"]) - // assert.NotEmpty(t, metadata["jwks_uri"]) - // assert.NotEmpty(t, metadata["registration_endpoint"]) - assert.NotEmpty(t, metadata["scopes_supported"]) - assert.NotEmpty(t, metadata["response_types_supported"]) - assert.NotEmpty(t, metadata["response_modes_supported"]) - assert.NotEmpty(t, metadata["grant_types_supported"]) - assert.NotEmpty(t, metadata["token_endpoint_auth_methods_supported"]) - assert.NotEmpty(t, metadata["token_endpoint_auth_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["service_documentation"]) - assert.NotEmpty(t, metadata["ui_locales_supported"]) - // assert.NotEmpty(t, metadata["op_policy_uri"]) - // assert.NotEmpty(t, metadata["op_tos_uri"]) - assert.NotEmpty(t, metadata["revocation_endpoint"]) - assert.NotEmpty(t, metadata["revocation_endpoint_auth_methods_supported"]) - assert.NotEmpty(t, metadata["revocation_endpoint_auth_signing_alg_values_supported"]) - assert.NotEmpty(t, metadata["introspection_endpoint"]) - assert.NotEmpty(t, metadata["introspection_endpoint_auth_methods_supported"]) - assert.NotEmpty(t, metadata["introspection_endpoint_auth_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["code_challenge_methods_supported"]) - }) - - t.Run("GET /.well-known/openid-configuration", func(t *testing.T) { - response := x.Must(client.Get("http://idp.example.com:8080/.well-known/openid-configuration")) - require.Equal(t, http.StatusOK, response.StatusCode) - metadata := x.Must(serde.FromJSON[map[string]interface{}](response.Body)) - assert.Equal(t, "http://idp.example.com:8080/.well-known/oauth-authorization-server", metadata["issuer"]) - assert.Equal(t, "http://idp.example.com:8080/oauth/authorize", metadata["authorization_endpoint"]) - assert.Equal(t, "http://idp.example.com:8080/oauth/token", metadata["token_endpoint"]) - assert.NotEmpty(t, metadata["userinfo_endpoint"]) - // assert.NotEmpty(t, metadata["jwks_uri"]) - // assert.NotEmpty(t, metadata["registration_endpoint"]) - assert.NotEmpty(t, metadata["scopes_supported"]) - assert.NotEmpty(t, metadata["response_types_supported"]) - assert.NotEmpty(t, metadata["response_modes_supported"]) - assert.NotEmpty(t, metadata["grant_types_supported"]) - // assert.NotEmpty(t, metadata["acr_values_supported"]) - assert.NotEmpty(t, metadata["subject_types_supported"]) - assert.NotEmpty(t, metadata["id_token_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["id_token_encryption_alg_values_supported"]) - // assert.NotEmpty(t, metadata["id_token_encryption_enc_values_supported"]) - assert.NotEmpty(t, metadata["userinfo_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["userinfo_encryption_alg_values_supported"]) - // assert.NotEmpty(t, metadata["userinfo_encryption_enc_values_supported"]) - assert.NotEmpty(t, metadata["request_object_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["request_object_encryption_alg_values_supported"]) - // assert.NotEmpty(t, metadata["request_object_encryption_enc_values_supported"]) - assert.NotEmpty(t, metadata["token_endpoint_auth_methods_supported"]) - // assert.NotEmpty(t, metadata["token_endpoint_auth_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["display_values_supported"]) - assert.NotEmpty(t, metadata["claim_types_supported"]) - assert.NotEmpty(t, metadata["claims_supported"]) - // assert.NotEmpty(t, metadata["service_documentation"]) - // assert.NotEmpty(t, metadata["claims_locales_supported"]) - assert.NotEmpty(t, metadata["ui_locales_supported"]) - // assert.True(t, metadata["claims_parameter_supported"]) - // assert.True(t, metadata["request_parameter_supported"]) - // assert.True(t, metadata["request_uri_parameter_supported"]) - // assert.True(t, metadata["require_request_uri_registration"]) - // assert.NotEmpty(t, metadata["op_policy_uri"]) - // assert.NotEmpty(t, metadata["op_tos_uri"]) - }) - - t.Run("authorization code grant", func(t *testing.T) { - conf := &oauth2.Config{ - ClientID: "client_id", - ClientSecret: "client_secret", - Scopes: []string{"openid"}, - Endpoint: oauth2.Endpoint{ - TokenURL: "http://idp.example.com:8080/oauth/token", - AuthURL: "http://idp.example.com:8080/oauth/authorize", - }, - } - - authURL := conf.AuthCodeURL( - "state", - oauth2.SetAuthURLParam("client_id", "client_id"), - oauth2.SetAuthURLParam("scope", "openid"), - oauth2.SetAuthURLParam("redirect_uri", "http://example.org/oauth/callback"), - oauth2.SetAuthURLParam("response_type", "code"), - oauth2.SetAuthURLParam("response_mode", "fragment"), - ) - assert.NoError(t, page.Context().ClearCookies()) - x.Must(page.Goto(authURL)) - - page.Locator("#username").Fill("root") - page.Locator("#password").Fill("root") - assert.NoError(t, page.Locator("#login-button").Click()) - - assert.NoError(t, page.Locator("#submit-button").Click()) - - uri := x.Must(url.Parse(page.URL())) - values := x.Must(url.ParseQuery(uri.Fragment)) - code := values.Get("code") - - ctx := t.Context() - ctx = context.WithValue(ctx, oauth2.HTTPClient, client) - credentials := x.Must(conf.Exchange(ctx, code)) - assert.NotEmpty(t, credentials.AccessToken) - assert.Equal(t, "Bearer", credentials.TokenType) - assert.NotEmpty(t, credentials.RefreshToken) - - t.Run("cannot re-use the same authorization grant", func(t *testing.T) { - newCredentials, err := conf.Exchange(ctx, code) - - assert.Error(t, err) - assert.Empty(t, newCredentials) - }) - - t.Run("token is usable against REST API", func(t *testing.T) { - client := conf.Client(ctx, credentials) - response := x.Must(client.Get("http://api.example.com:8080/projects.json")) - require.Equal(t, http.StatusOK, response.StatusCode) - projects := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, projects) - - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{"name": "foo"})) - response = x.Must(client.Post("http://api.example.com:8080/projects", "application/json", io)) - require.Equal(t, http.StatusCreated, response.StatusCode) - project := x.Must(serde.FromJSON[map[string]string](response.Body)) - assert.Equal(t, "foo", project["name"]) - }) - - t.Run("token can be introspected", func(t *testing.T) { - client := conf.Client(ctx, credentials) - - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{"token": credentials.AccessToken})) - response := x.Must(client.Post("http://idp.example.com:8080/oauth/introspect", "application/json", io)) - require.Equal(t, http.StatusOK, response.StatusCode) - - claims := x.Must(serde.FromJSON[map[string]interface{}](response.Body)) - assert.Equal(t, true, claims["active"]) - assert.Equal(t, "gid://example/User/1", claims["sub"]) - }) - }) - }) -} |
