diff options
Diffstat (limited to 'contrib/tlsauth/gemini.go')
-rw-r--r-- | contrib/tlsauth/gemini.go | 58 |
1 files changed, 58 insertions, 0 deletions
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.") +} |