1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2025-01-10 04:18:14 +02:00
oauth2-proxy/pkg/middleware/headers_test.go
Rishi Kambil 41cd418a5d
Fix - Refresh Session not working for multiple cookies (#1209) (#1227)
* Fix - Refresh Session not working for multiple cookies (#1209)

* added comments for flattenheaders fix

Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk>

* Updated Changelog.md

Co-authored-by: Rishi Kambil <rishi.kambil@lntinfotech.com>
Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk>
2021-06-09 10:22:33 +01:00

439 lines
11 KiB
Go

package middleware
import (
"encoding/base64"
"net/http"
"net/http/httptest"
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
)
var _ = Describe("Headers Suite", func() {
type headersTableInput struct {
headers []options.Header
initialHeaders http.Header
session *sessionsapi.SessionState
expectedHeaders http.Header
expectedErr string
}
DescribeTable("the request header injector",
func(in headersTableInput) {
scope := &middlewareapi.RequestScope{
Session: in.session,
}
// Set up the request with a request scope
req := httptest.NewRequest("", "/", nil)
req = middlewareapi.AddRequestScope(req, scope)
req.Header = in.initialHeaders.Clone()
rw := httptest.NewRecorder()
// Create the handler with a next handler that will capture the headers
// from the request
var gotHeaders http.Header
injector, err := NewRequestHeaderInjector(in.headers)
if in.expectedErr != "" {
Expect(err).To(MatchError(in.expectedErr))
return
}
Expect(err).ToNot(HaveOccurred())
handler := injector(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotHeaders = r.Header.Clone()
}))
handler.ServeHTTP(rw, req)
Expect(gotHeaders).To(Equal(in.expectedHeaders))
},
Entry("with no configured headers", headersTableInput{
headers: []options.Header{},
initialHeaders: http.Header{
"Foo": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{},
expectedHeaders: http.Header{
"Foo": []string{"bar,baz"},
},
expectedErr: "",
}),
Entry("with a claim valued header", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Foo": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{
IDToken: "IDToken-1234",
},
expectedHeaders: http.Header{
"Foo": []string{"bar,baz"},
"Claim": []string{"IDToken-1234"},
},
expectedErr: "",
}),
Entry("with a claim valued header (without preservation)", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Claim": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{
IDToken: "IDToken-1234",
},
expectedHeaders: http.Header{
"Claim": []string{"IDToken-1234"},
},
expectedErr: "",
}),
Entry("with a claim valued header (with preservation)", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
PreserveRequestValue: true,
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Claim": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{
IDToken: "IDToken-1234",
},
expectedHeaders: http.Header{
"Claim": []string{"bar,baz,IDToken-1234"},
},
expectedErr: "",
}),
Entry("with a claim valued header that's not present (without preservation)", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Claim": []string{"bar", "baz"},
},
session: nil,
expectedHeaders: http.Header{},
expectedErr: "",
}),
Entry("with a claim valued header that's not present (with preservation)", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
PreserveRequestValue: true,
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Claim": []string{"bar", "baz"},
},
session: nil,
expectedHeaders: http.Header{
"Claim": []string{"bar,baz"},
},
expectedErr: "",
}),
Entry("with an invalid basicAuthPassword claim valued header", headersTableInput{
headers: []options.Header{
{
Name: "X-Auth-Request-Authorization",
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "user",
BasicAuthPassword: &options.SecretSource{
Value: []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))),
FromEnv: "SECRET_ENV",
},
},
},
},
},
},
initialHeaders: http.Header{
"foo": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{
User: "user-123",
},
expectedHeaders: nil,
expectedErr: "error building request header injector: error building request injector: error building injector for header \"X-Auth-Request-Authorization\": error loading basicAuthPassword: secret source is invalid: exactly one entry required, specify either value, fromEnv or fromFile",
}),
)
DescribeTable("the response header injector",
func(in headersTableInput) {
scope := &middlewareapi.RequestScope{
Session: in.session,
}
// Set up the request with a request scope
req := httptest.NewRequest("", "/", nil)
req = middlewareapi.AddRequestScope(req, scope)
rw := httptest.NewRecorder()
for key, values := range in.initialHeaders {
for _, value := range values {
rw.Header().Add(key, value)
}
}
// Create the handler with a next handler that will capture the headers
// from the request
var gotHeaders http.Header
injector, err := NewResponseHeaderInjector(in.headers)
if in.expectedErr != "" {
Expect(err).To(MatchError(in.expectedErr))
return
}
Expect(err).ToNot(HaveOccurred())
handler := injector(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotHeaders = w.Header().Clone()
}))
handler.ServeHTTP(rw, req)
Expect(gotHeaders).To(Equal(in.expectedHeaders))
},
Entry("with no configured headers", headersTableInput{
headers: []options.Header{},
initialHeaders: http.Header{
"Foo": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{},
expectedHeaders: http.Header{
"Foo": []string{"bar,baz"},
},
expectedErr: "",
}),
Entry("with flattenHeaders (set-cookie and any other)", headersTableInput{
headers: []options.Header{
{
Name: "Set-Cookie",
Values: []options.HeaderValue{
{
SecretSource: &options.SecretSource{
Value: []byte("_oauth2_proxy=ey123123123"),
},
},
},
},
{
Name: "X-Auth-User",
Values: []options.HeaderValue{
{
SecretSource: &options.SecretSource{
Value: []byte("oauth_user"),
},
},
},
},
},
initialHeaders: http.Header{
"Set-Cookie": []string{"cookie1=value1", "cookie2=value2"},
"X-Auth-User": []string{"oauth_user_1"},
},
expectedHeaders: http.Header{
"Set-Cookie": []string{"cookie1=value1", "cookie2=value2", "_oauth2_proxy=ey123123123"},
"X-Auth-User": []string{"oauth_user_1,oauth_user"},
},
expectedErr: "",
}),
Entry("with a claim valued header", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Foo": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{
IDToken: "IDToken-1234",
},
expectedHeaders: http.Header{
"Foo": []string{"bar,baz"},
"Claim": []string{"IDToken-1234"},
},
expectedErr: "",
}),
Entry("with a claim valued header (without preservation)", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Claim": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{
IDToken: "IDToken-1234",
},
expectedHeaders: http.Header{
"Claim": []string{"bar,baz,IDToken-1234"},
},
expectedErr: "",
}),
Entry("with a claim valued header (with preservation)", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
PreserveRequestValue: true,
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Claim": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{
IDToken: "IDToken-1234",
},
expectedHeaders: http.Header{
"Claim": []string{"bar,baz,IDToken-1234"},
},
expectedErr: "",
}),
Entry("with a claim valued header that's not present (without preservation)", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Claim": []string{"bar", "baz"},
},
session: nil,
expectedHeaders: http.Header{
"Claim": []string{"bar,baz"},
},
expectedErr: "",
}),
Entry("with a claim valued header that's not present (with preservation)", headersTableInput{
headers: []options.Header{
{
Name: "Claim",
PreserveRequestValue: true,
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "id_token",
},
},
},
},
},
initialHeaders: http.Header{
"Claim": []string{"bar", "baz"},
},
session: nil,
expectedHeaders: http.Header{
"Claim": []string{"bar,baz"},
},
expectedErr: "",
}),
Entry("with an invalid basicAuthPassword claim valued header", headersTableInput{
headers: []options.Header{
{
Name: "X-Auth-Request-Authorization",
Values: []options.HeaderValue{
{
ClaimSource: &options.ClaimSource{
Claim: "user",
BasicAuthPassword: &options.SecretSource{
Value: []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))),
FromEnv: "SECRET_ENV",
},
},
},
},
},
},
initialHeaders: http.Header{
"foo": []string{"bar", "baz"},
},
session: &sessionsapi.SessionState{
User: "user-123",
},
expectedHeaders: nil,
expectedErr: "error building response header injector: error building response injector: error building injector for header \"X-Auth-Request-Authorization\": error loading basicAuthPassword: secret source is invalid: exactly one entry required, specify either value, fromEnv or fromFile",
}),
)
})