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:
Anish Ramasekar 2021-03-30 13:05:05 -07:00 коммит произвёл GitHub
Родитель c3c360fa41
Коммит 04554fdd60
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 143 добавлений и 16 удалений

Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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")
}