add validations for app state
This commit is contained in:
BIN
build/server
BIN
build/server
Binary file not shown.
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@@ -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`)
|
||||
}
|
||||
|
@@ -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{
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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>
|
Reference in New Issue
Block a user