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 131 132 133 134 135 136
|
package accessverifier
import (
"context"
"fmt"
"net/http"
pb "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"gitlab.com/gitlab-org/gitlab-shell/v14/client"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/command/commandargs"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/config"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/gitlabnet"
)
const (
sshProtocol = "ssh"
anyChanges = "_any"
)
type Client struct {
client *client.GitlabNetClient
}
type Request struct {
Action commandargs.CommandType `json:"action"`
Repo string `json:"project"`
Changes string `json:"changes"`
Protocol string `json:"protocol"`
KeyId string `json:"key_id,omitempty"`
Username string `json:"username,omitempty"`
Krb5Principal string `json:"krb5principal,omitempty"`
CheckIp string `json:"check_ip,omitempty"`
// NamespacePath is the full path of the namespace in which the authenticated
// user is allowed to perform operation.
NamespacePath string `json:"namespace_path,omitempty"`
}
type Gitaly struct {
Repo pb.Repository `json:"repository"`
Address string `json:"address"`
Token string `json:"token"`
Features map[string]string `json:"features"`
}
type CustomPayloadData struct {
ApiEndpoints []string `json:"api_endpoints"`
Username string `json:"gl_username"`
PrimaryRepo string `json:"primary_repo"`
UserId string `json:"gl_id,omitempty"`
RequestHeaders map[string]string `json:"request_headers"`
GeoProxyDirectToPrimary bool `json:"geo_proxy_direct_to_primary"`
GeoProxyFetchDirectToPrimary bool `json:"geo_proxy_fetch_direct_to_primary"`
GeoProxyFetchDirectToPrimaryWithOptions bool `json:"geo_proxy_fetch_direct_to_primary_with_options"`
}
type CustomPayload struct {
Action string `json:"action"`
Data CustomPayloadData `json:"data"`
}
type Response struct {
Success bool `json:"status"`
Message string `json:"message"`
Repo string `json:"gl_repository"`
UserId string `json:"gl_id"`
KeyType string `json:"gl_key_type"`
KeyId int `json:"gl_key_id"`
Username string `json:"gl_username"`
GitConfigOptions []string `json:"git_config_options"`
Gitaly Gitaly `json:"gitaly"`
GitProtocol string `json:"git_protocol"`
Payload CustomPayload `json:"payload"`
ConsoleMessages []string `json:"gl_console_messages"`
Who string
StatusCode int
// NeedAudit indicates whether git event should be audited to rails.
NeedAudit bool `json:"need_audit"`
}
func NewClient(config *config.Config) (*Client, error) {
client, err := gitlabnet.GetClient(config)
if err != nil {
return nil, fmt.Errorf("Error creating http client: %v", err)
}
return &Client{client: client}, nil
}
func (c *Client) Verify(ctx context.Context, args *commandargs.Shell, action commandargs.CommandType, repo string) (*Response, error) {
request := &Request{
Action: action,
Repo: repo,
Changes: anyChanges,
Protocol: sshProtocol,
NamespacePath: args.Env.NamespacePath,
}
if args.GitlabUsername != "" {
request.Username = args.GitlabUsername
} else if args.GitlabKrb5Principal != "" {
request.Krb5Principal = args.GitlabKrb5Principal
} else {
request.KeyId = args.GitlabKeyId
}
request.CheckIp = gitlabnet.ParseIP(args.Env.RemoteAddr)
response, err := c.client.Post(ctx, "/allowed", request)
if err != nil {
return nil, err
}
defer response.Body.Close()
return parse(response, args)
}
func parse(hr *http.Response, args *commandargs.Shell) (*Response, error) {
response := &Response{}
if err := gitlabnet.ParseJSON(hr, response); err != nil {
return nil, err
}
if args.GitlabKeyId != "" {
response.Who = "key-" + args.GitlabKeyId
} else {
response.Who = response.UserId
}
response.StatusCode = hr.StatusCode
return response, nil
}
func (r *Response) IsCustomAction() bool {
return r.StatusCode == http.StatusMultipleChoices
}
|