/
auth_tls.go
65 lines (54 loc) · 1.98 KB
/
auth_tls.go
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
59
60
61
62
63
64
65
package auth
import (
"context"
"crypto/x509"
"fmt"
"sync"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/peer"
"google.golang.org/grpc/status"
"github.com/oasisprotocol/oasis-core/go/common/accessctl"
)
// PeerCertAuthenticator is a server side gRPC authentication function
// that restricts access to all methods based on the hash of the DER
// representation of the client certificate presented in the TLS handshake.
type PeerCertAuthenticator struct {
sync.RWMutex
whitelist map[accessctl.Subject]bool
}
// AuthFunc is an AuthenticationFunction backed by the PeerCertAuthenticator.
func (auth *PeerCertAuthenticator) AuthFunc(ctx context.Context, fullMethodName string, req interface{}) error {
peer, ok := peer.FromContext(ctx)
if !ok {
return status.Errorf(codes.PermissionDenied, "grpc: failed to obtain connection peer from context")
}
tlsAuth, ok := peer.AuthInfo.(credentials.TLSInfo)
if !ok {
return status.Errorf(codes.PermissionDenied, "grpc: unexpected peer authentication credentials")
}
if nPeerCerts := len(tlsAuth.State.PeerCertificates); nPeerCerts != 1 {
return status.Errorf(codes.PermissionDenied, fmt.Sprintf("grpc: unexpected number of peer certificates: %d", nPeerCerts))
}
peerCert := tlsAuth.State.PeerCertificates[0]
subject := accessctl.SubjectFromX509Certificate(peerCert)
auth.RLock()
defer auth.RUnlock()
if !auth.whitelist[subject] {
return status.Errorf(codes.PermissionDenied, "grpc: unknown peer certificate")
}
return nil
}
// AllowPeerCertificate allows a peer certificate access.
func (auth *PeerCertAuthenticator) AllowPeerCertificate(cert *x509.Certificate) {
subject := accessctl.SubjectFromX509Certificate(cert)
auth.Lock()
defer auth.Unlock()
auth.whitelist[subject] = true
}
// NewPeerCertAuthenticator creates a new (empty) PeerCertAuthenticator.
func NewPeerCertAuthenticator() *PeerCertAuthenticator {
return &PeerCertAuthenticator{
whitelist: make(map[accessctl.Subject]bool),
}
}