diff --git a/README.md b/README.md index c5bd138..2711af6 100644 --- a/README.md +++ b/README.md @@ -107,11 +107,11 @@ Each JSON configuration file for the gateways can specify detailed settings for ``` ## Authentication -Basic authentication can be enabled using the `--auth` flag. The username and password should be set through environment variables `GATEWAY_USERNAME` and `GATEWAY_PASSWORD`, respectively. +Authentication can be enabled using the `--auth` flag. The auth token should be set through environment variables `GATEWAY_PASSWORD`. ### Running the Application To run the application with authentication: ``` -DEBUG=true GATEWAY_USERNAME=myuser GATEWAY_PASSWORD=mypass go run . --config config.json --auth +DEBUG=true GATEWAY_PASSWORD=my_auth_token go run . --config config.json --auth ``` diff --git a/internal/auth/auth.go b/internal/auth/auth.go new file mode 100644 index 0000000..ff13218 --- /dev/null +++ b/internal/auth/auth.go @@ -0,0 +1,19 @@ +package auth + +import ( + "net/http" +) + +func URLTokenAuth(token string) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authToken := r.URL.Query().Get("auth_token") + if authToken == "" || authToken != token { + w.WriteHeader(http.StatusUnauthorized) + + return + } + next.ServeHTTP(w, r) + }) + } +} diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go new file mode 100644 index 0000000..1952e0c --- /dev/null +++ b/internal/auth/auth_test.go @@ -0,0 +1,54 @@ +package auth + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func TestUrlTokenAuth(t *testing.T) { + validToken := "valid_token" + middleware := URLTokenAuth(validToken) + + tests := []struct { + name string + url string + expectedStatus int + }{ + { + name: "Valid token", + url: "/?auth_token=valid_token", + expectedStatus: http.StatusOK, + }, + { + name: "Invalid token", + url: "/?auth_token=invalid_token", + expectedStatus: http.StatusUnauthorized, + }, + { + name: "Missing token", + url: "/", + expectedStatus: http.StatusUnauthorized, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req, err := http.NewRequest("GET", tt.url, nil) + if err != nil { + t.Fatalf("could not create request: %v", err) + } + + rr := httptest.NewRecorder() + handler := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + handler.ServeHTTP(rr, req) + + if rr.Code != tt.expectedStatus { + t.Errorf("expected status %v; got %v", tt.expectedStatus, rr.Code) + } + }) + } +} diff --git a/main.go b/main.go index ae3541f..725c6b2 100644 --- a/main.go +++ b/main.go @@ -15,6 +15,7 @@ import ( "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/httplog/v2" + "github.com/sygmaprotocol/rpc-gateway/internal/auth" "github.com/sygmaprotocol/rpc-gateway/internal/metrics" "github.com/sygmaprotocol/rpc-gateway/internal/util" @@ -80,14 +81,12 @@ func main() { r.Use(middleware.Heartbeat("/health")) // Add basic auth middleware if cc.Bool("auth") { - username := os.Getenv("GATEWAY_USERNAME") - password := os.Getenv("GATEWAY_PASSWORD") - if username == "" || password == "" { - return errors.New("both GATEWAY_USERNAME and GATEWAY_PASSWORD environment variables must be set for basic authentication") + authToken := os.Getenv("GATEWAY_PASSWORD") + if authToken == "" { + return errors.New("GATEWAY_PASSWORD environment variables must be set for basic authentication") } - r.Use(middleware.BasicAuth("API Realm", map[string]string{ - username: password, - })) + r.Use(auth.URLTokenAuth(authToken)) + fmt.Println("Authentication configured on gateway") } server := &http.Server{