Path: blob/main/component/otelcol/auth/oauth2/oauth2_test.go
4096 views
package oauth2_test12import (3"context"4"fmt"5"net/http"6"net/http/httptest"7"testing"8"time"910"github.com/grafana/agent/component/otelcol/auth"11"github.com/grafana/agent/component/otelcol/auth/oauth2"12"github.com/grafana/agent/pkg/flow/componenttest"13"github.com/grafana/agent/pkg/river"14"github.com/grafana/agent/pkg/util"15"github.com/stretchr/testify/require"16"go.opentelemetry.io/collector/config/configauth"17"gotest.tools/assert"18)1920// Test performs a oauth2 integration test which runs the otelcol.auth.oauth221// component and ensures that it can be used for authentication.22func Test(t *testing.T) {23tests := []struct {24testName string25accessToken string26tokenType string27refreshToken string28configBuilder func(string) string29}{30{31"runWithRequiredParams",32"TestAccessToken",33"TestTokenType",34"TestRefreshToken",35func(srvProvidingTokensURL string) string {36return fmt.Sprintf(`37client_id = "someclientid"38client_secret = "someclientsecret"39token_url = "%s/oauth2/default/v1/token"40`, srvProvidingTokensURL)41},42},43{44"runWithOptionalParams",45"TestAccessToken",46"TestTokenType",47"TestRefreshToken",48func(srvProvidingTokensURL string) string {49return fmt.Sprintf(`50client_id = "someclientid2"51client_secret = "someclientsecret2"52token_url = "%s/oauth2/default/v1/token"53endpoint_params = {"audience" = ["someaudience"]}54scopes = ["api.metrics"]55timeout = "1s"56tls {57insecure = true58}59`, srvProvidingTokensURL)60},61},62}6364//TODO: Could we call t.Parallel() here? I am not sure if httptest.NewServer() usage is thread safe.65// For now we do the tests synchronously because there aren't that many of them anyway.66for _, tt := range tests {67t.Run(tt.testName, func(t *testing.T) {68// Create an HTTP server which will assert that oauth2 auth has been injected69// into the request.70srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {71w.WriteHeader(http.StatusOK)7273authHeader := r.Header.Get("Authorization")74expectedAuthHeader := fmt.Sprintf("%s %s", tt.tokenType, tt.accessToken)75assert.Equal(t, expectedAuthHeader, authHeader, "auth header didn't match")7677//TODO: Also write checks for `endpoint_params`` and `scopes``78}))79defer srv.Close()80t.Logf("Created server which will require authentication on address %s", srv.URL)8182srvProvidingTokens := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {83w.WriteHeader(http.StatusOK)84w.Write([]byte(fmt.Sprintf("access_token=%s&token_type=%s&refresh_token=%s", tt.accessToken, tt.tokenType, tt.refreshToken)))85}))86defer srvProvidingTokens.Close()87t.Logf("Created server which will provide authentication tokens on address %s", srvProvidingTokens.URL)8889ctx := componenttest.TestContext(t)90ctx, cancel := context.WithTimeout(ctx, time.Minute)91defer cancel()9293l := util.TestLogger(t)9495// Create and run our component96ctrl, err := componenttest.NewControllerFromID(l, "otelcol.auth.oauth2")97require.NoError(t, err)9899cfg := tt.configBuilder(srvProvidingTokens.URL)100var args oauth2.Arguments101require.NoError(t, river.Unmarshal([]byte(cfg), &args))102103go func() {104err := ctrl.Run(ctx, args)105require.NoError(t, err)106}()107108require.NoError(t, ctrl.WaitRunning(time.Second), "component never started")109require.NoError(t, ctrl.WaitExports(time.Second), "component never exported anything")110111// Get the authentication extension from our component and use it to make a112// request to our test server.113exports := ctrl.Exports().(auth.Exports)114require.NotNil(t, exports.Handler.Extension, "handler extension is nil")115116clientAuth, ok := exports.Handler.Extension.(configauth.ClientAuthenticator)117require.True(t, ok, "handler does not implement configauth.ClientAuthenticator")118119rt, err := clientAuth.RoundTripper(http.DefaultTransport)120require.NoError(t, err)121cli := &http.Client{Transport: rt}122123// Wait until the request finishes. We don't assert anything else here; our124// HTTP handler won't write the response until it ensures that the oauth2 auth125// was found.126req, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL, nil)127require.NoError(t, err)128resp, err := cli.Do(req)129require.NoError(t, err, "HTTP request failed")130require.Equal(t, http.StatusOK, resp.StatusCode)131})132}133}134135136