summaryrefslogtreecommitdiff
path: root/contrib/tlsauth/gemini.go
diff options
context:
space:
mode:
authortjpcc <tjp@ctrl-c.club>2023-01-20 10:58:35 -0700
committertjpcc <tjp@ctrl-c.club>2023-01-20 10:58:35 -0700
commit8229f31f70ecdbe03d03c96cba17d6ee85397bca (patch)
tree5c51a1bdd9366a69fd1cf03dcdd1c41e49bcb6e2 /contrib/tlsauth/gemini.go
parenta1c186878d228bada894a6fd580bfc4eb9da2ffa (diff)
"tlsauth" contrib package
This package adds authentication middlewares via TLS client certificates.
Diffstat (limited to 'contrib/tlsauth/gemini.go')
-rw-r--r--contrib/tlsauth/gemini.go58
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.")
+}