From 7aec1fb513187599d54171eb0c9f3198b1555ea0 Mon Sep 17 00:00:00 2001 From: Fabian Vowie Date: Thu, 20 Jan 2022 21:09:19 +0100 Subject: [PATCH 1/4] Add token-based authorization middleware --- auth/authorization.go | 19 +++++++++++++++ auth/authorization_test.go | 50 ++++++++++++++++++++++++++++++++++++++ main.go | 6 +++++ 3 files changed, 75 insertions(+) create mode 100644 auth/authorization.go create mode 100644 auth/authorization_test.go diff --git a/auth/authorization.go b/auth/authorization.go new file mode 100644 index 0000000..5e058eb --- /dev/null +++ b/auth/authorization.go @@ -0,0 +1,19 @@ +package auth + +import "net/http" + +type AuthenticationMiddleware struct { + Secret string +} + +func (middleware AuthenticationMiddleware) Middleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authToken := r.Header.Get("Authorization") + + if authToken == "" || authToken != middleware.Secret { + http.Error(w, "Forbidden", http.StatusForbidden) + } else { + next.ServeHTTP(w, r) + } + }) +} diff --git a/auth/authorization_test.go b/auth/authorization_test.go new file mode 100644 index 0000000..a8fc6c8 --- /dev/null +++ b/auth/authorization_test.go @@ -0,0 +1,50 @@ +package auth + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAuthorizationMiddleware(t *testing.T) { + t.Run("AuthorizationMiddleware returns 403 response when authorization header is incorrect", func(t *testing.T) { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + middleware := AuthenticationMiddleware{ + Secret: "foo", + } + + middlewareHandler := middleware.Middleware(handler) + + request, _ := http.NewRequest("GET", "/", nil) + responseRecorder := httptest.NewRecorder() + + middlewareHandler.ServeHTTP(responseRecorder, request) + + assert.Equal(t, responseRecorder.Code, 403) + }) + + t.Run("AuthorizationMiddleware continues when authorization header is correct", func(t *testing.T) { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + middleware := AuthenticationMiddleware{ + Secret: "foo", + } + + middlewareHandler := middleware.Middleware(handler) + + request, _ := http.NewRequest("GET", "/", nil) + request.Header.Set("Authorization", "foo") + responseRecorder := httptest.NewRecorder() + + middlewareHandler.ServeHTTP(responseRecorder, request) + + assert.Equal(t, responseRecorder.Code, 200) + }) +} diff --git a/main.go b/main.go index 1afeb91..cb25943 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" + "github.com/geplauder/lithium/auth" "github.com/geplauder/lithium/pipelines" "github.com/geplauder/lithium/settings" "github.com/geplauder/lithium/storage" @@ -56,7 +57,12 @@ func main() { pipes := pipelines.LoadPipelines() + authMiddleware := auth.AuthenticationMiddleware{ + Secret: settings.Token, + } + r := mux.NewRouter() + r.Use(authMiddleware.Middleware) r.HandleFunc("/", IndexHandler) RegisterPipelineRoutes(r, pipes, storageProvider) From a0370a78ece12988a1c161d08950ae0a67a965f6 Mon Sep 17 00:00:00 2001 From: Fabian Vowie Date: Thu, 20 Jan 2022 21:11:09 +0100 Subject: [PATCH 2/4] Fix assertion usage and use randomly generated token in auth middleware tests --- auth/authorization_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/auth/authorization_test.go b/auth/authorization_test.go index a8fc6c8..7f8d45e 100644 --- a/auth/authorization_test.go +++ b/auth/authorization_test.go @@ -5,17 +5,20 @@ import ( "net/http/httptest" "testing" + "github.com/bxcodec/faker/v3" "github.com/stretchr/testify/assert" ) func TestAuthorizationMiddleware(t *testing.T) { + token := faker.Word() + t.Run("AuthorizationMiddleware returns 403 response when authorization header is incorrect", func(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) middleware := AuthenticationMiddleware{ - Secret: "foo", + Secret: token, } middlewareHandler := middleware.Middleware(handler) @@ -25,7 +28,7 @@ func TestAuthorizationMiddleware(t *testing.T) { middlewareHandler.ServeHTTP(responseRecorder, request) - assert.Equal(t, responseRecorder.Code, 403) + assert.Equal(t, 403, responseRecorder.Code) }) t.Run("AuthorizationMiddleware continues when authorization header is correct", func(t *testing.T) { @@ -34,17 +37,17 @@ func TestAuthorizationMiddleware(t *testing.T) { }) middleware := AuthenticationMiddleware{ - Secret: "foo", + Secret: token, } middlewareHandler := middleware.Middleware(handler) request, _ := http.NewRequest("GET", "/", nil) - request.Header.Set("Authorization", "foo") + request.Header.Set("Authorization", token) responseRecorder := httptest.NewRecorder() middlewareHandler.ServeHTTP(responseRecorder, request) - assert.Equal(t, responseRecorder.Code, 200) + assert.Equal(t, 200, responseRecorder.Code) }) } From 5bbae63e6c96d40c2d929546ca4e108de7bf53a4 Mon Sep 17 00:00:00 2001 From: Fabian Vowie Date: Thu, 20 Jan 2022 21:22:06 +0100 Subject: [PATCH 3/4] Require 'Bearer' prefix in authorization header --- auth/authorization.go | 7 +++++-- auth/authorization_test.go | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/auth/authorization.go b/auth/authorization.go index 5e058eb..42f955f 100644 --- a/auth/authorization.go +++ b/auth/authorization.go @@ -1,6 +1,9 @@ package auth -import "net/http" +import ( + "net/http" + "strings" +) type AuthenticationMiddleware struct { Secret string @@ -10,7 +13,7 @@ func (middleware AuthenticationMiddleware) Middleware(next http.Handler) http.Ha return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authToken := r.Header.Get("Authorization") - if authToken == "" || authToken != middleware.Secret { + if authToken == "" || strings.HasPrefix(authToken, "Bearer ") == false || authToken[7:] != middleware.Secret { http.Error(w, "Forbidden", http.StatusForbidden) } else { next.ServeHTTP(w, r) diff --git a/auth/authorization_test.go b/auth/authorization_test.go index 7f8d45e..0aa737e 100644 --- a/auth/authorization_test.go +++ b/auth/authorization_test.go @@ -43,7 +43,7 @@ func TestAuthorizationMiddleware(t *testing.T) { middlewareHandler := middleware.Middleware(handler) request, _ := http.NewRequest("GET", "/", nil) - request.Header.Set("Authorization", token) + request.Header.Set("Authorization", "Bearer "+token) responseRecorder := httptest.NewRecorder() middlewareHandler.ServeHTTP(responseRecorder, request) From 6ac87dc7dcdf4d3be4a40f7ab19b46ffc1a8cf2f Mon Sep 17 00:00:00 2001 From: Fabian Vowie Date: Thu, 20 Jan 2022 21:27:47 +0100 Subject: [PATCH 4/4] Add builder function to create AuthenticationMiddleware objects --- auth/authorization.go | 10 ++++++++-- auth/authorization_test.go | 25 ++++++------------------- main.go | 4 +--- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/auth/authorization.go b/auth/authorization.go index 42f955f..5048228 100644 --- a/auth/authorization.go +++ b/auth/authorization.go @@ -6,17 +6,23 @@ import ( ) type AuthenticationMiddleware struct { - Secret string + secret string } func (middleware AuthenticationMiddleware) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authToken := r.Header.Get("Authorization") - if authToken == "" || strings.HasPrefix(authToken, "Bearer ") == false || authToken[7:] != middleware.Secret { + if authToken == "" || strings.HasPrefix(authToken, "Bearer ") == false || authToken[7:] != middleware.secret { http.Error(w, "Forbidden", http.StatusForbidden) } else { next.ServeHTTP(w, r) } }) } + +func CreateAuthenticationMiddleware(secret string) AuthenticationMiddleware { + return AuthenticationMiddleware{ + secret: secret, + } +} diff --git a/auth/authorization_test.go b/auth/authorization_test.go index 0aa737e..139f416 100644 --- a/auth/authorization_test.go +++ b/auth/authorization_test.go @@ -11,18 +11,15 @@ import ( func TestAuthorizationMiddleware(t *testing.T) { token := faker.Word() + middleware := CreateAuthenticationMiddleware(token) - t.Run("AuthorizationMiddleware returns 403 response when authorization header is incorrect", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - }) - - middleware := AuthenticationMiddleware{ - Secret: token, - } + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) - middlewareHandler := middleware.Middleware(handler) + middlewareHandler := middleware.Middleware(handler) + t.Run("AuthorizationMiddleware returns 403 response when authorization header is incorrect", func(t *testing.T) { request, _ := http.NewRequest("GET", "/", nil) responseRecorder := httptest.NewRecorder() @@ -32,16 +29,6 @@ func TestAuthorizationMiddleware(t *testing.T) { }) t.Run("AuthorizationMiddleware continues when authorization header is correct", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - }) - - middleware := AuthenticationMiddleware{ - Secret: token, - } - - middlewareHandler := middleware.Middleware(handler) - request, _ := http.NewRequest("GET", "/", nil) request.Header.Set("Authorization", "Bearer "+token) responseRecorder := httptest.NewRecorder() diff --git a/main.go b/main.go index cb25943..79145dc 100644 --- a/main.go +++ b/main.go @@ -57,9 +57,7 @@ func main() { pipes := pipelines.LoadPipelines() - authMiddleware := auth.AuthenticationMiddleware{ - Secret: settings.Token, - } + authMiddleware := auth.CreateAuthenticationMiddleware(settings.Token) r := mux.NewRouter() r.Use(authMiddleware.Middleware)