|
|
|
@ -83,85 +83,98 @@ func HTTP(ctx *context.Context) { |
|
|
|
|
|
|
|
|
|
// check access
|
|
|
|
|
if askAuth { |
|
|
|
|
authHead := ctx.Req.Header.Get("Authorization") |
|
|
|
|
if len(authHead) == 0 { |
|
|
|
|
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=\".\"") |
|
|
|
|
ctx.Error(http.StatusUnauthorized) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
auths := strings.Fields(authHead) |
|
|
|
|
// currently check basic auth
|
|
|
|
|
// TODO: support digit auth
|
|
|
|
|
// FIXME: middlewares/context.go did basic auth check already,
|
|
|
|
|
// maybe could use that one.
|
|
|
|
|
if len(auths) != 2 || auths[0] != "Basic" { |
|
|
|
|
ctx.HandleText(http.StatusUnauthorized, "no basic auth and digit auth") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
authUsername, authPasswd, err = base.BasicAuthDecode(auths[1]) |
|
|
|
|
if err != nil { |
|
|
|
|
ctx.HandleText(http.StatusUnauthorized, "no basic auth and digit auth") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
authUser, err = models.UserSignIn(authUsername, authPasswd) |
|
|
|
|
if err != nil { |
|
|
|
|
if !models.IsErrUserNotExist(err) { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "UserSignIn error: %v", err) |
|
|
|
|
if setting.Service.EnableReverseProxyAuth { |
|
|
|
|
authUsername = ctx.Req.Header.Get(setting.ReverseProxyAuthUser) |
|
|
|
|
if len(authUsername) == 0 { |
|
|
|
|
ctx.HandleText(401, "reverse proxy login error. authUsername empty") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Assume username now is a token.
|
|
|
|
|
token, err := models.GetAccessTokenBySHA(authUsername) |
|
|
|
|
authUser, err = models.GetUserByName(authUsername) |
|
|
|
|
if err != nil { |
|
|
|
|
if models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err) { |
|
|
|
|
ctx.HandleText(http.StatusUnauthorized, "invalid token") |
|
|
|
|
} else { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "GetAccessTokenBySha", err) |
|
|
|
|
} |
|
|
|
|
ctx.HandleText(401, "reverse proxy login error, got error while running GetUserByName") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
}else{ |
|
|
|
|
authHead := ctx.Req.Header.Get("Authorization") |
|
|
|
|
if len(authHead) == 0 { |
|
|
|
|
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=\".\"") |
|
|
|
|
ctx.Error(http.StatusUnauthorized) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
token.Updated = time.Now() |
|
|
|
|
if err = models.UpdateAccessToken(token); err != nil { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "UpdateAccessToken", err) |
|
|
|
|
|
|
|
|
|
auths := strings.Fields(authHead) |
|
|
|
|
// currently check basic auth
|
|
|
|
|
// TODO: support digit auth
|
|
|
|
|
// FIXME: middlewares/context.go did basic auth check already,
|
|
|
|
|
// maybe could use that one.
|
|
|
|
|
if len(auths) != 2 || auths[0] != "Basic" { |
|
|
|
|
ctx.HandleText(http.StatusUnauthorized, "no basic auth and digit auth") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
authUser, err = models.GetUserByID(token.UID) |
|
|
|
|
authUsername, authPasswd, err = base.BasicAuthDecode(auths[1]) |
|
|
|
|
if err != nil { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "GetUserByID", err) |
|
|
|
|
ctx.HandleText(http.StatusUnauthorized, "no basic auth and digit auth") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !isPublicPull { |
|
|
|
|
var tp = models.AccessModeWrite |
|
|
|
|
if isPull { |
|
|
|
|
tp = models.AccessModeRead |
|
|
|
|
authUser, err = models.UserSignIn(authUsername, authPasswd) |
|
|
|
|
if err != nil { |
|
|
|
|
if !models.IsErrUserNotExist(err) { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "UserSignIn error: %v", err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Assume username now is a token.
|
|
|
|
|
token, err := models.GetAccessTokenBySHA(authUsername) |
|
|
|
|
if err != nil { |
|
|
|
|
if models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err) { |
|
|
|
|
ctx.HandleText(http.StatusUnauthorized, "invalid token") |
|
|
|
|
} else { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "GetAccessTokenBySha", err) |
|
|
|
|
} |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
token.Updated = time.Now() |
|
|
|
|
if err = models.UpdateAccessToken(token); err != nil { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "UpdateAccessToken", err) |
|
|
|
|
} |
|
|
|
|
authUser, err = models.GetUserByID(token.UID) |
|
|
|
|
if err != nil { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "GetUserByID", err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
has, err := models.HasAccess(authUser, repo, tp) |
|
|
|
|
if err != nil { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "HasAccess", err) |
|
|
|
|
return |
|
|
|
|
} else if !has { |
|
|
|
|
if tp == models.AccessModeRead { |
|
|
|
|
has, err = models.HasAccess(authUser, repo, models.AccessModeWrite) |
|
|
|
|
if err != nil { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "HasAccess2", err) |
|
|
|
|
return |
|
|
|
|
} else if !has { |
|
|
|
|
if !isPublicPull { |
|
|
|
|
var tp = models.AccessModeWrite |
|
|
|
|
if isPull { |
|
|
|
|
tp = models.AccessModeRead |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
has, err := models.HasAccess(authUser, repo, tp) |
|
|
|
|
if err != nil { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "HasAccess", err) |
|
|
|
|
return |
|
|
|
|
} else if !has { |
|
|
|
|
if tp == models.AccessModeRead { |
|
|
|
|
has, err = models.HasAccess(authUser, repo, models.AccessModeWrite) |
|
|
|
|
if err != nil { |
|
|
|
|
ctx.Handle(http.StatusInternalServerError, "HasAccess2", err) |
|
|
|
|
return |
|
|
|
|
} else if !has { |
|
|
|
|
ctx.HandleText(http.StatusForbidden, "User permission denied") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
ctx.HandleText(http.StatusForbidden, "User permission denied") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
ctx.HandleText(http.StatusForbidden, "User permission denied") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !isPull && repo.IsMirror { |
|
|
|
|
ctx.HandleText(http.StatusForbidden, "mirror repository is read-only") |
|
|
|
|
return |
|
|
|
|
if !isPull && repo.IsMirror { |
|
|
|
|
ctx.HandleText(http.StatusForbidden, "mirror repository is read-only") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|