From 8229f31f70ecdbe03d03c96cba17d6ee85397bca Mon Sep 17 00:00:00 2001 From: tjpcc Date: Fri, 20 Jan 2023 10:58:35 -0700 Subject: "tlsauth" contrib package This package adds authentication middlewares via TLS client certificates. --- contrib/tlsauth/gemini.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 contrib/tlsauth/gemini.go (limited to 'contrib/tlsauth/gemini.go') diff --git a/contrib/tlsauth/gemini.go b/contrib/tlsauth/gemini.go new file mode 100644 index 0000000..0db89de --- /dev/null +++ b/contrib/tlsauth/gemini.go @@ -0,0 +1,58 @@ +package tlsauth + +import ( + "context" + + "tildegit.org/tjp/gus" + "tildegit.org/tjp/gus/gemini" +) + +// GeminiAuth builds an authentication middleware from approval criteria. +// +// If a request does not contain a client certificate it will be rejected +// with a "60 certificate required" response. If the client identity does +// not pass the approver it will be rejected with "62 certificate invalid". +func GeminiAuth(approver Approver) gus.Middleware { + return func(inner gus.Handler) gus.Handler { + return func(ctx context.Context, request *gus.Request) *gus.Response { + identity := Identity(request) + if identity == nil { + return geminiMissingCert(ctx, request) + } + if !approver(identity) { + return geminiCertNotAuthorized(ctx, request) + } + + return inner(ctx, request) + } + } +} + +// GeminiOptionalAuth builds auth middleware which doesn't require an identity. +// +// If there is no client certificate the request will pass through the middleware. +// It will only be rejected with "62 certificate invalid" if there *is* a client +// certificate, but it fails the approval. +func GeminiOptionalAuth(approver Approver) gus.Middleware { + return func(inner gus.Handler) gus.Handler { + return func(ctx context.Context, request *gus.Request) *gus.Response { + identity := Identity(request) + if identity != nil && !approver(identity) { + return geminiCertNotAuthorized(ctx, request) + } + + return inner(ctx, request) + } + } +} + +// GeminiRequireCertificate is a middleware that only requires a client certificate. +var GeminiRequireCertificate = GeminiAuth(Allow) + +func geminiMissingCert(_ context.Context, _ *gus.Request) *gus.Response { + return gemini.RequireCert("A client certificate is required.") +} + +func geminiCertNotAuthorized(_ context.Context, _ *gus.Request) *gus.Response { + return gemini.CertAuthFailure("Client certificate not authorized.") +} -- cgit v1.2.3