Skip to content

Commit 7d5b1ba

Browse files
authored
[confighttp] Add option to include query params in auth context (#10445)
This PR adds a new option to the ServerConfig's Auth option, allowing users to specify a list of query parameters to add to the sources of auth data, in addition to HTTP headers. Instead of simply adding all parameters, which might be numeruous, we require users to specify which ones to include. Auth extensions don't need to be changed, but should document which attributes they expect to find in the context and how to configure confighttp to accomplish that. Fixes #4806 Signed-off-by: Juraci Paixão Kröhling <[email protected]> --------- Signed-off-by: Juraci Paixão Kröhling <[email protected]>
1 parent e590ed1 commit 7d5b1ba

File tree

7 files changed

+105
-20
lines changed

7 files changed

+105
-20
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
change_type: 'enhancement'
2+
component: confighttp
3+
note: Add option to include query params in auth context
4+
issues: [4806]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
change_type: 'breaking'
2+
component: confighttp
3+
note: Auth data type signature has changed
4+
subtext: |
5+
As part of the linked PR, the `auth` attribute was moved from `configauth.Authentication`
6+
to a new `AuthConfig`, which contains a `configauth.Authentication`. For end-users, this
7+
is a non-breaking change. For users of the API, create a new AuthConfig using the
8+
`configauth.Authentication` instance that was being used before.
9+
issues: [4806]
10+
change_logs: [api]

config/confighttp/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ will not be enabled.
8282
- `compression_algorithms`: configures the list of compression algorithms the server can accept. Default: ["", "gzip", "zstd", "zlib", "snappy", "deflate"]
8383
- [`tls`](../configtls/README.md)
8484
- [`auth`](../configauth/README.md)
85+
- `request_params`: a list of query parameter names to add to the auth context, along with the HTTP headers
8586

8687
You can enable [`attribute processor`][attribute-processor] to append any http header to span's attribute using custom key. You also need to enable the "include_metadata"
8788

@@ -94,6 +95,8 @@ receivers:
9495
http:
9596
include_metadata: true
9697
auth:
98+
request_params:
99+
- token
97100
authenticator: some-authenticator-extension
98101
cors:
99102
allowed_origins:

config/confighttp/confighttp.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ type ServerConfig struct {
291291
CORS *CORSConfig `mapstructure:"cors"`
292292

293293
// Auth for this receiver
294-
Auth *configauth.Authentication `mapstructure:"auth"`
294+
Auth *AuthConfig `mapstructure:"auth"`
295295

296296
// MaxRequestBodySize sets the maximum request body size in bytes. Default: 20MiB.
297297
MaxRequestBodySize int64 `mapstructure:"max_request_body_size"`
@@ -308,6 +308,15 @@ type ServerConfig struct {
308308
CompressionAlgorithms []string `mapstructure:"compression_algorithms"`
309309
}
310310

311+
type AuthConfig struct {
312+
// Auth for this receiver.
313+
*configauth.Authentication `mapstructure:"-"`
314+
315+
// RequestParameters is a list of parameters that should be extracted from the request and added to the context.
316+
// When a parameter is found in both the query string and the header, the value from the query string will be used.
317+
RequestParameters []string `mapstructure:"request_params"`
318+
}
319+
311320
// ToListener creates a net.Listener.
312321
func (hss *ServerConfig) ToListener(ctx context.Context) (net.Listener, error) {
313322
listener, err := net.Listen("tcp", hss.Endpoint)
@@ -387,7 +396,7 @@ func (hss *ServerConfig) ToServer(_ context.Context, host component.Host, settin
387396
return nil, err
388397
}
389398

390-
handler = authInterceptor(handler, server)
399+
handler = authInterceptor(handler, server, hss.Auth.RequestParameters)
391400
}
392401

393402
if hss.CORS != nil && len(hss.CORS.AllowedOrigins) > 0 {
@@ -467,9 +476,16 @@ type CORSConfig struct {
467476
MaxAge int `mapstructure:"max_age"`
468477
}
469478

470-
func authInterceptor(next http.Handler, server auth.Server) http.Handler {
479+
func authInterceptor(next http.Handler, server auth.Server, requestParams []string) http.Handler {
471480
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
472-
ctx, err := server.Authenticate(r.Context(), r.Header)
481+
sources := r.Header
482+
query := r.URL.Query()
483+
for _, param := range requestParams {
484+
if val, ok := query[param]; ok {
485+
sources[param] = val
486+
}
487+
}
488+
ctx, err := server.Authenticate(r.Context(), sources)
473489
if err != nil {
474490
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
475491
return

config/confighttp/confighttp_test.go

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -865,8 +865,10 @@ func TestHttpCorsWithSettings(t *testing.T) {
865865
CORS: &CORSConfig{
866866
AllowedOrigins: []string{"*"},
867867
},
868-
Auth: &configauth.Authentication{
869-
AuthenticatorID: mockID,
868+
Auth: &AuthConfig{
869+
Authentication: &configauth.Authentication{
870+
AuthenticatorID: mockID,
871+
},
870872
},
871873
}
872874

@@ -1168,8 +1170,10 @@ func TestServerAuth(t *testing.T) {
11681170
authCalled := false
11691171
hss := ServerConfig{
11701172
Endpoint: "localhost:0",
1171-
Auth: &configauth.Authentication{
1172-
AuthenticatorID: mockID,
1173+
Auth: &AuthConfig{
1174+
Authentication: &configauth.Authentication{
1175+
AuthenticatorID: mockID,
1176+
},
11731177
},
11741178
}
11751179

@@ -1202,8 +1206,10 @@ func TestServerAuth(t *testing.T) {
12021206

12031207
func TestInvalidServerAuth(t *testing.T) {
12041208
hss := ServerConfig{
1205-
Auth: &configauth.Authentication{
1206-
AuthenticatorID: nonExistingID,
1209+
Auth: &AuthConfig{
1210+
Authentication: &configauth.Authentication{
1211+
AuthenticatorID: nonExistingID,
1212+
},
12071213
},
12081214
}
12091215

@@ -1216,8 +1222,10 @@ func TestFailedServerAuth(t *testing.T) {
12161222
// prepare
12171223
hss := ServerConfig{
12181224
Endpoint: "localhost:0",
1219-
Auth: &configauth.Authentication{
1220-
AuthenticatorID: mockID,
1225+
Auth: &AuthConfig{
1226+
Authentication: &configauth.Authentication{
1227+
AuthenticatorID: mockID,
1228+
},
12211229
},
12221230
}
12231231
host := &mockHost{
@@ -1390,6 +1398,48 @@ func TestDefaultMaxRequestBodySize(t *testing.T) {
13901398
}
13911399
}
13921400

1401+
func TestAuthWithQueryParams(t *testing.T) {
1402+
// prepare
1403+
authCalled := false
1404+
hss := ServerConfig{
1405+
Endpoint: "localhost:0",
1406+
Auth: &AuthConfig{
1407+
RequestParameters: []string{"auth"},
1408+
Authentication: &configauth.Authentication{
1409+
AuthenticatorID: mockID,
1410+
},
1411+
},
1412+
}
1413+
1414+
host := &mockHost{
1415+
ext: map[component.ID]component.Component{
1416+
mockID: auth.NewServer(
1417+
auth.WithServerAuthenticate(func(ctx context.Context, sources map[string][]string) (context.Context, error) {
1418+
require.Len(t, sources, 1)
1419+
assert.Equal(t, "1", sources["auth"][0])
1420+
authCalled = true
1421+
return ctx, nil
1422+
}),
1423+
),
1424+
},
1425+
}
1426+
1427+
handlerCalled := false
1428+
handler := http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
1429+
handlerCalled = true
1430+
})
1431+
1432+
srv, err := hss.ToServer(context.Background(), host, componenttest.NewNopTelemetrySettings(), handler)
1433+
require.NoError(t, err)
1434+
1435+
// test
1436+
srv.Handler.ServeHTTP(&httptest.ResponseRecorder{}, httptest.NewRequest("GET", "/?auth=1", nil))
1437+
1438+
// verify
1439+
assert.True(t, handlerCalled)
1440+
assert.True(t, authCalled)
1441+
}
1442+
13931443
type mockHost struct {
13941444
component.Host
13951445
ext map[component.ID]component.Component

extension/auth/server.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ import (
1818
type Server interface {
1919
extension.Extension
2020

21-
// Authenticate checks whether the given headers map contains valid auth data. Successfully authenticated calls will always return a nil error.
21+
// Authenticate checks whether the given map contains valid auth data. Successfully authenticated calls will always return a nil error.
2222
// When the authentication fails, an error must be returned and the caller must not retry. This function is typically called from interceptors,
2323
// on behalf of receivers, but receivers can still call this directly if the usage of interceptors isn't suitable.
2424
// The deadline and cancellation given to this function must be respected, but note that authentication data has to be part of the map, not context.
2525
// The resulting context should contain the authentication data, such as the principal/username, group membership (if available), and the raw
2626
// authentication data (if possible). This will allow other components in the pipeline to make decisions based on that data, such as routing based
2727
// on tenancy as determined by the group membership, or passing through the authentication data to the next collector/backend.
2828
// The context keys to be used are not defined yet.
29-
Authenticate(ctx context.Context, headers map[string][]string) (context.Context, error)
29+
Authenticate(ctx context.Context, sources map[string][]string) (context.Context, error)
3030
}
3131

3232
type defaultServer struct {
@@ -39,14 +39,14 @@ type defaultServer struct {
3939
type ServerOption func(*defaultServer)
4040

4141
// ServerAuthenticateFunc defines the signature for the function responsible for performing the authentication based
42-
// on the given headers map. See Server.Authenticate.
43-
type ServerAuthenticateFunc func(ctx context.Context, headers map[string][]string) (context.Context, error)
42+
// on the given sources map. See Server.Authenticate.
43+
type ServerAuthenticateFunc func(ctx context.Context, sources map[string][]string) (context.Context, error)
4444

45-
func (f ServerAuthenticateFunc) Authenticate(ctx context.Context, headers map[string][]string) (context.Context, error) {
45+
func (f ServerAuthenticateFunc) Authenticate(ctx context.Context, sources map[string][]string) (context.Context, error) {
4646
if f == nil {
4747
return ctx, nil
4848
}
49-
return f(ctx, headers)
49+
return f(ctx, sources)
5050
}
5151

5252
// WithServerAuthenticate specifies which function to use to perform the authentication.

extension/zpagesextension/zpagesextension_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ func TestZPagesExtensionBadAuthExtension(t *testing.T) {
7878
cfg := &Config{
7979
confighttp.ServerConfig{
8080
Endpoint: "localhost:0",
81-
Auth: &configauth.Authentication{
82-
AuthenticatorID: component.MustNewIDWithName("foo", "bar"),
81+
Auth: &confighttp.AuthConfig{
82+
Authentication: &configauth.Authentication{
83+
AuthenticatorID: component.MustNewIDWithName("foo", "bar"),
84+
},
8385
},
8486
},
8587
}

0 commit comments

Comments
 (0)