1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2025-03-31 22:21:57 +02:00
Nick Meves 6fb3274ca3
Refactor organization of scope aware request utils
Reorganized the structure of the Request Utils due to their widespread use
resulting in circular imports issues (mostly because of middleware & logger).
2021-01-16 13:55:48 -08:00

403 lines
10 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 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",
}),
)
})