Skip to content

Commit 0d504b8

Browse files
Merge pull request #1051 from renyunkang/check-access
add git repository reachability validation
2 parents 70deaf9 + 5f27295 commit 0d504b8

File tree

5 files changed

+101
-6
lines changed

5 files changed

+101
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ scripts
2020

2121
# editor and IDE paraphernalia
2222
.idea
23+
.nocalhost
2324
*.swp
2425
*.swo
2526
*~

pkg/client/git/client.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (c *ClientFactory) GetClient() (client *goscm.Client, err error) {
6363
var token string
6464
username := ""
6565
if c.secretRef != nil {
66-
if token, username, err = c.getTokenFromSecret(c.secretRef); err != nil {
66+
if token, username, _, err = c.GetTokenFromSecret(c.secretRef); err != nil {
6767
return
6868
}
6969
}
@@ -73,7 +73,7 @@ func (c *ClientFactory) GetClient() (client *goscm.Client, err error) {
7373
return
7474
}
7575

76-
func (c *ClientFactory) getTokenFromSecret(secretRef *v1.SecretReference) (token, username string, err error) {
76+
func (c *ClientFactory) GetTokenFromSecret(secretRef *v1.SecretReference) (token, username string, privateKey []byte, err error) {
7777
var gitSecret *v1.Secret
7878
if gitSecret, err = c.getSecret(secretRef); err != nil {
7979
return
@@ -86,7 +86,12 @@ func (c *ClientFactory) getTokenFromSecret(secretRef *v1.SecretReference) (token
8686
case v1.SecretTypeOpaque:
8787
token = string(gitSecret.Data[v1.ServiceAccountTokenKey])
8888
case v1alpha3.SecretTypeSecretText:
89-
token = string(gitSecret.Data["secret"])
89+
username = string(gitSecret.Data[v1.BasicAuthUsernameKey])
90+
token = string(gitSecret.Data[v1alpha3.SecretTextSecretKey])
91+
case v1alpha3.SecretTypeSSHAuth:
92+
privateKey = gitSecret.Data[v1alpha3.SSHAuthPrivateKey]
93+
token = string(gitSecret.Data[v1alpha3.SSHAuthPassphraseKey])
94+
username = string(gitSecret.Data[v1alpha3.SSHAuthUsernameKey])
9095
}
9196
return
9297
}

pkg/kapis/devops/v1alpha3/scm/gitrepository_handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (h *handler) createGitRepositories(req *restful.Request, res *restful.Respo
4848
namespace := common.GetPathParameter(req, common.NamespacePathParameter)
4949
repo := &v1alpha3.GitRepository{}
5050
err := req.ReadEntity(repo)
51-
ctx := context.Background()
51+
ctx := req.Request.Context()
5252

5353
if err == nil {
5454
repo.Namespace = namespace

pkg/kapis/devops/v1alpha3/scm/scmhandler.go

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,19 @@ package scm
1919
import (
2020
"context"
2121
"fmt"
22+
"net/http"
23+
"strings"
24+
2225
"github.com/emicklei/go-restful/v3"
26+
gogit "github.com/go-git/go-git/v5"
27+
"github.com/go-git/go-git/v5/config"
28+
"github.com/go-git/go-git/v5/storage/memory"
2329
goscm "github.com/jenkins-x/go-scm/scm"
2430
"github.com/kubesphere/ks-devops/pkg/client/git"
2531
"github.com/kubesphere/ks-devops/pkg/kapis"
2632
"github.com/kubesphere/ks-devops/pkg/kapis/common"
2733
v1 "k8s.io/api/core/v1"
2834
"sigs.k8s.io/controller-runtime/pkg/client"
29-
"strings"
3035
)
3136

3237
// handler holds all the API handlers of SCM
@@ -48,14 +53,58 @@ func (h *handler) verify(request *restful.Request, response *restful.Response) {
4853
secretNamespace := request.QueryParameter("secretNamespace")
4954
server := common.GetQueryParameter(request, queryParameterServer)
5055

51-
_, code, err := h.getOrganizations(scm, server, secretName, secretNamespace, 1, 1, false)
56+
code, err := 0, error(nil)
57+
switch scm {
58+
case "git":
59+
if server == "" {
60+
err := fmt.Errorf("server is required")
61+
kapis.HandleError(request, response, err)
62+
response.WriteHeaderAndEntity(http.StatusBadRequest, err)
63+
return
64+
}
65+
code, err = h.checkRepoAccess(server, secretName, secretNamespace)
66+
67+
default:
68+
_, code, err = h.getOrganizations(scm, server, secretName, secretNamespace, 1, 1, false)
69+
}
5270

5371
response.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON)
5472
verifyResult := git.VerifyResult(err, code)
5573
verifyResult.CredentialID = secretName
5674
_ = response.WriteAsJson(verifyResult)
5775
}
5876

77+
func (h *handler) checkRepoAccess(repourl, secretName, secretNamespace string) (int, error) {
78+
storage := memory.NewStorage()
79+
remote := gogit.NewRemote(storage, &config.RemoteConfig{
80+
Name: "origin",
81+
URLs: []string{repourl},
82+
})
83+
84+
listOption := &gogit.ListOptions{}
85+
if secretName != "" && secretNamespace != "" {
86+
factory := git.NewClientFactory("git", &v1.SecretReference{
87+
Namespace: secretNamespace, Name: secretName,
88+
}, h.Client)
89+
token, user, privateKey, err := factory.GetTokenFromSecret(&v1.SecretReference{Namespace: secretNamespace, Name: secretName})
90+
if err != nil {
91+
return http.StatusInternalServerError, err
92+
}
93+
94+
listOption.Auth, err = getAuthMethod(repourl, user, token, privateKey)
95+
if err != nil {
96+
return http.StatusBadRequest, err
97+
}
98+
}
99+
100+
_, err := remote.List(listOption)
101+
if err != nil {
102+
return http.StatusForbidden, fmt.Errorf("access verification failed: %v", err)
103+
}
104+
105+
return http.StatusOK, nil
106+
}
107+
59108
func (h *handler) getOrganizations(scm, server, secret, namespace string, page, size int, includeUser bool) (orgs []*goscm.Organization, code int, err error) {
60109
factory := git.NewClientFactory(scm, &v1.SecretReference{
61110
Namespace: namespace, Name: secret,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package scm
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/go-git/go-git/v5/plumbing/transport"
9+
"github.com/go-git/go-git/v5/plumbing/transport/http"
10+
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
11+
gossh "golang.org/x/crypto/ssh"
12+
)
13+
14+
func getAuthMethod(repoURL, username, password string, sshKey []byte) (transport.AuthMethod, error) {
15+
switch {
16+
case strings.HasPrefix(repoURL, "http://"), strings.HasPrefix(repoURL, "https://"):
17+
if password == "" {
18+
return nil, errors.New("password/token required for HTTP URLs")
19+
}
20+
return &http.BasicAuth{Username: username, Password: password}, nil
21+
22+
case strings.HasPrefix(repoURL, "git@"):
23+
fallthrough
24+
case strings.Contains(repoURL, "ssh://"):
25+
if len(sshKey) == 0 {
26+
return nil, errors.New("SSH private key required for SSH URLs")
27+
}
28+
29+
publicKeys, err := ssh.NewPublicKeys(username, sshKey, password)
30+
if err != nil {
31+
return nil, fmt.Errorf("failed to create SSH auth: %w", err)
32+
}
33+
publicKeys.HostKeyCallback = gossh.InsecureIgnoreHostKey()
34+
35+
return publicKeys, nil
36+
37+
default:
38+
return nil, errors.New("unsupported repository URL scheme")
39+
}
40+
}

0 commit comments

Comments
 (0)