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
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO read query param = state which is base64 encoded
|
type State struct {
|
||||||
// make sure url is present in allowed origins
|
AuthorizerURL string `json:"authorizerURL"`
|
||||||
// set that in redirect_url
|
RedirectURL string `json:"redirectURL"`
|
||||||
|
}
|
||||||
|
|
||||||
func AppHandler() gin.HandlerFunc {
|
func AppHandler() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
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
|
// debug the request state
|
||||||
if pusher := c.Writer.Pusher(); pusher != nil {
|
if pusher := c.Writer.Pusher(); pusher != nil {
|
||||||
// use pusher.Push() to do server push
|
// use pusher.Push() to do server push
|
||||||
@@ -22,8 +59,8 @@ func AppHandler() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
c.HTML(http.StatusOK, "app.tmpl", gin.H{
|
c.HTML(http.StatusOK, "app.tmpl", gin.H{
|
||||||
"data": map[string]string{
|
"data": map[string]string{
|
||||||
"authorizerURL": c.Request.Host,
|
"authorizerURL": stateObj.AuthorizerURL,
|
||||||
"redirect_url": "http://localhost:8080/app",
|
"redirectURL": stateObj.RedirectURL,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -174,11 +174,12 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
code := c.Request.FormValue("code")
|
||||||
switch provider {
|
switch provider {
|
||||||
case enum.Google.String():
|
case enum.Google.String():
|
||||||
err = processGoogleUserInfo(c.Request.FormValue("code"), c)
|
err = processGoogleUserInfo(code, c)
|
||||||
case enum.Github.String():
|
case enum.Github.String():
|
||||||
err = processGithubUserInfo(c.Request.FormValue("code"), c)
|
err = processGithubUserInfo(code, c)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf(`invalid oauth provider`)
|
err = fmt.Errorf(`invalid oauth provider`)
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,7 @@ import (
|
|||||||
func OAuthLoginHandler() gin.HandlerFunc {
|
func OAuthLoginHandler() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
// TODO validate redirect URL
|
// TODO validate redirect URL
|
||||||
redirectURL := c.Query("redirect_url")
|
redirectURL := c.Query("redirectURL")
|
||||||
|
|
||||||
if redirectURL == "" {
|
if redirectURL == "" {
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
|
@@ -12,7 +12,7 @@ func SetCookie(gc *gin.Context, token string) {
|
|||||||
secure := true
|
secure := true
|
||||||
httpOnly := true
|
httpOnly := true
|
||||||
|
|
||||||
host := GetDomainName(gc.Request.Host)
|
host := GetHostName(gc.Request.Host)
|
||||||
log.Println("=> host", host)
|
log.Println("=> host", host)
|
||||||
gc.SetSameSite(http.SameSiteNoneMode)
|
gc.SetSameSite(http.SameSiteNoneMode)
|
||||||
gc.SetCookie(constants.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
|
gc.SetCookie(constants.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
|
||||||
@@ -35,7 +35,7 @@ func DeleteCookie(gc *gin.Context) {
|
|||||||
secure = false
|
secure = false
|
||||||
}
|
}
|
||||||
|
|
||||||
host := GetDomainName(gc.Request.Host)
|
host := GetHostName(gc.Request.Host)
|
||||||
gc.SetSameSite(http.SameSiteNoneMode)
|
gc.SetSameSite(http.SameSiteNoneMode)
|
||||||
gc.SetCookie(constants.COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
|
gc.SetCookie(constants.COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// function to get hostname
|
// function to get hostname
|
||||||
func GetDomainName(auth_url string) string {
|
func GetHostName(auth_url string) string {
|
||||||
u, err := url.Parse("//" + auth_url)
|
u, err := url.Parse("//" + auth_url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return `localhost`
|
return `localhost`
|
||||||
@@ -13,25 +15,38 @@ func GetDomainName(auth_url string) string {
|
|||||||
|
|
||||||
host := u.Hostname()
|
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
|
// code to get root domain in case of sub-domains
|
||||||
// hostParts := strings.Split(host, ".")
|
hostParts := strings.Split(host, ".")
|
||||||
// hostPartsLen := len(hostParts)
|
hostPartsLen := len(hostParts)
|
||||||
|
|
||||||
// if hostPartsLen == 1 {
|
if hostPartsLen == 1 {
|
||||||
// return host
|
return host
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if hostPartsLen == 2 {
|
if hostPartsLen == 2 {
|
||||||
// if hostParts[0] == "www" {
|
if hostParts[0] == "www" {
|
||||||
// return hostParts[1]
|
return hostParts[1]
|
||||||
// } else {
|
} else {
|
||||||
// return host
|
return host
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if hostPartsLen > 2 {
|
if hostPartsLen > 2 {
|
||||||
// return strings.Join(hostParts[hostPartsLen-2:], ".")
|
return strings.Join(hostParts[hostPartsLen-2:], ".")
|
||||||
// }
|
}
|
||||||
|
|
||||||
return host
|
return host
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,31 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "net/mail"
|
import (
|
||||||
|
"net/mail"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
)
|
||||||
|
|
||||||
func IsValidEmail(email string) bool {
|
func IsValidEmail(email string) bool {
|
||||||
_, err := mail.ParseAddress(email)
|
_, err := mail.ParseAddress(email)
|
||||||
return err == nil
|
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" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Document</title>
|
<title>Document</title>
|
||||||
<link rel="stylesheet" href="/app/build/bundle.css">
|
<link rel="stylesheet" href="/app/build/bundle.css">
|
||||||
|
<script>
|
||||||
|
window.__authorizer__ = {{.data}}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script src="/app/build/bundle.js"></script>
|
<script src="/app/build/bundle.js"></script>
|
||||||
<script>
|
|
||||||
window.__authorizer__ = {{.data}}
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Reference in New Issue
Block a user