2021-05-26 01:30:49 +02:00
|
|
|
package solver
|
2021-04-27 02:39:19 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-01-19 01:37:45 +01:00
|
|
|
"fmt"
|
2021-04-27 02:39:19 +02:00
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
bkauth "github.com/moby/buildkit/session/auth"
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
|
|
|
)
|
|
|
|
|
2022-01-19 01:37:45 +01:00
|
|
|
const defaultDockerDomain = "docker.io"
|
|
|
|
|
2021-05-26 01:30:49 +02:00
|
|
|
// RegistryAuthProvider is a buildkit provider for registry authentication
|
2021-04-27 02:39:19 +02:00
|
|
|
// Adapted from: https://github.com/moby/buildkit/blob/master/session/auth/authprovider/authprovider.go
|
2021-05-26 01:30:49 +02:00
|
|
|
type RegistryAuthProvider struct {
|
2021-04-27 02:39:19 +02:00
|
|
|
credentials map[string]*bkauth.CredentialsResponse
|
|
|
|
m sync.RWMutex
|
|
|
|
}
|
|
|
|
|
2021-05-26 01:30:49 +02:00
|
|
|
func NewRegistryAuthProvider() *RegistryAuthProvider {
|
|
|
|
return &RegistryAuthProvider{
|
2021-04-27 02:39:19 +02:00
|
|
|
credentials: map[string]*bkauth.CredentialsResponse{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-26 01:30:49 +02:00
|
|
|
func (a *RegistryAuthProvider) AddCredentials(target, username, secret string) {
|
2021-04-27 02:39:19 +02:00
|
|
|
a.m.Lock()
|
|
|
|
defer a.m.Unlock()
|
|
|
|
|
|
|
|
a.credentials[target] = &bkauth.CredentialsResponse{
|
|
|
|
Username: username,
|
|
|
|
Secret: secret,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-26 01:30:49 +02:00
|
|
|
func (a *RegistryAuthProvider) Register(server *grpc.Server) {
|
2021-04-27 02:39:19 +02:00
|
|
|
bkauth.RegisterAuthServer(server, a)
|
|
|
|
}
|
|
|
|
|
2021-05-26 01:30:49 +02:00
|
|
|
func (a *RegistryAuthProvider) Credentials(ctx context.Context, req *bkauth.CredentialsRequest) (*bkauth.CredentialsResponse, error) {
|
2021-07-01 14:08:49 +02:00
|
|
|
host := req.Host
|
|
|
|
if host == "registry-1.docker.io" {
|
2022-01-19 01:37:45 +01:00
|
|
|
host = defaultDockerDomain
|
2021-04-27 02:39:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
a.m.RLock()
|
|
|
|
defer a.m.RUnlock()
|
|
|
|
|
|
|
|
for authHost, auth := range a.credentials {
|
2022-01-31 16:05:58 +01:00
|
|
|
u, err := ParseAuthHost(authHost)
|
2021-04-27 02:39:19 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-07-01 14:08:49 +02:00
|
|
|
if u == host {
|
2021-04-27 02:39:19 +02:00
|
|
|
return auth, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &bkauth.CredentialsResponse{}, nil
|
|
|
|
}
|
|
|
|
|
2022-01-19 01:37:45 +01:00
|
|
|
// Parsing function based on splitReposSearchTerm
|
|
|
|
// "github.com/docker/docker/registry"
|
2022-01-31 16:05:58 +01:00
|
|
|
func ParseAuthHost(host string) (string, error) {
|
2021-06-30 18:27:26 +02:00
|
|
|
host = strings.TrimPrefix(host, "http://")
|
|
|
|
host = strings.TrimPrefix(host, "https://")
|
2022-01-19 01:37:45 +01:00
|
|
|
host = strings.TrimSuffix(host, "/")
|
2021-06-18 22:01:16 +02:00
|
|
|
|
2022-01-19 01:37:45 +01:00
|
|
|
// Remove everything after @
|
|
|
|
nameParts := strings.SplitN(host, "@", 2)
|
|
|
|
host = nameParts[0]
|
|
|
|
|
|
|
|
// if ":" > 1, trim after last ":" found
|
|
|
|
if strings.Count(host, ":") > 1 {
|
|
|
|
host = host[:strings.LastIndex(host, ":")]
|
|
|
|
}
|
|
|
|
|
|
|
|
// if ":" > 0, trim after last ":" found if it contains "."
|
|
|
|
// ex: samalba/hipache:1.15, registry.com:5000:1.0
|
|
|
|
if strings.Count(host, ":") > 0 {
|
|
|
|
tmpStr := host[strings.LastIndex(host, ":"):]
|
|
|
|
if strings.Count(tmpStr, ".") > 0 {
|
|
|
|
host = host[:strings.LastIndex(host, ":")]
|
|
|
|
}
|
|
|
|
}
|
2021-04-27 02:39:19 +02:00
|
|
|
|
2022-01-19 01:37:45 +01:00
|
|
|
nameParts = strings.SplitN(host, "/", 2)
|
|
|
|
var domain string
|
|
|
|
switch {
|
|
|
|
// Localhost registry parsing
|
|
|
|
case strings.Contains(nameParts[0], "localhost"):
|
|
|
|
domain = nameParts[0]
|
|
|
|
// If the split returned an array of len 1 that doesn't contain any .
|
|
|
|
// ex: ubuntu
|
|
|
|
case len(nameParts) == 1 && !strings.Contains(nameParts[0], "."):
|
|
|
|
domain = defaultDockerDomain
|
|
|
|
// if the split does not contain "." nor ":", but contains images
|
|
|
|
// ex: samalba/hipache, samalba/hipache:1.15, samalba/hipache@sha:...
|
|
|
|
case !strings.Contains(nameParts[0], ".") && !strings.Contains(nameParts[0], ":"):
|
|
|
|
domain = defaultDockerDomain
|
|
|
|
case nameParts[0] == "registry-1.docker.io":
|
|
|
|
domain = defaultDockerDomain
|
|
|
|
case nameParts[0] == "index.docker.io":
|
|
|
|
domain = defaultDockerDomain
|
|
|
|
// Private remaining registry parsing
|
|
|
|
case strings.Contains(nameParts[0], "."):
|
|
|
|
domain = nameParts[0]
|
|
|
|
// Fail by default
|
|
|
|
default:
|
|
|
|
return "", fmt.Errorf("failed parsing [%s] expected host format: [%s]", nameParts[0], "registrydomain.extension")
|
2021-04-27 02:39:19 +02:00
|
|
|
}
|
2022-01-19 01:37:45 +01:00
|
|
|
return domain, nil
|
2021-04-27 02:39:19 +02:00
|
|
|
}
|
|
|
|
|
2021-05-26 01:30:49 +02:00
|
|
|
func (a *RegistryAuthProvider) FetchToken(ctx context.Context, req *bkauth.FetchTokenRequest) (rr *bkauth.FetchTokenResponse, err error) {
|
2021-04-27 02:39:19 +02:00
|
|
|
return nil, status.Errorf(codes.Unavailable, "client side tokens not implemented")
|
|
|
|
}
|
|
|
|
|
2021-05-26 01:30:49 +02:00
|
|
|
func (a *RegistryAuthProvider) GetTokenAuthority(ctx context.Context, req *bkauth.GetTokenAuthorityRequest) (*bkauth.GetTokenAuthorityResponse, error) {
|
2021-04-27 02:39:19 +02:00
|
|
|
return nil, status.Errorf(codes.Unavailable, "client side tokens not implemented")
|
|
|
|
}
|
|
|
|
|
2021-05-26 01:30:49 +02:00
|
|
|
func (a *RegistryAuthProvider) VerifyTokenAuthority(ctx context.Context, req *bkauth.VerifyTokenAuthorityRequest) (*bkauth.VerifyTokenAuthorityResponse, error) {
|
2021-04-27 02:39:19 +02:00
|
|
|
return nil, status.Errorf(codes.Unavailable, "client side tokens not implemented")
|
|
|
|
}
|