feat: login wall (#42)

* feat: add login-wall app

* fix: rename vars

* fix: rename vars

* update docker file

* add validations for app state

* add host check for app

* fix: docker file
This commit is contained in:
Lakhan Samani
2021-08-04 12:18:57 +05:30
committed by GitHub
parent d1973c1f8f
commit f88363e6dc
41 changed files with 2274 additions and 120 deletions

87
server/handlers/app.go Normal file
View File

@@ -0,0 +1,87 @@
package handlers
import (
"encoding/base64"
"encoding/json"
"log"
"net/http"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/gin-gonic/gin"
)
type State struct {
AuthorizerURL string `json:"authorizerURL"`
RedirectURL string `json:"redirectURL"`
}
func AppHandler() gin.HandlerFunc {
return func(c *gin.Context) {
host := "http://" + c.Request.Host
state := c.Query("state")
var stateObj State
if state == "" {
cookie, err := utils.GetAuthToken(c)
log.Println(`cookie`, cookie)
if err != nil {
c.JSON(400, gin.H{"error": "invalid state"})
return
}
stateObj.AuthorizerURL = host
stateObj.RedirectURL = host + "/app"
} else {
decodedState, err := base64.StdEncoding.DecodeString(state)
if err != nil {
c.JSON(400, gin.H{"error": "[unable to decode state] invalid state"})
return
}
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
}
if stateObj.AuthorizerURL == "" {
c.JSON(400, gin.H{"error": "invalid authorizer url"})
return
}
// 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
}
}
log.Println(gin.H{
"data": map[string]string{
"authorizerURL": "http://" + stateObj.AuthorizerURL,
"redirectURL": stateObj.RedirectURL,
},
})
// debug the request state
if pusher := c.Writer.Pusher(); pusher != nil {
// use pusher.Push() to do server push
if err := pusher.Push("/app/build/bundle.js", nil); err != nil {
log.Printf("Failed to push: %v", err)
}
}
c.HTML(http.StatusOK, "app.tmpl", gin.H{
"data": map[string]string{
"authorizerURL": stateObj.AuthorizerURL,
"redirectURL": stateObj.RedirectURL,
},
})
}
}

View File

@@ -15,8 +15,8 @@ func GraphqlHandler() gin.HandlerFunc {
h := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{}}))
return func(c *gin.Context) {
if constants.AUTHORIZER_DOMAIN == "" {
constants.AUTHORIZER_DOMAIN = "https://" + c.Request.Host
if constants.AUTHORIZER_URL == "" {
constants.AUTHORIZER_URL = "https://" + c.Request.Host
}
h.ServeHTTP(c.Writer, c.Request)
}

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
"time"
@@ -18,12 +19,7 @@ import (
"golang.org/x/oauth2"
)
func processGoogleUserInfo(state string, code string, c *gin.Context) error {
sessionState := session.GetToken(state)
if sessionState == "" {
return fmt.Errorf("invalid oauth state")
}
session.DeleteToken(sessionState)
func processGoogleUserInfo(code string, c *gin.Context) error {
token, err := oauth.OAuthProvider.GoogleConfig.Exchange(oauth2.NoContext, code)
if err != nil {
return fmt.Errorf("invalid google exchange code: %s", err.Error())
@@ -82,12 +78,7 @@ func processGoogleUserInfo(state string, code string, c *gin.Context) error {
return nil
}
func processGithubUserInfo(state string, code string, c *gin.Context) error {
sessionState := session.GetToken(state)
if sessionState == "" {
return fmt.Errorf("invalid oauth state")
}
session.DeleteToken(sessionState)
func processGithubUserInfo(code string, c *gin.Context) error {
token, err := oauth.OAuthProvider.GithubConfig.Exchange(oauth2.NoContext, code)
if err != nil {
return fmt.Errorf("invalid google exchange code: %s", err.Error())
@@ -165,21 +156,38 @@ func processGithubUserInfo(state string, code string, c *gin.Context) error {
func OAuthCallbackHandler() gin.HandlerFunc {
return func(c *gin.Context) {
log.Println("url:", c.Request.URL)
provider := c.Param("oauth_provider")
state := c.Request.FormValue("state")
log.Println("session state", state)
sessionState := session.GetToken(state)
if sessionState == "" {
c.JSON(400, gin.H{"error": "invalid oauth state"})
}
session.DeleteToken(sessionState)
sessionSplit := strings.Split(state, "___")
log.Println(sessionSplit)
// TODO validate redirect url
if len(sessionSplit) != 2 {
c.JSON(400, gin.H{"error": "invalid redirect url"})
return
}
var err error
code := c.Request.FormValue("code")
switch provider {
case enum.Google.String():
err = processGoogleUserInfo(c.Request.FormValue("state"), c.Request.FormValue("code"), c)
err = processGoogleUserInfo(code, c)
case enum.Github.String():
err = processGithubUserInfo(c.Request.FormValue("state"), c.Request.FormValue("code"), c)
err = processGithubUserInfo(code, c)
default:
err = fmt.Errorf(`invalid oauth provider`)
}
if err != nil {
c.Redirect(http.StatusTemporaryRedirect, constants.FRONTEND_URL+"?error="+err.Error())
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.Redirect(http.StatusTemporaryRedirect, constants.FRONTEND_URL)
c.Redirect(http.StatusTemporaryRedirect, sessionSplit[1])
}
}

View File

@@ -10,11 +10,22 @@ import (
"github.com/google/uuid"
)
func OAuthLoginHandler() gin.HandlerFunc {
uuid := uuid.New()
oauthStateString := uuid.String()
// set host in the oauth state that is useful for redirecting
func OAuthLoginHandler() gin.HandlerFunc {
return func(c *gin.Context) {
// TODO validate redirect URL
redirectURL := c.Query("redirectURL")
if redirectURL == "" {
c.JSON(400, gin.H{
"error": "invalid redirect url",
})
return
}
uuid := uuid.New()
oauthStateString := uuid.String() + "___" + redirectURL
provider := c.Param("oauth_provider")
switch provider {

View File

@@ -5,7 +5,6 @@ import (
"net/http"
"time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/session"
@@ -63,6 +62,6 @@ func VerifyEmailHandler() gin.HandlerFunc {
session.SetToken(userIdStr, refreshToken)
utils.SetCookie(c, accessToken)
c.Redirect(http.StatusTemporaryRedirect, constants.FRONTEND_URL)
c.Redirect(http.StatusTemporaryRedirect, claim.Host)
}
}