mirror of https://github.com/h44z/wg-portal.git
				
				
				
			sec: validate return url
This commit is contained in:
		
							parent
							
								
									0664bd0ad0
								
							
						
					
					
						commit
						378252ba2f
					
				|  | @ -2,14 +2,16 @@ package handlers | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"net/http" | ||||||
|  | 	"net/url" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
| 	"github.com/h44z/wg-portal/internal/app" | 	"github.com/h44z/wg-portal/internal/app" | ||||||
| 	"github.com/h44z/wg-portal/internal/app/api/v0/model" | 	"github.com/h44z/wg-portal/internal/app/api/v0/model" | ||||||
| 	"github.com/h44z/wg-portal/internal/domain" | 	"github.com/h44z/wg-portal/internal/domain" | ||||||
| 	"net/http" |  | ||||||
| 	"net/url" |  | ||||||
| 	"strconv" |  | ||||||
| 	"time" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type authEndpoint struct { | type authEndpoint struct { | ||||||
|  | @ -114,6 +116,10 @@ func (e authEndpoint) handleOauthInitiateGet() gin.HandlerFunc { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if returnTo != "" { | 		if returnTo != "" { | ||||||
|  | 			if !e.isValidReturnUrl(returnTo) { | ||||||
|  | 				c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "invalid return URL"}) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
| 			if u, err := url.Parse(returnTo); err == nil { | 			if u, err := url.Parse(returnTo); err == nil { | ||||||
| 				returnUrl = u | 				returnUrl = u | ||||||
| 			} | 			} | ||||||
|  | @ -138,10 +144,11 @@ func (e authEndpoint) handleOauthInitiateGet() gin.HandlerFunc { | ||||||
| 		ctx := domain.SetUserInfoFromGin(c) | 		ctx := domain.SetUserInfoFromGin(c) | ||||||
| 		authCodeUrl, state, nonce, err := e.app.Authenticator.OauthLoginStep1(ctx, provider) | 		authCodeUrl, state, nonce, err := e.app.Authenticator.OauthLoginStep1(ctx, provider) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if autoRedirect { | 			if autoRedirect && e.isValidReturnUrl(returnTo) { | ||||||
| 				redirectToReturn() | 				redirectToReturn() | ||||||
| 			} else { | 			} else { | ||||||
| 				c.JSON(http.StatusInternalServerError, model.Error{Code: http.StatusInternalServerError, Message: err.Error()}) | 				c.JSON(http.StatusInternalServerError, | ||||||
|  | 					model.Error{Code: http.StatusInternalServerError, Message: err.Error()}) | ||||||
| 			} | 			} | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  | @ -193,7 +200,7 @@ func (e authEndpoint) handleOauthCallbackGet() gin.HandlerFunc { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if currentSession.LoggedIn { | 		if currentSession.LoggedIn { | ||||||
| 			if returnUrl != nil { | 			if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { | ||||||
| 				queryParams := returnUrl.Query() | 				queryParams := returnUrl.Query() | ||||||
| 				queryParams.Set("wgLoginState", "success") | 				queryParams.Set("wgLoginState", "success") | ||||||
| 				returnParams = queryParams.Encode() | 				returnParams = queryParams.Encode() | ||||||
|  | @ -209,15 +216,16 @@ func (e authEndpoint) handleOauthCallbackGet() gin.HandlerFunc { | ||||||
| 		oauthState := c.Query("state") | 		oauthState := c.Query("state") | ||||||
| 
 | 
 | ||||||
| 		if provider != currentSession.OauthProvider { | 		if provider != currentSession.OauthProvider { | ||||||
| 			if returnUrl != nil { | 			if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { | ||||||
| 				redirectToReturn() | 				redirectToReturn() | ||||||
| 			} else { | 			} else { | ||||||
| 				c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "invalid oauth provider"}) | 				c.JSON(http.StatusBadRequest, | ||||||
|  | 					model.Error{Code: http.StatusBadRequest, Message: "invalid oauth provider"}) | ||||||
| 			} | 			} | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		if oauthState != currentSession.OauthState { | 		if oauthState != currentSession.OauthState { | ||||||
| 			if returnUrl != nil { | 			if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { | ||||||
| 				redirectToReturn() | 				redirectToReturn() | ||||||
| 			} else { | 			} else { | ||||||
| 				c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "invalid oauth state"}) | 				c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "invalid oauth state"}) | ||||||
|  | @ -328,3 +336,12 @@ func (e authEndpoint) handleLogoutPost() gin.HandlerFunc { | ||||||
| 		c.JSON(http.StatusOK, model.Error{Code: http.StatusOK, Message: "logout ok"}) | 		c.JSON(http.StatusOK, model.Error{Code: http.StatusOK, Message: "logout ok"}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // isValidReturnUrl checks if the given return URL matches the configured external URL of the application.
 | ||||||
|  | func (e authEndpoint) isValidReturnUrl(returnUrl string) bool { | ||||||
|  | 	if !strings.HasPrefix(returnUrl, e.app.Config.Web.ExternalUrl) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue