fix: add location middleware to get exact host

This commit is contained in:
Lakhan Samani 2021-08-04 15:55:13 +05:30
parent f88363e6dc
commit 104adfea1d
21 changed files with 102 additions and 70 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

14
app/package-lock.json generated
View File

@ -8,7 +8,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@authorizerdev/authorizer-react": "^0.1.0-beta.6",
"@authorizerdev/authorizer-react": "^0.1.0-beta.7",
"@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9",
"esbuild": "^0.12.17",
@ -22,9 +22,9 @@
}
},
"node_modules/@authorizerdev/authorizer-react": {
"version": "0.1.0-beta.6",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.1.0-beta.6.tgz",
"integrity": "sha512-2lmhpIz6e++FG9A5BPkenQZt79C6gn8K/Lq3i8E+u75umKvIoWgF9QYkvGlDtkBVyrkbnbA09RAVsXFTpF1+mg==",
"version": "0.1.0-beta.7",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.1.0-beta.7.tgz",
"integrity": "sha512-YPiDtmCchdY1uQLxv1GD1RQxnSn9g08/CK5HA4oRt5h0BNfGuK0c7dzMGVrmuX46YvZirPCMwE3ESIcXysS+Mg==",
"dependencies": {
"@urql/core": "^2.1.5",
"final-form": "^4.20.2",
@ -790,9 +790,9 @@
},
"dependencies": {
"@authorizerdev/authorizer-react": {
"version": "0.1.0-beta.6",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.1.0-beta.6.tgz",
"integrity": "sha512-2lmhpIz6e++FG9A5BPkenQZt79C6gn8K/Lq3i8E+u75umKvIoWgF9QYkvGlDtkBVyrkbnbA09RAVsXFTpF1+mg==",
"version": "0.1.0-beta.7",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.1.0-beta.7.tgz",
"integrity": "sha512-YPiDtmCchdY1uQLxv1GD1RQxnSn9g08/CK5HA4oRt5h0BNfGuK0c7dzMGVrmuX46YvZirPCMwE3ESIcXysS+Mg==",
"requires": {
"@urql/core": "^2.1.5",
"final-form": "^4.20.2",

View File

@ -10,7 +10,7 @@
"author": "Lakhan Samani",
"license": "ISC",
"dependencies": {
"@authorizerdev/authorizer-react": "^0.1.0-beta.6",
"@authorizerdev/authorizer-react": "^0.1.0-beta.7",
"@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9",
"esbuild": "^0.12.17",

View File

@ -6,7 +6,7 @@ import Login from './pages/login';
import ResetPassword from './pages/rest-password';
export default function Root() {
const { token, loading } = useAuthorizer();
const { token, loading, config } = useAuthorizer();
if (loading) {
return <h1>Loading...</h1>;

View File

@ -19,7 +19,7 @@ var (
REDIS_URL = ""
IS_PROD = false
COOKIE_NAME = ""
FORGOT_PASSWORD_URI = ""
RESET_PASSWORD_URL = ""
DISABLE_EMAIL_VERICATION = "false"
DISABLE_BASIC_AUTHENTICATION = "false"
VERIFY_EMAIL_URI = ""

View File

@ -63,7 +63,7 @@ func InitEnv() {
constants.FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET")
constants.TWITTER_CLIENT_ID = os.Getenv("TWITTER_CLIENT_ID")
constants.TWITTER_CLIENT_SECRET = os.Getenv("TWITTER_CLIENT_SECRET")
constants.FORGOT_PASSWORD_URI = strings.TrimPrefix(os.Getenv("FORGOT_PASSWORD_URI"), "/")
constants.RESET_PASSWORD_URL = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/")
constants.VERIFY_EMAIL_URI = strings.TrimPrefix(os.Getenv("VERIFY_EMAIL_URI"), "/")
constants.DISABLE_BASIC_AUTHENTICATION = os.Getenv("DISABLE_BASIC_AUTHENTICATION")
constants.DISABLE_EMAIL_VERICATION = os.Getenv("DISABLE_EMAIL_VERICATION")

View File

@ -4,6 +4,7 @@ go 1.16
require (
github.com/99designs/gqlgen v0.13.0
github.com/gin-contrib/location v0.0.2 // indirect
github.com/gin-gonic/gin v1.7.2
github.com/go-playground/validator/v10 v10.8.0 // indirect
github.com/go-redis/redis/v8 v8.11.0

View File

@ -114,8 +114,11 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=
github.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
@ -134,6 +137,7 @@ github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8c
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.8.0 h1:1kAa0fCrnpv+QYdkdcRzrRM7AyYs5o8+jZdJCz9xj6k=
github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=

View File

@ -5,7 +5,9 @@ import (
"encoding/json"
"log"
"net/http"
"strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/gin-gonic/gin"
)
@ -17,20 +19,20 @@ type State struct {
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
}
// 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"
stateObj.AuthorizerURL = constants.AUTHORIZER_URL
stateObj.RedirectURL = constants.AUTHORIZER_URL + "/app"
} else {
decodedState, err := base64.StdEncoding.DecodeString(state)
@ -44,6 +46,8 @@ func AppHandler() gin.HandlerFunc {
c.JSON(400, gin.H{"error": "[unable to parse state] invalid state"})
return
}
stateObj.AuthorizerURL = strings.TrimSuffix(stateObj.AuthorizerURL, "/")
stateObj.RedirectURL = strings.TrimSuffix(stateObj.RedirectURL, "/")
// validate redirect url with allowed origins
if !utils.IsValidRedirectURL(stateObj.RedirectURL) {
@ -57,7 +61,7 @@ func AppHandler() gin.HandlerFunc {
}
// validate host and domain of authorizer url
if utils.GetDomainName(stateObj.AuthorizerURL) != utils.GetDomainName(host) {
if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != constants.AUTHORIZER_URL {
c.JSON(400, gin.H{"error": "invalid host url"})
return
}
@ -65,7 +69,7 @@ func AppHandler() gin.HandlerFunc {
log.Println(gin.H{
"data": map[string]string{
"authorizerURL": "http://" + stateObj.AuthorizerURL,
"authorizerURL": stateObj.AuthorizerURL,
"redirectURL": stateObj.RedirectURL,
},
})

View File

@ -2,7 +2,6 @@ package handlers
import (
"github.com/99designs/gqlgen/graphql/handler"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph"
"github.com/authorizerdev/authorizer/server/graph/generated"
"github.com/gin-gonic/gin"
@ -15,9 +14,6 @@ func GraphqlHandler() gin.HandlerFunc {
h := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{}}))
return func(c *gin.Context) {
if constants.AUTHORIZER_URL == "" {
constants.AUTHORIZER_URL = "https://" + c.Request.Host
}
h.ServeHTTP(c.Writer, c.Request)
}
}

View File

@ -3,6 +3,7 @@ package handlers
import (
"net/http"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/oauth"
"github.com/authorizerdev/authorizer/server/session"
@ -31,10 +32,13 @@ func OAuthLoginHandler() gin.HandlerFunc {
switch provider {
case enum.Google.String():
session.SetToken(oauthStateString, enum.Google.String())
// during the init of OAuthProvider authorizer url might be empty
oauth.OAuthProvider.GoogleConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/google"
url := oauth.OAuthProvider.GoogleConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url)
case enum.Github.String():
session.SetToken(oauthStateString, enum.Github.String())
oauth.OAuthProvider.GithubConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/github"
url := oauth.OAuthProvider.GithubConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url)
default:

View File

@ -2,16 +2,26 @@ package main
import (
"context"
"fmt"
"log"
"strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/handlers"
"github.com/authorizerdev/authorizer/server/oauth"
"github.com/authorizerdev/authorizer/server/session"
"github.com/gin-contrib/location"
"github.com/gin-gonic/gin"
)
func GinContextToContextMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
if constants.AUTHORIZER_URL == "" {
url := location.Get(c)
constants.AUTHORIZER_URL = strings.TrimSuffix(fmt.Sprintf("%s", url), "/")
log.Println("=> setting url:", constants.AUTHORIZER_URL)
}
ctx := context.WithValue(c.Request.Context(), "GinContextKey", c)
c.Request = c.Request.WithContext(ctx)
c.Next()
@ -44,6 +54,7 @@ func main() {
oauth.InitOAuth()
r := gin.Default()
r.Use(location.Default())
r.Use(GinContextToContextMiddleware())
r.Use(CORSMiddleware())
@ -54,9 +65,14 @@ func main() {
r.GET("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler())
// login wall app related routes
r.Static("/app/build", "app/build")
r.LoadHTMLGlob("templates/*")
r.GET("/app", handlers.AppHandler())
app := r.Group("/app")
{
app.Static("/build", "app/build")
app.GET("/", handlers.AppHandler())
app.GET("/reset-password", handlers.AppHandler())
}
r.Run()
}

View File

@ -35,7 +35,7 @@ func ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*mod
return res, fmt.Errorf(`user with this email not found`)
}
token, err := utils.CreateVerificationToken(params.Email, enum.ForgotPassword.String(), host)
token, err := utils.CreateVerificationToken(params.Email, enum.ForgotPassword.String())
if err != nil {
log.Println(`Error generating token`, err)
}

View File

@ -13,25 +13,19 @@ import (
)
func ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx)
var res *model.Response
if err != nil {
return res, err
}
params.Email = strings.ToLower(params.Email)
if !utils.IsValidEmail(params.Email) {
return res, fmt.Errorf("invalid email")
}
host := gc.Request.Host
verificationRequest, err := db.Mgr.GetVerificationByEmail(params.Email)
if err != nil {
return res, fmt.Errorf(`verification request not found`)
}
token, err := utils.CreateVerificationToken(params.Email, verificationRequest.Identifier, host)
token, err := utils.CreateVerificationToken(params.Email, verificationRequest.Identifier)
if err != nil {
log.Println(`Error generating token`, err)
}

View File

@ -3,9 +3,11 @@ package resolvers
import (
"context"
"fmt"
"strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils"
)
@ -39,6 +41,12 @@ func ResetPassword(ctx context.Context, params model.ResetPassowrdInput) (*model
password, _ := utils.HashPassword(params.Password)
user.Password = password
signupMethod := user.SignupMethod
if !strings.Contains(signupMethod, enum.BasicAuth.String()) {
signupMethod = signupMethod + "," + enum.BasicAuth.String()
}
user.SignupMethod = signupMethod
// delete from verification table
db.Mgr.DeleteToken(claim.Email)
db.Mgr.UpdateUser(user)

View File

@ -84,7 +84,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
if constants.DISABLE_EMAIL_VERICATION != "true" {
// insert verification request
verificationType := enum.BasicAuthSignup.String()
token, err := utils.CreateVerificationToken(params.Email, verificationType, gc.Request.Host)
token, err := utils.CreateVerificationToken(params.Email, verificationType)
if err != nil {
log.Println(`Error generating token`, err)
}

View File

@ -105,7 +105,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
hasEmailChanged = true
// insert verification request
verificationType := enum.UpdateEmail.String()
token, err := utils.CreateVerificationToken(newEmail, verificationType, gc.Request.Host)
token, err := utils.CreateVerificationToken(newEmail, verificationType)
if err != nil {
log.Println(`Error generating token`, err)
}

View File

@ -12,7 +12,7 @@ func SetCookie(gc *gin.Context, token string) {
secure := true
httpOnly := true
host := GetHostName(gc.Request.Host)
host := GetHostName(constants.AUTHORIZER_URL)
log.Println("=> cookie 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 := GetHostName(gc.Request.Host)
host := GetHostName(constants.AUTHORIZER_URL)
gc.SetSameSite(http.SameSiteNoneMode)
gc.SetCookie(constants.COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
}

View File

@ -34,12 +34,17 @@ func SendVerificationMail(toEmail, token string) error {
// SendForgotPasswordMail to send verification email
func SendForgotPasswordMail(toEmail, token, host string) error {
if constants.RESET_PASSWORD_URL == "" {
constants.RESET_PASSWORD_URL = constants.AUTHORIZER_URL + "/app/reset-password"
}
sender := email.NewSender()
// The receiver needs to be in slice as the receive supports multiple receiver
Receiver := []string{toEmail}
Subject := "Reset Password"
message := fmt.Sprintf(`
<!DOCTYPE HTML PULBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
@ -51,7 +56,7 @@ func SendForgotPasswordMail(toEmail, token, host string) error {
<a href="%s">Reset Password</a>
</body>
</html>
`, host+"/"+constants.FORGOT_PASSWORD_URI+"?token="+token)
`, constants.RESET_PASSWORD_URL+"?token="+token)
bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
return sender.SendMail(Receiver, Subject, bodyMessage)

View File

@ -19,7 +19,7 @@ type CustomClaim struct {
}
// TODO convert tokenType to enum
func CreateVerificationToken(email string, tokenType string, host string) (string, error) {
func CreateVerificationToken(email string, tokenType string) (string, error) {
t := jwt.New(jwt.GetSigningMethod(constants.JWT_TYPE))
t.Claims = &CustomClaim{
@ -28,7 +28,7 @@ func CreateVerificationToken(email string, tokenType string, host string) (strin
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
},
tokenType,
UserInfo{Email: email, Host: host},
UserInfo{Email: email, Host: constants.AUTHORIZER_URL},
}
return t.SignedString([]byte(constants.JWT_SECRET))