github.com/buildtool/build-tools@v0.2.29-0.20240322150259-6a1d0a553c23/pkg/docker/auth.go (about) 1 // MIT License 2 // 3 // Copyright (c) 2018 buildtool 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 // SOFTWARE. 22 23 package docker 24 25 import ( 26 "context" 27 "crypto/ed25519" 28 "crypto/hmac" 29 "crypto/sha256" 30 "fmt" 31 "net/http" 32 "time" 33 34 authutil "github.com/containerd/containerd/remotes/docker/auth" 35 36 "github.com/docker/docker/api/types/registry" 37 "github.com/moby/buildkit/session" 38 "github.com/moby/buildkit/session/auth" 39 "golang.org/x/crypto/nacl/sign" 40 "google.golang.org/grpc" 41 ) 42 43 type authenticator struct { 44 authConfig registry.AuthConfig 45 registryHost string 46 } 47 48 func NewAuthenticator(registryHost string, authConfig registry.AuthConfig) Authenticator { 49 return &authenticator{ 50 authConfig: authConfig, 51 registryHost: registryHost, 52 } 53 } 54 55 func (a *authenticator) Register(server *grpc.Server) { 56 auth.RegisterAuthServer(server, a) 57 } 58 59 func (a authenticator) Credentials(ctx context.Context, req *auth.CredentialsRequest) (*auth.CredentialsResponse, error) { 60 if req.Host != a.registryHost { 61 return &auth.CredentialsResponse{}, nil 62 } 63 return &auth.CredentialsResponse{Username: a.authConfig.Username, Secret: a.authConfig.Password}, nil 64 } 65 66 func (a authenticator) FetchToken(ctx context.Context, req *auth.FetchTokenRequest) (*auth.FetchTokenResponse, error) { 67 to := authutil.TokenOptions{ 68 Realm: req.Realm, 69 Service: req.Service, 70 Scopes: req.Scopes, 71 Username: "", 72 Secret: "", 73 } 74 // do request anonymously 75 resp, err := authutil.FetchToken(ctx, http.DefaultClient, nil, to) 76 if err != nil { 77 // try with auth 78 to.Username = a.authConfig.Username 79 to.Secret = a.authConfig.Password 80 resp, err = authutil.FetchToken(ctx, http.DefaultClient, nil, to) 81 if err != nil { 82 return nil, fmt.Errorf("failed to fetch anonymous and authenticated token, %w", err) 83 } 84 } 85 return toTokenResponse(resp.Token, resp.IssuedAt, resp.ExpiresIn), nil 86 } 87 88 func (ap *authenticator) GetTokenAuthority(ctx context.Context, req *auth.GetTokenAuthorityRequest) (*auth.GetTokenAuthorityResponse, error) { 89 key := ap.getAuthorityKey(req.Host, req.Salt) 90 91 return &auth.GetTokenAuthorityResponse{PublicKey: key[32:]}, nil 92 } 93 94 func (ap *authenticator) VerifyTokenAuthority(ctx context.Context, req *auth.VerifyTokenAuthorityRequest) (*auth.VerifyTokenAuthorityResponse, error) { 95 key := ap.getAuthorityKey(req.Host, req.Salt) 96 97 priv := new([64]byte) 98 copy((*priv)[:], key) 99 100 return &auth.VerifyTokenAuthorityResponse{Signed: sign.Sign(nil, req.Payload, priv)}, nil 101 } 102 103 var _ Authenticator = &authenticator{} 104 105 type Authenticator interface { 106 auth.AuthServer 107 session.Attachable 108 } 109 110 func toTokenResponse(token string, issuedAt time.Time, expires int) *auth.FetchTokenResponse { 111 resp := &auth.FetchTokenResponse{ 112 Token: token, 113 ExpiresIn: int64(expires), 114 } 115 if !issuedAt.IsZero() { 116 resp.IssuedAt = issuedAt.Unix() 117 } 118 return resp 119 } 120 121 func (ap *authenticator) getAuthorityKey(host string, salt []byte) ed25519.PrivateKey { 122 mac := hmac.New(sha256.New, salt) 123 sum := mac.Sum(nil) 124 125 return ed25519.NewKeyFromSeed(sum[:ed25519.SeedSize]) 126 }