summaryrefslogtreecommitdiff
path: root/contrib/tlsauth/gemini.go
blob: 40bee9e784005327531a334ae0e8c5a462c32224 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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 gus.HandlerFunc(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.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) gus.Middleware {
	return func(inner gus.Handler) gus.Handler {
		return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
			identity := Identity(request)
			if identity != nil && !approver(identity) {
				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, _ *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.")
}