fix: add case insensitive handler pattern (#1021)
* fix: add case insensitive handler pattern Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com> * fix: use no cache for docker build Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
This commit is contained in:
Родитель
c3c360fa41
Коммит
04554fdd60
4
Makefile
4
Makefile
|
@ -137,6 +137,7 @@ docker-buildx-builder:
|
|||
image-nmi:
|
||||
docker buildx build \
|
||||
--target nmi \
|
||||
--no-cache \
|
||||
--build-arg IMAGE_VERSION=$(IMAGE_VERSION) \
|
||||
--platform "$(BUILD_PLATFORMS)" \
|
||||
--output=type=$(OUTPUT_TYPE) \
|
||||
|
@ -146,6 +147,7 @@ image-nmi:
|
|||
image-mic:
|
||||
docker buildx build \
|
||||
--target mic \
|
||||
--no-cache \
|
||||
--build-arg IMAGE_VERSION=$(IMAGE_VERSION) \
|
||||
--platform "$(BUILD_PLATFORMS)" \
|
||||
--output=type=$(OUTPUT_TYPE) \
|
||||
|
@ -155,6 +157,7 @@ image-mic:
|
|||
image-demo:
|
||||
docker buildx build \
|
||||
--target demo \
|
||||
--no-cache \
|
||||
--build-arg IMAGE_VERSION=$(IMAGE_VERSION) \
|
||||
--platform "$(BUILD_PLATFORMS)" \
|
||||
--output=type=$(OUTPUT_TYPE) \
|
||||
|
@ -164,6 +167,7 @@ image-demo:
|
|||
image-identity-validator:
|
||||
docker buildx build \
|
||||
--target identityvalidator \
|
||||
--no-cache \
|
||||
--build-arg IMAGE_VERSION=$(IMAGE_VERSION) \
|
||||
--platform "$(BUILD_PLATFORMS)" \
|
||||
--output=type=$(OUTPUT_TYPE) \
|
||||
|
|
1
go.mod
1
go.mod
|
@ -13,6 +13,7 @@ require (
|
|||
github.com/coreos/go-iptables v0.3.0
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/google/go-cmp v0.5.2
|
||||
github.com/gorilla/mux v1.6.2
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.6.1
|
||||
go.opencensus.io v0.22.3
|
||||
|
|
2
go.sum
2
go.sum
|
@ -166,7 +166,9 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
|
|||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
|
||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
"github.com/gorilla/mux"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"github.com/Azure/aad-pod-identity/pkg/auth"
|
||||
|
@ -30,6 +31,11 @@ import (
|
|||
|
||||
const (
|
||||
localhost = "127.0.0.1"
|
||||
// "/metadata" portion is case-insensitive in IMDS
|
||||
tokenPathPrefix = "/{type:(?i:metadata)}/identity/oauth2/token" // #nosec
|
||||
hostTokenPathPrefix = "/host/token"
|
||||
// "/metadata" portion is case-insensitive in IMDS
|
||||
instancePathPrefix = "/{type:(?i:metadata)}/instance" // #nosec
|
||||
)
|
||||
|
||||
// Server encapsulates all of the parameters necessary for starting up
|
||||
|
@ -85,18 +91,16 @@ func NewServer(micNamespace string, blockInstanceMetadata bool, metadataHeaderRe
|
|||
func (s *Server) Run() error {
|
||||
go s.updateIPTableRules()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/metadata/identity/oauth2/token", appHandler(s.msiHandler))
|
||||
mux.Handle("/metadata/identity/oauth2/token/", appHandler(s.msiHandler))
|
||||
mux.Handle("/host/token", appHandler(s.hostHandler))
|
||||
mux.Handle("/host/token/", appHandler(s.hostHandler))
|
||||
rtr := mux.NewRouter()
|
||||
rtr.PathPrefix(tokenPathPrefix).Handler(appHandler(s.msiHandler))
|
||||
rtr.PathPrefix(hostTokenPathPrefix).Handler(appHandler(s.hostHandler))
|
||||
if s.BlockInstanceMetadata {
|
||||
mux.Handle("/metadata/instance", http.HandlerFunc(forbiddenHandler))
|
||||
rtr.PathPrefix(instancePathPrefix).HandlerFunc(forbiddenHandler)
|
||||
}
|
||||
mux.Handle("/", http.HandlerFunc(s.defaultPathHandler))
|
||||
rtr.PathPrefix("/").HandlerFunc(s.defaultPathHandler)
|
||||
|
||||
klog.Infof("listening on port %s", s.NMIPort)
|
||||
if err := http.ListenAndServe("localhost:"+s.NMIPort, mux); err != nil {
|
||||
if err := http.ListenAndServe("localhost:"+s.NMIPort, rtr); err != nil {
|
||||
klog.Fatalf("error creating http server: %+v", err)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -8,17 +8,19 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
var (
|
||||
mux *http.ServeMux
|
||||
rtr *mux.Router
|
||||
server *httptest.Server
|
||||
tokenPath = "/metadata/identity/oauth2/token"
|
||||
tokenPath = "/metadata/identity/oauth2/token/"
|
||||
)
|
||||
|
||||
func setup() {
|
||||
mux = http.NewServeMux()
|
||||
server = httptest.NewServer(mux)
|
||||
rtr = mux.NewRouter()
|
||||
server = httptest.NewServer(rtr)
|
||||
}
|
||||
|
||||
func teardown() {
|
||||
|
@ -32,7 +34,7 @@ func TestMsiHandler_NoMetadataHeader(t *testing.T) {
|
|||
s := &Server{
|
||||
MetadataHeaderRequired: true,
|
||||
}
|
||||
mux.Handle(tokenPath, appHandler(s.msiHandler))
|
||||
rtr.PathPrefix("/{type:(?i:metadata)}/identity/oauth2/token/").Handler(appHandler(s.msiHandler))
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, tokenPath, nil)
|
||||
if err != nil {
|
||||
|
@ -40,7 +42,7 @@ func TestMsiHandler_NoMetadataHeader(t *testing.T) {
|
|||
}
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
mux.ServeHTTP(recorder, req)
|
||||
rtr.ServeHTTP(recorder, req)
|
||||
|
||||
if recorder.Code != http.StatusBadRequest {
|
||||
t.Errorf("Unexpected status code %d", recorder.Code)
|
||||
|
@ -67,7 +69,7 @@ func TestMsiHandler_NoRemoteAddress(t *testing.T) {
|
|||
s := &Server{
|
||||
MetadataHeaderRequired: false,
|
||||
}
|
||||
mux.Handle(tokenPath, appHandler(s.msiHandler))
|
||||
rtr.PathPrefix("/{type:(?i:metadata)}/identity/oauth2/token/").Handler(appHandler(s.msiHandler))
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, tokenPath, nil)
|
||||
if err != nil {
|
||||
|
@ -75,7 +77,7 @@ func TestMsiHandler_NoRemoteAddress(t *testing.T) {
|
|||
}
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
mux.ServeHTTP(recorder, req)
|
||||
rtr.ServeHTTP(recorder, req)
|
||||
|
||||
if recorder.Code != http.StatusInternalServerError {
|
||||
t.Errorf("Unexpected status code %d", recorder.Code)
|
||||
|
@ -147,3 +149,117 @@ func TestTokenRequest_ValidateResourceParamExists(t *testing.T) {
|
|||
t.Error("ValidateResourceParamExists should have returned false when the resource is unset")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterPathPrefix(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
url string
|
||||
expectedStatusCode int
|
||||
expectedBody string
|
||||
}{
|
||||
{
|
||||
name: "token request",
|
||||
url: "/metadata/identity/oauth2/token/",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "token_request_handler",
|
||||
},
|
||||
{
|
||||
name: "token request without / suffix",
|
||||
url: "/metadata/identity/oauth2/token",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "token_request_handler",
|
||||
},
|
||||
{
|
||||
name: "token request with upper case metadata",
|
||||
url: "/Metadata/identity/oauth2/token/",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "token_request_handler",
|
||||
},
|
||||
{
|
||||
name: "token request with upper case identity",
|
||||
url: "/metadata/Identity/oauth2/token/",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "default_handler",
|
||||
},
|
||||
{
|
||||
name: "host token request",
|
||||
url: "/host/token/",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "host_token_request_handler",
|
||||
},
|
||||
{
|
||||
name: "host token request without / suffix",
|
||||
url: "/host/token",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "host_token_request_handler",
|
||||
},
|
||||
{
|
||||
name: "instance metadata request",
|
||||
url: "/metadata/instance",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "instance_request_handler",
|
||||
},
|
||||
{
|
||||
name: "instance metadata request with upper case metadata",
|
||||
url: "/Metadata/instance",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "instance_request_handler",
|
||||
},
|
||||
{
|
||||
name: "instance metadata request / suffix",
|
||||
url: "/Metadata/instance/",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "instance_request_handler",
|
||||
},
|
||||
{
|
||||
name: "default metadata request",
|
||||
url: "/metadata/",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedBody: "default_handler",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
rtr.PathPrefix(tokenPathPrefix).HandlerFunc(testTokenHandler)
|
||||
rtr.PathPrefix(hostTokenPathPrefix).HandlerFunc(testHostTokenHandler)
|
||||
rtr.PathPrefix(instancePathPrefix).HandlerFunc(testInstanceHandler)
|
||||
rtr.PathPrefix("/").HandlerFunc(testDefaultHandler)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, test.url, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
rtr.ServeHTTP(recorder, req)
|
||||
|
||||
if recorder.Code != test.expectedStatusCode {
|
||||
t.Errorf("unexpected status code %d", recorder.Code)
|
||||
}
|
||||
|
||||
if test.expectedBody != strings.TrimSpace(recorder.Body.String()) {
|
||||
t.Errorf("unexpected response body %s", recorder.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testTokenHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "token_request_handler\n")
|
||||
}
|
||||
|
||||
func testHostTokenHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "host_token_request_handler\n")
|
||||
}
|
||||
|
||||
func testInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "instance_request_handler\n")
|
||||
}
|
||||
|
||||
func testDefaultHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "default_handler\n")
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче