push + pull now works with reverse proxy + basic auth on apache 2.4
This commit is contained in:
		
							parent
							
								
									937b4b5aa1
								
							
						
					
					
						commit
						37eec6c9b7
					
				
					 1 changed files with 81 additions and 68 deletions
				
			
		|  | @ -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 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue