package tlsauth import ( "context" sr "tildegit.org/tjp/sliderule" "tildegit.org/tjp/sliderule/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) sr.Middleware { return func(inner sr.Handler) sr.Handler { return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response { if Identity(request) == nil { return geminiMissingCert(ctx, request) } if !approver(ctx, request) { return geminiCertNotAuthorized(ctx, request) } return inner.Handle(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) sr.Middleware { return func(inner sr.Handler) sr.Handler { return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response { if Identity(request) != nil && !approver(ctx, request) { return geminiCertNotAuthorized(ctx, request) } return inner.Handle(ctx, request) }) } } // GeminiRequireCertificate is a middleware that only requires a client certificate. var GeminiRequireCertificate = GeminiAuth(Allow) func geminiMissingCert(_ context.Context, _ *sr.Request) *sr.Response { return gemini.RequireCert("A client certificate is required.") } func geminiCertNotAuthorized(_ context.Context, _ *sr.Request) *sr.Response { return gemini.CertAuthFailure("Client certificate not authorized.") }