File: auth.go

package info (click to toggle)
singularity-container 4.1.5%2Bds4-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 43,876 kB
  • sloc: asm: 14,840; sh: 3,190; ansic: 1,751; awk: 414; makefile: 413; python: 99
file content (130 lines) | stat: -rw-r--r-- 3,286 bytes parent folder | download | duplicates (3)
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package auth

import (
	"context"
	"crypto/rand"
	"crypto/subtle"
	"sync"

	"github.com/moby/buildkit/session"
	"github.com/moby/buildkit/util/grpcerrors"
	"github.com/pkg/errors"
	"golang.org/x/crypto/nacl/sign"
	"google.golang.org/grpc/codes"
)

var salt []byte
var saltOnce sync.Once

// getSalt returns unique component per daemon restart to avoid persistent keys
func getSalt() []byte {
	saltOnce.Do(func() {
		salt = make([]byte, 32)
		rand.Read(salt)
	})
	return salt
}

func CredentialsFunc(sm *session.Manager, g session.Group) func(string) (session, username, secret string, err error) {
	return func(host string) (string, string, string, error) {
		var sessionID, user, secret string
		err := sm.Any(context.TODO(), g, func(ctx context.Context, id string, c session.Caller) error {
			client := NewAuthClient(c.Conn())

			resp, err := client.Credentials(ctx, &CredentialsRequest{
				Host: host,
			})
			if err != nil {
				if grpcerrors.Code(err) == codes.Unimplemented {
					return nil
				}
				return err
			}
			sessionID = id
			user = resp.Username
			secret = resp.Secret
			return nil
		})
		if err != nil {
			return "", "", "", err
		}
		return sessionID, user, secret, nil
	}
}

func FetchToken(ctx context.Context, req *FetchTokenRequest, sm *session.Manager, g session.Group) (resp *FetchTokenResponse, err error) {
	err = sm.Any(ctx, g, func(ctx context.Context, id string, c session.Caller) error {
		client := NewAuthClient(c.Conn())

		resp, err = client.FetchToken(ctx, req)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func VerifyTokenAuthority(ctx context.Context, host string, pubKey *[32]byte, sm *session.Manager, g session.Group) (sessionID string, ok bool, err error) {
	var verified bool
	err = sm.Any(ctx, g, func(ctx context.Context, id string, c session.Caller) error {
		client := NewAuthClient(c.Conn())

		payload := make([]byte, 32)
		rand.Read(payload)
		resp, err := client.VerifyTokenAuthority(ctx, &VerifyTokenAuthorityRequest{
			Host:    host,
			Salt:    getSalt(),
			Payload: payload,
		})
		if err != nil {
			if grpcerrors.Code(err) == codes.Unimplemented {
				return nil
			}
			return err
		}
		var dt []byte
		dt, ok = sign.Open(nil, resp.Signed, pubKey)
		if ok && subtle.ConstantTimeCompare(dt, payload) == 1 {
			verified = true
		}
		sessionID = id
		return nil
	})
	if err != nil {
		return "", false, err
	}
	return sessionID, verified, nil
}

func GetTokenAuthority(ctx context.Context, host string, sm *session.Manager, g session.Group) (sessionID string, pubKey *[32]byte, err error) {
	err = sm.Any(ctx, g, func(ctx context.Context, id string, c session.Caller) error {
		client := NewAuthClient(c.Conn())

		resp, err := client.GetTokenAuthority(ctx, &GetTokenAuthorityRequest{
			Host: host,
			Salt: getSalt(),
		})
		if err != nil {
			if grpcerrors.Code(err) == codes.Unimplemented || grpcerrors.Code(err) == codes.Unavailable {
				return nil
			}
			return err
		}
		if len(resp.PublicKey) != 32 {
			return errors.Errorf("invalid pubkey length %d", len(pubKey))
		}

		sessionID = id
		pubKey = new([32]byte)
		copy((*pubKey)[:], resp.PublicKey)
		return nil
	})
	if err != nil {
		return "", nil, err
	}
	return sessionID, pubKey, nil
}