Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions creds/creds.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type Creds map[string][]string
func bufferCreds(c Creds) *bytes.Buffer {
buf := new(bytes.Buffer)

buf.Write([]byte("capability[]=authtype\n"))
for k, v := range c {
for _, item := range v {
buf.Write([]byte(k))
Expand Down
21 changes: 16 additions & 5 deletions lfsapi/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (c *Client) getCreds(remote string, access creds.Access, req *http.Request)
err = credWrapper.FillCreds()
if err == nil {
tracerx.Printf("Filled credentials for %s", credsURL)
setRequestAuth(req, creds.FirstEntryForKey(credWrapper.Creds, "username"), creds.FirstEntryForKey(credWrapper.Creds, "password"))
setRequestAuthWithCreds(req, credWrapper.Creds)
}
return credWrapper, err
}
Expand Down Expand Up @@ -303,6 +303,20 @@ func setRequestAuth(req *http.Request, user, pass string) {
req.Header.Set("Authorization", auth)
}

func setRequestAuthWithCreds(req *http.Request, c creds.Creds) {
authtype := creds.FirstEntryForKey(c, "authtype")
credential := creds.FirstEntryForKey(c, "credential")
if len(authtype) == 0 && len(credential) == 0 {
user := creds.FirstEntryForKey(c, "username")
pass := creds.FirstEntryForKey(c, "password")
setRequestAuth(req, user, pass)
return
}

auth := fmt.Sprintf("%s %s", authtype, credential)
req.Header.Set("Authorization", auth)
}

func getReqOperation(req *http.Request) string {
operation := "download"
if req.Method == "POST" || req.Method == "PUT" {
Expand Down Expand Up @@ -335,10 +349,7 @@ func getAuthAccess(res *http.Response, access creds.AccessMode, modes []creds.Ac
continue
}

switch creds.AccessMode(pieces[0]) {
case creds.BasicAccess, creds.NegotiateAccess:
supportedModes[creds.AccessMode(pieces[0])] = struct{}{}
}
supportedModes[creds.AccessMode(pieces[0])] = struct{}{}
}
}
for _, mode := range newModes {
Expand Down
66 changes: 53 additions & 13 deletions t/cmd/git-credential-lfstest.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,33 @@ func fill() {
}

hostPieces := strings.SplitN(firstEntryForKey(creds, "host"), ":", 2)
user, pass, err := credsForHostAndPath(hostPieces[0], firstEntryForKey(creds, "path"))
authtype, user, cred, err := credsForHostAndPath(hostPieces[0], firstEntryForKey(creds, "path"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}

if user != "skip" {
capas := discoverCapabilities(creds)

switch authtype {
case "skip":
case "":
if _, ok := creds["username"]; !ok {
creds["username"] = []string{user}
}

if _, ok := creds["password"]; !ok {
creds["password"] = []string{pass}
creds["password"] = []string{cred}
}
default:
if _, ok := capas["authtype"]; ok {
if _, ok := creds["authtype"]; !ok {
creds["authtype"] = []string{authtype}
}

if _, ok := creds["credential"]; !ok {
creds["credential"] = []string{cred}
}
}
}

Expand All @@ -97,15 +111,41 @@ func fill() {
}
delete(creds, "wwwauth[]")

// Send capabilities first to all for one-pass parsing.
for _, entry := range creds["capability[]"] {
key := "capability[]"
fmt.Fprintf(os.Stderr, "CREDS SEND: %s=%s\n", key, entry)
fmt.Fprintf(os.Stdout, "%s=%s\n", key, entry)
}
for key, value := range creds {
if key == "capability[]" {
continue
}
for _, entry := range value {
fmt.Fprintf(os.Stderr, "CREDS SEND: %s=%s\n", key, entry)
fmt.Fprintf(os.Stdout, "%s=%s\n", key, entry)
}
}
}

func credsForHostAndPath(host, path string) (string, string, error) {
func discoverCapabilities(creds map[string][]string) map[string]struct{} {
capas := make(map[string]struct{})
supportedCapas := map[string]struct{}{
"authtype": struct{}{},
}
capasToSend := []string{}
for _, capa := range creds["capability[]"] {
capas[capa] = struct{}{}
// Only pass on capabilities we support.
if _, ok := supportedCapas[capa]; ok {
capasToSend = append(capasToSend, capa)
}
}
creds["capability[]"] = capasToSend
return capas
}

func credsForHostAndPath(host, path string) (string, string, string, error) {
var hostFilename string

// We need hostFilename to end in a slash so that our credentials all
Expand All @@ -120,25 +160,25 @@ func credsForHostAndPath(host, path string) (string, string, error) {

if len(path) > 0 {
pathFilename := fmt.Sprintf("%s--%s", hostFilename, strings.Replace(path, "/", "-", -1))
u, p, err := credsFromFilename(pathFilename)
authtype, u, cred, err := credsFromFilename(pathFilename)
if err == nil {
return u, p, err
return authtype, u, cred, err
}
}

return credsFromFilename(hostFilename)
}

func credsFromFilename(file string) (string, string, error) {
userPass, err := os.ReadFile(file)
func credsFromFilename(file string) (string, string, string, error) {
credential, err := os.ReadFile(file)
if err != nil {
return "", "", fmt.Errorf("Error opening %q: %s", file, err)
return "", "", "", fmt.Errorf("Error opening %q: %s", file, err)
}
credsPieces := strings.SplitN(strings.TrimSpace(string(userPass)), ":", 2)
if len(credsPieces) != 2 {
return "", "", fmt.Errorf("Invalid data %q while reading %q", string(userPass), file)
credsPieces := strings.SplitN(strings.TrimSpace(string(credential)), ":", 3)
if len(credsPieces) != 3 {
return "", "", "", fmt.Errorf("Invalid data %q while reading %q", string(credential), file)
}
return credsPieces[0], credsPieces[1], nil
return credsPieces[0], credsPieces[1], credsPieces[2], nil
}

func log() {
Expand Down
60 changes: 42 additions & 18 deletions t/cmd/lfstest-gitserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ var (
"status-batch-resume-206", "batch-resume-fail-fallback", "return-expired-action", "return-expired-action-forever", "return-invalid-size",
"object-authenticated", "storage-download-retry", "storage-upload-retry", "storage-upload-retry-later", "unknown-oid",
"send-verify-action", "send-deprecated-links", "redirect-storage-upload", "storage-compress", "batch-hash-algo-empty", "batch-hash-algo-invalid",
"auth-bearer",
}

reqCookieReposRE = regexp.MustCompile(`\A/require-cookie-`)
Expand Down Expand Up @@ -373,7 +374,7 @@ func lfsBatchHandler(w http.ResponseWriter, r *http.Request, id, repo string) {
}

if repo == "netrctest" {
user, pass, err := extractAuth(r.Header.Get("Authorization"))
_, user, pass, err := extractAuth(r.Header.Get("Authorization"))
if err != nil || (user != "netrcuser" || pass != "netrcpass") {
w.WriteHeader(403)
return
Expand Down Expand Up @@ -1206,7 +1207,7 @@ func locksHandler(w http.ResponseWriter, r *http.Request, repo string) {
enc := json.NewEncoder(w)

if repo == "netrctest" {
user, pass, err := extractAuth(r.Header.Get("Authorization"))
_, user, pass, err := extractAuth(r.Header.Get("Authorization"))
if err != nil || (user == "netrcuser" && pass == "badpassretry") {
writeLFSError(w, 401, "Error: Bad Auth")
return
Expand Down Expand Up @@ -1422,7 +1423,7 @@ func missingRequiredCreds(w http.ResponseWriter, r *http.Request, repo string) b
return true
}

user, pass, err := extractAuth(auth)
_, user, pass, err := extractAuth(auth)
if err != nil {
writeLFSError(w, 403, err.Error())
return true
Expand Down Expand Up @@ -1555,23 +1556,26 @@ func newLfsStorage() *lfsStorage {
}
}

func extractAuth(auth string) (string, string, error) {
func extractAuth(auth string) (string, string, string, error) {
if strings.HasPrefix(auth, "Basic ") {
decodeBy, err := base64.StdEncoding.DecodeString(auth[6:len(auth)])
decoded := string(decodeBy)

if err != nil {
return "", "", err
return "", "", "", err
}

parts := strings.SplitN(decoded, ":", 2)
if len(parts) == 2 {
return parts[0], parts[1], nil
return "Basic", parts[0], parts[1], nil
}
return "", "", nil
return "", "", "", nil
} else if strings.HasPrefix(auth, "Bearer ") {
authtype, cred, _ := strings.Cut(auth, " ")
return authtype, "", cred, nil
}

return "", "", nil
return "", "", "", nil
}

func skipIfNoCookie(w http.ResponseWriter, r *http.Request, id string) bool {
Expand All @@ -1586,32 +1590,52 @@ func skipIfNoCookie(w http.ResponseWriter, r *http.Request, id string) bool {
}

func skipIfBadAuth(w http.ResponseWriter, r *http.Request, id string) bool {
wantedAuth := "Basic realm=\"testsuite\""
authHeader := "Lfs-Authenticate"
if strings.HasPrefix(r.URL.Path, "/auth-bearer") {
wantedAuth = "Bearer"
authHeader = "Www-Authenticate"
}

auth := r.Header.Get("Authorization")
if auth == "" {
w.Header().Add("Lfs-Authenticate", "Basic realm=\"testsuite\"")
w.Header().Add(authHeader, wantedAuth)
w.WriteHeader(401)
return true
}

user, pass, err := extractAuth(auth)
authtype, user, cred, err := extractAuth(auth)
if err != nil {
w.WriteHeader(403)
debug(id, "Error decoding auth: %s", err)
return true
}

switch user {
case "user":
if pass == "pass" {
if !strings.HasPrefix(wantedAuth, authtype) {
w.WriteHeader(403)
debug(id, "Unwanted auth: %s (wanted %q)", authtype, wantedAuth)
return true
}

switch authtype {
case "Basic":
switch user {
case "user":
if cred == "pass" {
return false
}
case "netrcuser", "requirecreds":
return false
case "path":
if strings.HasPrefix(r.URL.Path, "/"+cred) {
return false
}
debug(id, "auth attempt against: %q", r.URL.Path)
}
case "netrcuser", "requirecreds":
return false
case "path":
if strings.HasPrefix(r.URL.Path, "/"+pass) {
case "Bearer":
if cred == "token" {
return false
}
debug(id, "auth attempt against: %q", r.URL.Path)
}

w.WriteHeader(403)
Expand Down
Loading