From 6deaa0fb1a769ac1b8cd4825272cb145faa4ea1b Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Thu, 10 Sep 2020 18:34:18 -0700 Subject: [PATCH] Fix lint errors --- cmd/local-user-authenticator/main.go | 92 ++++++++++++---------- cmd/local-user-authenticator/main_test.go | 6 +- test/integration/credentialrequest_test.go | 1 + 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/cmd/local-user-authenticator/main.go b/cmd/local-user-authenticator/main.go index b5d1400e..4d66ea4e 100644 --- a/cmd/local-user-authenticator/main.go +++ b/cmd/local-user-authenticator/main.go @@ -35,6 +35,7 @@ import ( restclient "k8s.io/client-go/rest" "k8s.io/klog/v2" + "github.com/suzerain-io/pinniped/internal/constable" "github.com/suzerain-io/pinniped/internal/controller/apicerts" "github.com/suzerain-io/pinniped/internal/controllerlib" "github.com/suzerain-io/pinniped/internal/provider" @@ -46,14 +47,13 @@ const ( // This string must match the name of the Service declared in the deployment yaml. serviceName = "local-user-authenticator" - // TODO there must be a better way to get this specific json result string without needing to hardcode it - unauthenticatedResponse = `{"apiVersion":"authentication.k8s.io/v1beta1","kind":"TokenReview","status":{"authenticated":false}}` - - // TODO there must be a better way to get this specific json result string without needing to hardcode it + unauthenticatedResponse = `{"apiVersion":"authentication.k8s.io/v1beta1","kind":"TokenReview","status":{"authenticated":false}}` authenticatedResponseTemplate = `{"apiVersion":"authentication.k8s.io/v1beta1","kind":"TokenReview","status":{"authenticated":true,"user":{"username":"%s","uid":"%s","groups":%s}}}` singletonWorker = 1 defaultResyncInterval = 3 * time.Minute + + invalidRequest = constable.Error("invalid request") ) type webhook struct { @@ -111,47 +111,11 @@ func (w *webhook) start(ctx context.Context, l net.Listener) error { func (w *webhook) ServeHTTP(rsp http.ResponseWriter, req *http.Request) { defer req.Body.Close() - if req.URL.Path != "/authenticate" { - klog.InfoS("received request path other than /authenticate", "path", req.URL.Path) - rsp.WriteHeader(http.StatusNotFound) + username, password, err := getUsernameAndPasswordFromRequest(rsp, req) + if err != nil { return } - if req.Method != http.MethodPost { - klog.InfoS("received request method other than post", "method", req.Method) - rsp.WriteHeader(http.StatusMethodNotAllowed) - return - } - - if !headerContains(req, "Content-Type", "application/json") { - klog.InfoS("content type is not application/json", "Content-Type", req.Header.Values("Content-Type")) - rsp.WriteHeader(http.StatusUnsupportedMediaType) - return - } - if !headerContains(req, "Accept", "application/json") && - !headerContains(req, "Accept", "application/*") && - !headerContains(req, "Accept", "*/*") { - klog.InfoS("client does not accept application/json", "Accept", req.Header.Values("Accept")) - rsp.WriteHeader(http.StatusUnsupportedMediaType) - return - } - - var body authenticationv1.TokenReview - if err := json.NewDecoder(req.Body).Decode(&body); err != nil { - klog.InfoS("failed to decode body", "err", err) - rsp.WriteHeader(http.StatusBadRequest) - return - } - - tokenSegments := strings.SplitN(body.Spec.Token, ":", 2) - if len(tokenSegments) != 2 { - klog.InfoS("bad token format in request") - rsp.WriteHeader(http.StatusBadRequest) - return - } - username := tokenSegments[0] - password := tokenSegments[1] - secret, err := w.secretInformer.Lister().Secrets(namespace).Get(username) notFound := k8serrors.IsNotFound(err) if err != nil && !notFound { @@ -193,6 +157,50 @@ func (w *webhook) ServeHTTP(rsp http.ResponseWriter, req *http.Request) { respondWithAuthenticated(rsp, secret.ObjectMeta.Name, string(secret.UID), groups) } +func getUsernameAndPasswordFromRequest(rsp http.ResponseWriter, req *http.Request) (string, string, error) { + if req.URL.Path != "/authenticate" { + klog.InfoS("received request path other than /authenticate", "path", req.URL.Path) + rsp.WriteHeader(http.StatusNotFound) + return "", "", invalidRequest + } + + if req.Method != http.MethodPost { + klog.InfoS("received request method other than post", "method", req.Method) + rsp.WriteHeader(http.StatusMethodNotAllowed) + return "", "", invalidRequest + } + + if !headerContains(req, "Content-Type", "application/json") { + klog.InfoS("content type is not application/json", "Content-Type", req.Header.Values("Content-Type")) + rsp.WriteHeader(http.StatusUnsupportedMediaType) + return "", "", invalidRequest + } + + if !headerContains(req, "Accept", "application/json") && + !headerContains(req, "Accept", "application/*") && + !headerContains(req, "Accept", "*/*") { + klog.InfoS("client does not accept application/json", "Accept", req.Header.Values("Accept")) + rsp.WriteHeader(http.StatusUnsupportedMediaType) + return "", "", invalidRequest + } + + var body authenticationv1.TokenReview + if err := json.NewDecoder(req.Body).Decode(&body); err != nil { + klog.InfoS("failed to decode body", "err", err) + rsp.WriteHeader(http.StatusBadRequest) + return "", "", invalidRequest + } + + tokenSegments := strings.SplitN(body.Spec.Token, ":", 2) + if len(tokenSegments) != 2 { + klog.InfoS("bad token format in request") + rsp.WriteHeader(http.StatusBadRequest) + return "", "", invalidRequest + } + + return tokenSegments[0], tokenSegments[1], nil +} + func headerContains(req *http.Request, headerName, s string) bool { headerValues := req.Header.Values(headerName) for i := range headerValues { diff --git a/cmd/local-user-authenticator/main_test.go b/cmd/local-user-authenticator/main_test.go index 4ac44fa6..0bc49255 100644 --- a/cmd/local-user-authenticator/main_test.go +++ b/cmd/local-user-authenticator/main_test.go @@ -451,9 +451,9 @@ func unauthenticatedResponseJSON() *string { } func authenticatedResponseJSON(user, uid string, groups []string) *string { - var quotedGroups []string - for _, group := range groups { - quotedGroups = append(quotedGroups, `"`+group+`"`) + quotedGroups := make([]string, len(groups)) + for i, group := range groups { + quotedGroups[i] = `"` + group + `"` } // Very specific expected result. Avoid using json package so we know exactly what we're asserting. diff --git a/test/integration/credentialrequest_test.go b/test/integration/credentialrequest_test.go index e3e3ff50..cb9b0418 100644 --- a/test/integration/credentialrequest_test.go +++ b/test/integration/credentialrequest_test.go @@ -93,6 +93,7 @@ func TestSuccessfulCredentialRequest(t *testing.T) { }) for _, group := range expectedTestUserGroups { + group := group t.Run("access as group "+group, func(t *testing.T) { addTestClusterRoleBinding(ctx, t, adminClient, &rbacv1.ClusterRoleBinding{ TypeMeta: metav1.TypeMeta{},