From 37eec6c9b7056e1e05d0067aef86d2e61d67f757 Mon Sep 17 00:00:00 2001 From: Gogs Date: Wed, 28 Dec 2016 21:33:59 +0000 Subject: [PATCH] push + pull now works with reverse proxy + basic auth on apache 2.4 --- routers/repo/http.go | 137 +++++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 62 deletions(-) diff --git a/routers/repo/http.go b/routers/repo/http.go index 2f0a707f7c0b5..6b4dec8149073 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -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 + } } } }