add validations for app state

This commit is contained in:
Lakhan Samani
2021-08-02 23:31:17 +05:30
parent d0897b1d83
commit dbd19b7465
8 changed files with 107 additions and 31 deletions

Binary file not shown.

View File

@@ -1,18 +1,55 @@
package handlers
import (
"encoding/base64"
"encoding/json"
"log"
"net/http"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/gin-gonic/gin"
)
// TODO read query param = state which is base64 encoded
// make sure url is present in allowed origins
// set that in redirect_url
type State struct {
AuthorizerURL string `json:"authorizerURL"`
RedirectURL string `json:"redirectURL"`
}
func AppHandler() gin.HandlerFunc {
return func(c *gin.Context) {
log.Println("Host:", c.Request.Host)
host := c.Request.Host
state := c.Query("state")
if state == "" {
c.JSON(400, gin.H{"error": "invalid state"})
return
}
decodedState, err := base64.StdEncoding.DecodeString(state)
if err != nil {
c.JSON(400, gin.H{"error": "[unable to decode state] invalid state"})
return
}
var stateObj State
err = json.Unmarshal(decodedState, &stateObj)
if err != nil {
c.JSON(400, gin.H{"error": "[unable to parse state] invalid state"})
return
}
// validate redirect url with allowed origins
if !utils.IsValidRedirectURL(stateObj.RedirectURL) {
c.JSON(400, gin.H{"error": "invalid redirect url"})
return
}
log.Println(stateObj)
log.Println(host, utils.GetDomainName(stateObj.AuthorizerURL), utils.GetDomainName(host))
// validate host and domain of authorizer url
if utils.GetDomainName(stateObj.AuthorizerURL) != utils.GetDomainName(host) {
c.JSON(400, gin.H{"error": "invalid host url"})
return
}
// debug the request state
if pusher := c.Writer.Pusher(); pusher != nil {
// use pusher.Push() to do server push
@@ -22,8 +59,8 @@ func AppHandler() gin.HandlerFunc {
}
c.HTML(http.StatusOK, "app.tmpl", gin.H{
"data": map[string]string{
"authorizerURL": c.Request.Host,
"redirect_url": "http://localhost:8080/app",
"authorizerURL": stateObj.AuthorizerURL,
"redirectURL": stateObj.RedirectURL,
},
})
}

View File

@@ -174,11 +174,12 @@ func OAuthCallbackHandler() gin.HandlerFunc {
}
var err error
code := c.Request.FormValue("code")
switch provider {
case enum.Google.String():
err = processGoogleUserInfo(c.Request.FormValue("code"), c)
err = processGoogleUserInfo(code, c)
case enum.Github.String():
err = processGithubUserInfo(c.Request.FormValue("code"), c)
err = processGithubUserInfo(code, c)
default:
err = fmt.Errorf(`invalid oauth provider`)
}

View File

@@ -15,7 +15,7 @@ import (
func OAuthLoginHandler() gin.HandlerFunc {
return func(c *gin.Context) {
// TODO validate redirect URL
redirectURL := c.Query("redirect_url")
redirectURL := c.Query("redirectURL")
if redirectURL == "" {
c.JSON(400, gin.H{

View File

@@ -12,7 +12,7 @@ func SetCookie(gc *gin.Context, token string) {
secure := true
httpOnly := true
host := GetDomainName(gc.Request.Host)
host := GetHostName(gc.Request.Host)
log.Println("=> host", host)
gc.SetSameSite(http.SameSiteNoneMode)
gc.SetCookie(constants.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
@@ -35,7 +35,7 @@ func DeleteCookie(gc *gin.Context) {
secure = false
}
host := GetDomainName(gc.Request.Host)
host := GetHostName(gc.Request.Host)
gc.SetSameSite(http.SameSiteNoneMode)
gc.SetCookie(constants.COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
}

View File

@@ -1,11 +1,13 @@
package utils
import (
"log"
"net/url"
"strings"
)
// function to get hostname
func GetDomainName(auth_url string) string {
func GetHostName(auth_url string) string {
u, err := url.Parse("//" + auth_url)
if err != nil {
return `localhost`
@@ -13,25 +15,38 @@ func GetDomainName(auth_url string) string {
host := u.Hostname()
return host
}
// function to get domain name
func GetDomainName(auth_url string) string {
u, err := url.Parse("//" + auth_url)
if err != nil {
return `localhost`
}
host := u.Hostname()
log.Println("=> host", host)
// code to get root domain in case of sub-domains
// hostParts := strings.Split(host, ".")
// hostPartsLen := len(hostParts)
hostParts := strings.Split(host, ".")
hostPartsLen := len(hostParts)
// if hostPartsLen == 1 {
// return host
// }
if hostPartsLen == 1 {
return host
}
// if hostPartsLen == 2 {
// if hostParts[0] == "www" {
// return hostParts[1]
// } else {
// return host
// }
// }
if hostPartsLen == 2 {
if hostParts[0] == "www" {
return hostParts[1]
} else {
return host
}
}
// if hostPartsLen > 2 {
// return strings.Join(hostParts[hostPartsLen-2:], ".")
// }
if hostPartsLen > 2 {
return strings.Join(hostParts[hostPartsLen-2:], ".")
}
return host
}

View File

@@ -1,8 +1,31 @@
package utils
import "net/mail"
import (
"net/mail"
"strings"
"github.com/authorizerdev/authorizer/server/constants"
)
func IsValidEmail(email string) bool {
_, err := mail.ParseAddress(email)
return err == nil
}
func IsValidRedirectURL(url string) bool {
if len(constants.ALLOWED_ORIGINS) == 1 && constants.ALLOWED_ORIGINS[0] == "*" {
return true
}
hasValidURL := false
urlDomain := GetDomainName(url)
for _, val := range constants.ALLOWED_ORIGINS {
if strings.Contains(val, urlDomain) {
hasValidURL = true
break
}
}
return hasValidURL
}

View File

@@ -6,12 +6,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="/app/build/bundle.css">
<script>
window.__authorizer__ = {{.data}}
</script>
</head>
<body>
<div id="root"></div>
<script src="/app/build/bundle.js"></script>
<script>
window.__authorizer__ = {{.data}}
</script>
</body>
</html>