mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	push + pull now works with reverse proxy + basic auth on apache 2.4
This commit is contained in:
		
				
					committed by
					
						
						Kim "BKC" Carlbäcker
					
				
			
			
				
	
			
			
			
						parent
						
							937b4b5aa1
						
					
				
				
					commit
					37eec6c9b7
				
			@@ -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
 | 
			
		||||
			}
 | 
			
		||||
			authUser, err = models.GetUserByName(authUsername)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				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
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Assume username now is a token.
 | 
			
		||||
			token, err := models.GetAccessTokenBySHA(authUsername)
 | 
			
		||||
			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 {
 | 
			
		||||
				if models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err) {
 | 
			
		||||
					ctx.HandleText(http.StatusUnauthorized, "invalid token")
 | 
			
		||||
				} else {
 | 
			
		||||
					ctx.Handle(http.StatusInternalServerError, "GetAccessTokenBySha", err)
 | 
			
		||||
				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)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				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
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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
 | 
			
		||||
				// 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)
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					ctx.HandleText(http.StatusForbidden, "User permission denied")
 | 
			
		||||
					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
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if !isPull && repo.IsMirror {
 | 
			
		||||
				ctx.HandleText(http.StatusForbidden, "mirror repository is read-only")
 | 
			
		||||
				return
 | 
			
		||||
			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
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if !isPull && repo.IsMirror {
 | 
			
		||||
					ctx.HandleText(http.StatusForbidden, "mirror repository is read-only")
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user