From 3ed26b4a1199e5a4b66910bd1cab3bf041259202 Mon Sep 17 00:00:00 2001 From: "Grigoriev, Nikolai" Date: Tue, 7 Jan 2020 15:38:41 -0500 Subject: [PATCH] pipeline/authn: add unit test for token_from->cookie for both jwt and oauth2_introspection authenticators (#330) Update the schemas to add missing cookie config element Signed-off-by: Grigoriev, Nikolai --- .schemas/authenticators.jwt.schema.json | 19 +++++++++++--- ...nticators.oauth2_introspection.schema.json | 19 +++++++++++--- .schemas/config.schema.json | 15 +++++++++-- pipeline/authn/authenticator_jwt_test.go | 19 ++++++++++++++ ...authenticator_oauth2_introspection_test.go | 26 +++++++++++++++++-- 5 files changed, 88 insertions(+), 10 deletions(-) diff --git a/.schemas/authenticators.jwt.schema.json b/.schemas/authenticators.jwt.schema.json index c18a6ef8b9..0cd4965a00 100644 --- a/.schemas/authenticators.jwt.schema.json +++ b/.schemas/authenticators.jwt.schema.json @@ -52,7 +52,7 @@ }, "token_from": { "title": "Token From", - "description": "The location of the token.\n If not configured, the token will be received from a default location - 'Authorization' header.\n One and only one location (header or query) must be specified.", + "description": "The location of the token.\n If not configured, the token will be received from a default location - 'Authorization' header.\n One and only one location (header, query, or cookie) must be specified.", "oneOf": [ { "type": "object", @@ -63,7 +63,7 @@ "header": { "title": "Header", "type": "string", - "description": "The header (case insensitive) that must contain a token for request authentication. It can't be set along with query_parameter." + "description": "The header (case insensitive) that must contain a token for request authentication. It can't be set along with query_parameter or cookie." } } }, @@ -76,7 +76,20 @@ "query_parameter": { "title": "Query Parameter", "type": "string", - "description": "The query parameter (case sensitive) that must contain a token for request authentication. It can't be set along with header." + "description": "The query parameter (case sensitive) that must contain a token for request authentication. It can't be set along with header or cookie." + } + } + }, + { + "type": "object", + "required": [ + "cookie" + ], + "properties": { + "cookie": { + "title": "Cookie", + "type": "string", + "description": "The cookie (case sensitive) that must contain a token for request authentication. It can't be set along with header or query_parameter." } } } diff --git a/.schemas/authenticators.oauth2_introspection.schema.json b/.schemas/authenticators.oauth2_introspection.schema.json index a793c60a10..6e9a33f312 100644 --- a/.schemas/authenticators.oauth2_introspection.schema.json +++ b/.schemas/authenticators.oauth2_introspection.schema.json @@ -104,7 +104,7 @@ }, "token_from": { "title": "Token From", - "description": "The location of the token.\n If not configured, the token will be received from a default location - 'Authorization' header.\n One and only one location (header or query) must be specified.", + "description": "The location of the token.\n If not configured, the token will be received from a default location - 'Authorization' header.\n One and only one location (header, query, or cookie) must be specified.", "oneOf": [ { "type": "object", @@ -115,7 +115,7 @@ "header": { "title": "Header", "type": "string", - "description": "The header (case insensitive) that must contain a token for request authentication.\n It can't be set along with query_parameter." + "description": "The header (case insensitive) that must contain a token for request authentication.\n It can't be set along with query_parameter or cookie." } } }, @@ -128,7 +128,20 @@ "query_parameter": { "title": "Query Parameter", "type": "string", - "description": "The query parameter (case sensitive) that must contain a token for request authentication.\n It can't be set along with header." + "description": "The query parameter (case sensitive) that must contain a token for request authentication.\n It can't be set along with header or cookie." + } + } + }, + { + "type": "object", + "required": [ + "cookie" + ], + "properties": { + "cookie": { + "title": "Cookie", + "type": "string", + "description": "The cookie (case sensitive) that must contain a token for request authentication.\n It can't be set along with header or query_parameter." } } } diff --git a/.schemas/config.schema.json b/.schemas/config.schema.json index adca12b713..5448c21f21 100644 --- a/.schemas/config.schema.json +++ b/.schemas/config.schema.json @@ -425,7 +425,7 @@ "header": { "title": "Header", "type": "string", - "description": "The header (case insensitive) that must contain a token for request authentication. It can't be set along with query_parameter." + "description": "The header (case insensitive) that must contain a token for request authentication.\n It can't be set along with query_parameter or cookie." } } }, @@ -436,7 +436,18 @@ "query_parameter": { "title": "Query Parameter", "type": "string", - "description": "The query parameter (case sensitive) that must contain a token for request authentication. It can't be set along with header." + "description": "The query parameter (case sensitive) that must contain a token for request authentication.\n It can't be set along with header or cookie." + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "cookie": { + "title": "Cookie", + "type": "string", + "description": "The cookie (case sensitive) that must contain a token for request authentication.\n It can't be set along with header or query_parameter." } } } diff --git a/pipeline/authn/authenticator_jwt_test.go b/pipeline/authn/authenticator_jwt_test.go index 8deaaa593a..bd9e66e683 100644 --- a/pipeline/authn/authenticator_jwt_test.go +++ b/pipeline/authn/authenticator_jwt_test.go @@ -125,6 +125,16 @@ func TestAuthenticatorJWT(t *testing.T) { expectErr: true, expectExactErr: ErrAuthenticatorNotResponsible, }, + { + d: "should return error saying that authenticator is not responsible for validating the request, as the token was not provided in a proper location (cookie)", + r: &http.Request{Header: http.Header{"Cookie": []string{"biscuit=" + gen(keys[1], jwt.MapClaims{ + "sub": "sub", + "exp": now.Add(time.Hour).Unix(), + })}}}, + config: `{"token_from": {"cookie": "cake"}}`, + expectErr: true, + expectExactErr: ErrAuthenticatorNotResponsible, + }, { d: "should pass because the valid JWT token was provided in a proper location (custom header)", r: &http.Request{Header: http.Header{"X-Custom-Header": []string{gen(keys[1], jwt.MapClaims{ @@ -149,6 +159,15 @@ func TestAuthenticatorJWT(t *testing.T) { config: `{"token_from": {"query_parameter": "token"}}`, expectErr: false, }, + { + d: "should pass because the valid JWT token was provided in a proper location (cookie)", + r: &http.Request{Header: http.Header{"Cookie": []string{"biscuit=" + gen(keys[1], jwt.MapClaims{ + "sub": "sub", + "exp": now.Add(time.Hour).Unix(), + })}}}, + config: `{"token_from": {"cookie": "biscuit"}}`, + expectErr: false, + }, { d: "should pass because JWT is valid", r: &http.Request{Header: http.Header{"Authorization": []string{"bearer " + gen(keys[1], jwt.MapClaims{ diff --git a/pipeline/authn/authenticator_oauth2_introspection_test.go b/pipeline/authn/authenticator_oauth2_introspection_test.go index 399b5dddf0..1ee38990e3 100644 --- a/pipeline/authn/authenticator_oauth2_introspection_test.go +++ b/pipeline/authn/authenticator_oauth2_introspection_test.go @@ -102,7 +102,14 @@ func TestAuthenticatorOAuth2Introspection(t *testing.T) { expectExactErr: ErrAuthenticatorNotResponsible, }, { - d: "should pass because the valid JWT token was provided in a proper location (custom header)", + d: "should return error saying that authenticator is not responsible for validating the request, as the token was not provided in a proper location (cookie)", + r: &http.Request{Header: http.Header{"Cookie": {"biscuit=bearer token"}}}, + config: []byte(`{"token_from": {"cookie": "cake"}}`), + expectErr: true, + expectExactErr: ErrAuthenticatorNotResponsible, + }, + { + d: "should pass because the valid token was provided in a proper location (custom header)", r: &http.Request{Header: http.Header{"X-Custom-Header": {"token"}}}, config: []byte(`{"token_from": {"header": "X-Custom-Header"}}`), expectErr: false, @@ -117,7 +124,7 @@ func TestAuthenticatorOAuth2Introspection(t *testing.T) { }, }, { - d: "should pass because the valid JWT token was provided in a proper location (custom query parameter)", + d: "should pass because the valid token was provided in a proper location (custom query parameter)", r: &http.Request{ Form: map[string][]string{ "token": []string{"token"}, @@ -135,6 +142,21 @@ func TestAuthenticatorOAuth2Introspection(t *testing.T) { }) }, }, + { + d: "should pass because the valid token was provided in a proper location (cookie)", + r: &http.Request{Header: http.Header{"Cookie": {"biscuit=token"}}}, + config: []byte(`{"token_from": {"cookie": "biscuit"}}`), + expectErr: false, + setup: func(t *testing.T, m *httprouter.Router) { + m.POST("/oauth2/introspect", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + require.NoError(t, r.ParseForm()) + require.Equal(t, "token", r.Form.Get("token")) + require.NoError(t, json.NewEncoder(w).Encode(&AuthenticatorOAuth2IntrospectionResult{ + Active: true, + })) + }) + }, + }, { d: "should fail because not active", r: &http.Request{Header: http.Header{"Authorization": {"bearer token"}}},