From 91099eb13e741790ae7eb12e12a96b363d1c14b2 Mon Sep 17 00:00:00 2001 From: Daniel Ponte Date: Mon, 29 Jul 2024 00:58:32 -0400 Subject: [PATCH] make auth an interface --- pkg/gordio/auth/apikey.go | 10 +++++++--- pkg/gordio/auth/auth.go | 11 ++++++++--- pkg/gordio/auth/jwt.go | 36 ++++++++++++++++++++++++------------ pkg/gordio/ingestors/http.go | 4 ++-- pkg/gordio/server/server.go | 2 +- 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/pkg/gordio/auth/apikey.go b/pkg/gordio/auth/apikey.go index 32daf1a..cf42066 100644 --- a/pkg/gordio/auth/apikey.go +++ b/pkg/gordio/auth/apikey.go @@ -10,9 +10,13 @@ import ( "github.com/rs/zerolog/log" ) -// CheckAPIKey validates the provided key and returns the API key record. -// An error is returned if validation fails for any reason. -func (a *Authenticator) CheckAPIKey(ctx context.Context, key string) (*database.ApiKey, error) { +type apiKeyAuth interface { + // CheckAPIKey validates the provided key and returns the API key record. + // An error is returned if validation fails for any reason. + CheckAPIKey(ctx context.Context, key string) (*database.ApiKey, error) +} + +func (a *authenticator) CheckAPIKey(ctx context.Context, key string) (*database.ApiKey, error) { keyUuid, err := uuid.Parse(key) if err != nil { log.Error().Str("apikey", key).Msg("cannot parse key") diff --git a/pkg/gordio/auth/auth.go b/pkg/gordio/auth/auth.go index 27f42ef..c26db91 100644 --- a/pkg/gordio/auth/auth.go +++ b/pkg/gordio/auth/auth.go @@ -8,14 +8,19 @@ import ( ) // Authenticator performs API key and user JWT authentication. -type Authenticator struct { +type Authenticator interface { + jwtAuth + apiKeyAuth +} + +type authenticator struct { domain string jwt *jwtauth.JWTAuth } // NewAuthenticator creates a new Authenticator with the provided JWT secret and cookie domain. -func NewAuthenticator(jwtSecret string, domain string) *Authenticator { - return &Authenticator{ +func NewAuthenticator(jwtSecret string, domain string) Authenticator { + return &authenticator{ domain: domain, jwt: jwtauth.New("HS256", []byte(jwtSecret), nil), } diff --git a/pkg/gordio/auth/jwt.go b/pkg/gordio/auth/jwt.go index 4c6925a..65ac83e 100644 --- a/pkg/gordio/auth/jwt.go +++ b/pkg/gordio/auth/jwt.go @@ -15,27 +15,40 @@ import ( "github.com/rs/zerolog/log" ) +type jwtAuth interface { + // Authenticated returns whether the request is authenticated. It also returns the claims. + Authenticated(r *http.Request) (claims, bool) + + // Login attempts to return a JWT for the provided user and password. + Login(ctx context.Context, username, password string) (token string, err error) + + // InstallVerifyMiddleware installs the JWT verifier middleware to the provided chi Router. + InstallVerifyMiddleware(r chi.Router) + + // InstallAuthMiddleware installs the JWT authenticator middleware to the provided chi Router. + InstallAuthMiddleware(r chi.Router) + + // InstallRoutes installs the auth route to the provided chi Router. + InstallRoutes(r chi.Router) +} + type claims map[string]interface{} -// Authenticated returns whether the request is authenticated. It also returns the claims. -func (a *Authenticator) Authenticated(r *http.Request) (claims, bool) { +func (a *authenticator) Authenticated(r *http.Request) (claims, bool) { // TODO: check IP against ACL, or conf.Public, and against map of routes tok, cl, err := jwtauth.FromContext(r.Context()) return cl, err != nil && tok != nil } -// InstallVerifyMiddleware installs the JWT verifier middleware to the provided chi Router. -func (a *Authenticator) InstallVerifyMiddleware(r chi.Router) { +func (a *authenticator) InstallVerifyMiddleware(r chi.Router) { r.Use(jwtauth.Verifier(a.jwt)) } -// InstallVerifyMiddleware installs the JWT authenticator middleware to the provided chi Router. -func (a *Authenticator) InstallAuthMiddleware(r chi.Router) { +func (a *authenticator) InstallAuthMiddleware(r chi.Router) { r.Use(jwtauth.Authenticator(a.jwt)) } -// Login attempts to return a JWT for the provided user and password. -func (a *Authenticator) Login(ctx context.Context, username, password string) (token string, err error) { +func (a *authenticator) Login(ctx context.Context, username, password string) (token string, err error) { q := database.New(database.FromCtx(ctx)) users, err := q.GetUsers(ctx) if err != nil { @@ -64,7 +77,7 @@ func (a *Authenticator) Login(ctx context.Context, username, password string) (t return a.newToken(found.ID), nil } -func (a *Authenticator) newToken(uid int32) string { +func (a *authenticator) newToken(uid int32) string { claims := claims{ "user_id": uid, } @@ -76,12 +89,11 @@ func (a *Authenticator) newToken(uid int32) string { return tokenString } -// InstallRoutes installs the auth route to the provided chi Router. -func (a *Authenticator) InstallRoutes(r chi.Router) { +func (a *authenticator) InstallRoutes(r chi.Router) { r.Post("/auth", a.routeAuth) } -func (a *Authenticator) routeAuth(w http.ResponseWriter, r *http.Request) { +func (a *authenticator) routeAuth(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) diff --git a/pkg/gordio/ingestors/http.go b/pkg/gordio/ingestors/http.go index 9bdd39f..f3c158a 100644 --- a/pkg/gordio/ingestors/http.go +++ b/pkg/gordio/ingestors/http.go @@ -18,11 +18,11 @@ import ( // HTTPIngestor is an ingestor that accepts calls over HTTP. type HTTPIngestor struct { - auth *auth.Authenticator + auth auth.Authenticator } // NewHTTPIngestor creates a new HTTPIngestor. It requires an Authenticator. -func NewHTTPIngestor(auth *auth.Authenticator) *HTTPIngestor { +func NewHTTPIngestor(auth auth.Authenticator) *HTTPIngestor { return &HTTPIngestor{ auth: auth, } diff --git a/pkg/gordio/server/server.go b/pkg/gordio/server/server.go index b8a797f..75008bd 100644 --- a/pkg/gordio/server/server.go +++ b/pkg/gordio/server/server.go @@ -12,7 +12,7 @@ import ( ) type Server struct { - auth *auth.Authenticator + auth auth.Authenticator conf *config.Config db *database.DB r *chi.Mux