Verified Commit 4859ed02 authored by Timo Furrer's avatar Timo Furrer Committed by GitLab
Browse files

Merge branch 'unauthenticated-client' into 'main'

Support unauthenticated clients via Unauthenticated auth source

See merge request gitlab-org/api/client-go!2761
parents 29c4263b b28444ad
Loading
Loading
Loading
Loading
Loading
+26 −6
Original line number Diff line number Diff line
@@ -73,7 +73,13 @@ const (
	PrivateToken
)

var ErrNotFound = errors.New("404 Not Found")
var (
	// ErrNotFound is returned for 404 Not Found errors
	ErrNotFound = errors.New("404 Not Found")

	// errUnauthenticated is an internal sentinel error to indicate that the auth source doesn't use any authentication
	errUnauthenticated = errors.New("unauthenticated")
)

// URLValidationError wraps URL parsing errors with helpful context
type URLValidationError struct {
@@ -1162,13 +1168,16 @@ func (c *Client) Do(req *retryablehttp.Request, v any) (*Response, error) {
	}

	authKey, authValue, err := c.authSource.Header(req.Context())
	if err != nil {
		return nil, err
	}

	switch err {
	case nil:
		if v := req.Header.Values(authKey); len(v) == 0 {
			req.Header.Set(authKey, authValue)
		}
	case errUnauthenticated: //nolint:errorlint
		// we simply skip using an auth header
	default: // err != nil
		return nil, err
	}

	client := c.client

@@ -1453,3 +1462,14 @@ func (as *PasswordCredentialsAuthSource) Init(ctx context.Context, client *Clien

	return nil
}

// Unauthenticated is an authentication source for unauthenticated clients
type Unauthenticated struct{}

func (Unauthenticated) Init(context.Context, *Client) error {
	return nil
}

func (u Unauthenticated) Header(context.Context) (string, string, error) {
	return "", "", errUnauthenticated
}
+33 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ var timeLayout = "2006-01-02T15:04:05Z07:00"

// Interface implementation checks.
var (
	_ AuthSource = Unauthenticated{}
	_ AuthSource = OAuthTokenSource{}
	_ AuthSource = JobTokenAuthSource{}
	_ AuthSource = AccessTokenAuthSource{}
@@ -849,6 +850,38 @@ func TestNewAuthSourceClient(t *testing.T) {
	assert.Equal(t, []*Project{}, projects)
}

func TestNewAuthSourceClient_Unauthenticated(t *testing.T) {
	t.Parallel()

	handler := func(w http.ResponseWriter, r *http.Request) {
		av := r.Header.Get("Authorization")
		pv := r.Header.Get(AccessTokenHeaderName)
		jv := r.Header.Get(JobTokenHeaderName)

		if av != "" || pv != "" || jv != "" {
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		fmt.Fprint(w, "[]")
	}

	server := httptest.NewServer(http.HandlerFunc(handler))
	t.Cleanup(server.Close)

	client, err := NewAuthSourceClient(Unauthenticated{},
		WithBaseURL(server.URL),
		WithHTTPClient(server.Client()),
	)
	require.NoError(t, err)

	projects, resp, err := client.Projects.ListProjects(&ListProjectsOptions{})
	require.NoError(t, err)

	assert.Equal(t, http.StatusOK, resp.StatusCode)
	assert.Equal(t, []*Project{}, projects)
}

func TestHasStatusCode(t *testing.T) {
	t.Parallel()