Add user support to git2go implementation

Signed-off-by: Philip Laine <philip.laine@gmail.com>
This commit is contained in:
Philip Laine 2020-11-30 21:37:26 +01:00
parent 934f5df668
commit 5ff65d7ae7
6 changed files with 51 additions and 27 deletions

View File

@ -182,8 +182,12 @@ func (r *GitRepositoryReconciler) reconcile(ctx context.Context, repository sour
// determine auth method
auth := &common.Auth{}
authStrategy := git.AuthSecretStrategyForURL(repository.Spec.URL, repository.Spec.GitProtocolV2Compatibility)
if repository.Spec.SecretRef != nil && authStrategy != nil {
if repository.Spec.SecretRef != nil {
authStrategy, err := git.AuthSecretStrategyForURL(repository.Spec.URL, repository.Spec.GitProtocolV2Compatibility)
if err != nil {
return sourcev1.GitRepositoryNotReady(repository, sourcev1.AuthenticationFailedReason, err.Error()), err
}
name := types.NamespacedName{
Namespace: repository.GetNamespace(),
Name: repository.Spec.SecretRef.Name,

View File

@ -25,8 +25,9 @@ import (
)
const (
DefaultOrigin = "origin"
DefaultBranch = "master"
DefaultOrigin = "origin"
DefaultBranch = "master"
DefaultPublicKeyAuthUser = "git"
)
type Commit interface {

View File

@ -35,7 +35,7 @@ func CheckoutStrategyForRef(ref *sourcev1.GitRepositoryRef, useGitV2 bool) commo
return gitv1.CheckoutStrategyForRef(ref)
}
func AuthSecretStrategyForURL(url string, useGitV2 bool) common.AuthSecretStrategy {
func AuthSecretStrategyForURL(url string, useGitV2 bool) (common.AuthSecretStrategy, error) {
if useGitV2 {
return gitv2.AuthSecretStrategyForURL(url)
}

View File

@ -28,8 +28,6 @@ import (
"github.com/fluxcd/source-controller/pkg/git/common"
)
const defaultPublicKeyAuthUser = "git"
func AuthSecretStrategyForURL(URL string) (common.AuthSecretStrategy, error) {
u, err := url.Parse(URL)
if err != nil {
@ -75,7 +73,7 @@ func (s *PublicKeyAuth) Method(secret corev1.Secret) (*common.Auth, error) {
user := s.user
if user == "" {
user = defaultPublicKeyAuthUser
user = common.DefaultPublicKeyAuthUser
}
pk, err := ssh.NewPublicKeys(user, identity, "")

View File

@ -22,6 +22,7 @@ import (
"crypto/sha1"
"fmt"
"golang.org/x/crypto/ssh"
"net/url"
"strings"
"github.com/fluxcd/source-controller/pkg/git/common"
@ -29,14 +30,20 @@ import (
corev1 "k8s.io/api/core/v1"
)
func AuthSecretStrategyForURL(url string) common.AuthSecretStrategy {
switch {
case strings.HasPrefix(url, "http"):
return &BasicAuth{}
case strings.HasPrefix(url, "ssh"):
return &PublicKeyAuth{}
func AuthSecretStrategyForURL(URL string) (common.AuthSecretStrategy, error) {
u, err := url.Parse(URL)
if err != nil {
return nil, fmt.Errorf("failed to parse URL to determine auth strategy: %w", err)
}
switch {
case u.Scheme == "http", u.Scheme == "https":
return &BasicAuth{}, nil
case u.Scheme == "ssh":
return &PublicKeyAuth{user: u.User.Username()}, nil
default:
return nil, fmt.Errorf("no auth secret strategy for scheme %s", u.Scheme)
}
return nil
}
type BasicAuth struct{}
@ -65,7 +72,9 @@ func (s *BasicAuth) Method(secret corev1.Secret) (*common.Auth, error) {
return &common.Auth{CredCallback: credCallback, CertCallback: nil}, nil
}
type PublicKeyAuth struct{}
type PublicKeyAuth struct {
user string
}
func (s *PublicKeyAuth) Method(secret corev1.Secret) (*common.Auth, error) {
identity := secret.Data["identity"]
@ -79,14 +88,20 @@ func (s *PublicKeyAuth) Method(secret corev1.Secret) (*common.Auth, error) {
return nil, err
}
// Need to validate private key
// Need to validate private key as it is not
// done by git2go when loading the key
_, err = ssh.ParsePrivateKey(identity)
if err != nil {
return nil, err
}
user := s.user
if user == "" {
user = common.DefaultPublicKeyAuthUser
}
credCallback := func(url string, username_from_url string, allowed_types git2go.CredType) (*git2go.Cred, error) {
cred, err := git2go.NewCredSshKeyFromMemory("git", "", string(identity), "")
cred, err := git2go.NewCredSshKeyFromMemory(user, "", string(identity), "")
if err != nil {
return nil, err
}

View File

@ -66,19 +66,25 @@ var (
func TestAuthSecretStrategyForURL(t *testing.T) {
tests := []struct {
name string
url string
want common.AuthSecretStrategy
name string
url string
want common.AuthSecretStrategy
wantErr bool
}{
{"HTTP", "http://git.example.com/org/repo.git", &BasicAuth{}},
{"HTTPS", "https://git.example.com/org/repo.git", &BasicAuth{}},
{"SSH", "ssh://git.example.com:2222/org/repo.git", &PublicKeyAuth{}},
{"unsupported", "protocol://example.com", nil},
{"HTTP", "http://git.example.com/org/repo.git", &BasicAuth{}, false},
{"HTTPS", "https://git.example.com/org/repo.git", &BasicAuth{}, false},
{"SSH", "ssh://git.example.com:2222/org/repo.git", &PublicKeyAuth{}, false},
{"SSH with username", "ssh://example@git.example.com:2222/org/repo.git", &PublicKeyAuth{user: "example"}, false},
{"unsupported", "protocol://example.com", nil, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := AuthSecretStrategyForURL(tt.url)
if reflect.TypeOf(got) != reflect.TypeOf(tt.want) {
got, err := AuthSecretStrategyForURL(tt.url)
if (err != nil) != tt.wantErr {
t.Errorf("AuthSecretStrategyForURL() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("AuthSecretStrategyForURL() got = %v, want %v", got, tt.want)
}
})