Feat/dashboard (#105)

This commit is contained in:
Lakhan Samani
2022-01-17 11:32:13 +05:30
committed by GitHub
parent 7ce96367a3
commit f1b4141367
120 changed files with 3381 additions and 3044 deletions

View File

@@ -11,17 +11,19 @@ import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"github.com/robertkrimen/otto"
"golang.org/x/crypto/bcrypt"
)
func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (string, int64, error) {
t := jwt.New(jwt.GetSigningMethod(constants.EnvData.JWT_TYPE))
// CreateAuthToken util to create JWT token, based on
// user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT
func CreateAuthToken(user db.User, tokenType string, roles []string) (string, int64, error) {
t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyJwtType).(string)))
expiryBound := time.Hour
if tokenType == enum.RefreshToken {
if tokenType == constants.TokenTypeRefreshToken {
// expires in 1 year
expiryBound = time.Hour * 8760
}
@@ -33,12 +35,13 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st
var userMap map[string]interface{}
json.Unmarshal(userBytes, &userMap)
claimKey := envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyJwtRoleClaim).(string)
customClaims := jwt.MapClaims{
"exp": expiresAt,
"iat": time.Now().Unix(),
"token_type": tokenType.String(),
"allowed_roles": strings.Split(user.Roles, ","),
constants.EnvData.JWT_ROLE_CLAIM: roles,
"exp": expiresAt,
"iat": time.Now().Unix(),
"token_type": tokenType,
"allowed_roles": strings.Split(user.Roles, ","),
claimKey: roles,
}
for k, v := range userMap {
@@ -48,7 +51,7 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st
}
// check for the extra access token script
accessTokenScript := os.Getenv("CUSTOM_ACCESS_TOKEN_SCRIPT")
accessTokenScript := os.Getenv(constants.EnvKeyCustomAccessTokenScript)
if accessTokenScript != "" {
vm := otto.New()
@@ -79,7 +82,7 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st
t.Claims = customClaims
token, err := t.SignedString([]byte(constants.EnvData.JWT_SECRET))
token, err := t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyJwtSecret).(string)))
if err != nil {
return "", 0, err
}
@@ -87,6 +90,8 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st
return token, expiresAt, nil
}
// GetAuthToken helps in getting the JWT token from the
// request cookie or authorization header
func GetAuthToken(gc *gin.Context) (string, error) {
token, err := GetCookie(gc)
if err != nil || token == "" {
@@ -101,12 +106,13 @@ func GetAuthToken(gc *gin.Context) (string, error) {
return token, nil
}
// VerifyAuthToken helps in verifying the JWT token
func VerifyAuthToken(token string) (map[string]interface{}, error) {
var res map[string]interface{}
claims := jwt.MapClaims{}
_, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
return []byte(constants.EnvData.JWT_SECRET), nil
return []byte(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyJwtSecret).(string)), nil
})
if err != nil {
return res, err
@@ -126,10 +132,12 @@ func VerifyAuthToken(token string) (map[string]interface{}, error) {
return res, nil
}
func CreateAdminAuthToken(tokenType enum.TokenType, c *gin.Context) (string, error) {
return HashPassword(constants.EnvData.ADMIN_SECRET)
// CreateAdminAuthToken creates the admin token based on secret key
func CreateAdminAuthToken(tokenType string, c *gin.Context) (string, error) {
return EncryptPassword(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
}
// GetAdminAuthToken helps in getting the admin token from the request cookie
func GetAdminAuthToken(gc *gin.Context) (string, error) {
token, err := GetAdminCookie(gc)
if err != nil || token == "" {
@@ -143,7 +151,7 @@ func GetAdminAuthToken(gc *gin.Context) (string, error) {
return "", err
}
err = bcrypt.CompareHashAndPassword([]byte(decodedValue), []byte(constants.EnvData.ADMIN_SECRET))
err = bcrypt.CompareHashAndPassword([]byte(decodedValue), []byte(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string)))
log.Println("error comparing hash:", err)
if err != nil {
return "", fmt.Errorf(`unauthorized`)

View File

@@ -1,24 +1,11 @@
package utils
import (
"io"
"os"
"github.com/authorizerdev/authorizer/server/db"
"github.com/gin-gonic/gin"
)
func WriteToFile(filename string, data string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
_, err = io.WriteString(file, data)
if err != nil {
return err
}
return file.Sync()
}
// StringSliceContains checks if a string slice contains a particular string
func StringSliceContains(s []string, e string) bool {
for _, a := range s {
if a == e {
@@ -27,3 +14,15 @@ func StringSliceContains(s []string, e string) bool {
}
return false
}
// SaveSessionInDB saves sessions generated for a given user with meta information
// Not store token here as that could be security breach
func SaveSessionInDB(userId string, c *gin.Context) {
sessionData := db.Session{
UserID: userId,
UserAgent: GetUserAgent(c.Request),
IP: GetIP(c.Request),
}
db.Mgr.AddSession(sessionData)
}

View File

@@ -4,27 +4,33 @@ import (
"net/http"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/gin-gonic/gin"
)
// SetCookie sets the cookie in the response. It sets 2 cookies
// 1 COOKIE_NAME for the host (abc.com)
// 2 COOKIE_NAME-client for the domain (sub.abc.com).
// Note all sites don't allow 2nd type of cookie
func SetCookie(gc *gin.Context, token string) {
secure := true
httpOnly := true
host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
domain := GetDomainName(constants.EnvData.AUTHORIZER_URL)
host, _ := GetHostParts(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string))
domain := GetDomainName(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string))
if domain != "localhost" {
domain = "." + domain
}
gc.SetSameSite(http.SameSiteNoneMode)
gc.SetCookie(constants.EnvData.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
gc.SetCookie(constants.EnvData.COOKIE_NAME+"-client", token, 3600, "/", domain, secure, httpOnly)
gc.SetCookie(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string), token, 3600, "/", host, secure, httpOnly)
gc.SetCookie(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string)+"-client", token, 3600, "/", domain, secure, httpOnly)
}
// GetCookie gets the cookie from the request
func GetCookie(gc *gin.Context) (string, error) {
cookie, err := gc.Request.Cookie(constants.EnvData.COOKIE_NAME)
cookie, err := gc.Request.Cookie(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string))
if err != nil {
cookie, err = gc.Request.Cookie(constants.EnvData.COOKIE_NAME + "-client")
cookie, err = gc.Request.Cookie(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string) + "-client")
if err != nil {
return "", err
}
@@ -33,31 +39,33 @@ func GetCookie(gc *gin.Context) (string, error) {
return cookie.Value, nil
}
// DeleteCookie sets the cookie value as empty to make it expired
func DeleteCookie(gc *gin.Context) {
secure := true
httpOnly := true
host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
domain := GetDomainName(constants.EnvData.AUTHORIZER_URL)
host, _ := GetHostParts(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string))
domain := GetDomainName(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string))
if domain != "localhost" {
domain = "." + domain
}
gc.SetSameSite(http.SameSiteNoneMode)
gc.SetCookie(constants.EnvData.COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
gc.SetCookie(constants.EnvData.COOKIE_NAME+"-client", "", -1, "/", domain, secure, httpOnly)
gc.SetCookie(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string), "", -1, "/", host, secure, httpOnly)
gc.SetCookie(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string)+"-client", "", -1, "/", domain, secure, httpOnly)
}
// SetAdminCookie sets the admin cookie in the response
func SetAdminCookie(gc *gin.Context, token string) {
secure := true
httpOnly := true
host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
host, _ := GetHostParts(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string))
gc.SetCookie(constants.EnvData.ADMIN_COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
gc.SetCookie(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminCookieName).(string), token, 3600, "/", host, secure, httpOnly)
}
func GetAdminCookie(gc *gin.Context) (string, error) {
cookie, err := gc.Request.Cookie(constants.EnvData.ADMIN_COOKIE_NAME)
cookie, err := gc.Request.Cookie(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminCookieName).(string))
if err != nil {
return "", err
}
@@ -67,7 +75,7 @@ func GetAdminCookie(gc *gin.Context) (string, error) {
func DeleteAdminCookie(gc *gin.Context) {
secure := true
httpOnly := true
host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
host, _ := GetHostParts(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string))
gc.SetCookie(constants.EnvData.ADMIN_COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
gc.SetCookie(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminCookieName).(string), "", -1, "/", host, secure, httpOnly)
}

View File

@@ -1,16 +0,0 @@
package utils
import (
"github.com/authorizerdev/authorizer/server/db"
"github.com/gin-gonic/gin"
)
func CreateSession(userId string, c *gin.Context) {
sessionData := db.Session{
UserID: userId,
UserAgent: GetUserAgent(c.Request),
IP: GetIP(c.Request),
}
db.Mgr.AddSession(sessionData)
}

View File

@@ -5,15 +5,20 @@ import (
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"encoding/json"
"io"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"golang.org/x/crypto/bcrypt"
)
// EncryptB64 encrypts data into base64 string
func EncryptB64(text string) string {
return base64.StdEncoding.EncodeToString([]byte(text))
}
// DecryptB64 decrypts from base64 string to readable string
func DecryptB64(s string) (string, error) {
data, err := base64.StdEncoding.DecodeString(s)
if err != nil {
@@ -22,8 +27,9 @@ func DecryptB64(s string) (string, error) {
return string(data), nil
}
// EncryptAES encrypts data using AES algorithm
func EncryptAES(text []byte) ([]byte, error) {
key := []byte(constants.EnvData.ENCRYPTION_KEY)
key := []byte(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyEncryptionKey).(string))
c, err := aes.NewCipher(key)
var res []byte
if err != nil {
@@ -55,8 +61,9 @@ func EncryptAES(text []byte) ([]byte, error) {
return gcm.Seal(nonce, nonce, text, nil), nil
}
// DecryptAES decrypts data using AES algorithm
func DecryptAES(ciphertext []byte) ([]byte, error) {
key := []byte(constants.EnvData.ENCRYPTION_KEY)
key := []byte(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyEncryptionKey).(string))
c, err := aes.NewCipher(key)
var res []byte
if err != nil {
@@ -81,3 +88,39 @@ func DecryptAES(ciphertext []byte) ([]byte, error) {
return plaintext, nil
}
// EncryptEnvData is used to encrypt the env data
func EncryptEnvData(data map[string]interface{}) ([]byte, error) {
jsonBytes, err := json.Marshal(data)
if err != nil {
return []byte{}, err
}
envStoreObj := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
err = json.Unmarshal(jsonBytes, &envStoreObj)
if err != nil {
return []byte{}, err
}
configData, err := json.Marshal(envStoreObj)
if err != nil {
return []byte{}, err
}
encryptedConfig, err := EncryptAES(configData)
if err != nil {
return []byte{}, err
}
return encryptedConfig, nil
}
// EncryptPassword is used for encrypting password
func EncryptPassword(password string) (string, error) {
pw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(pw), nil
}

View File

@@ -1,231 +0,0 @@
package utils
import (
"bytes"
"encoding/json"
"html/template"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/email"
)
// SendVerificationMail to send verification email
func SendVerificationMail(toEmail, token string) error {
// The receiver needs to be in slice as the receive supports multiple receiver
Receiver := []string{toEmail}
Subject := "Please verify your email"
message := `
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<meta name="x-apple-disable-message-reformatting">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="telephone=no" name="format-detection">
<title></title>
<!--[if (mso 16)]>
<style type="text/css">
a {}
</style>
<![endif]-->
<!--[if gte mso 9]><style>sup { font-size: 100%% !important; }</style><![endif]-->
<!--[if gte mso 9]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG></o:AllowPNG>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
</head>
<body style="font-family: sans-serif;">
<div class="es-wrapper-color">
<!--[if gte mso 9]>
<v:background xmlns:v="urn:schemas-microsoft-com:vml" fill="t">
<v:fill type="tile" color="#ffffff"></v:fill>
</v:background>
<![endif]-->
<table class="es-wrapper" width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-email-paddings" valign="top">
<table class="es-content esd-footer-popover" cellspacing="0" cellpadding="0" align="center">
<tbody>
<tr>
<td class="esd-stripe" align="center">
<table class="es-content-body" style="border-left:1px solid transparent;border-right:1px solid transparent;border-top:1px solid transparent;border-bottom:1px solid transparent;padding:20px 0px;" width="600" cellspacing="0" cellpadding="0" bgcolor="#ffffff" align="center">
<tbody>
<tr>
<td class="esd-structure es-p20t es-p40b es-p40r es-p40l" esd-custom-block-id="8537" align="left">
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-container-frame" width="518" align="left">
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.OrgLogo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
</tr>
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
<p>Hey there 👋</p>
<p>We have received request to verify email for <b>{{.OrgName}}</b>. If this is correct, please confirm your email address by clicking the button below.</p> <br/>
<a
clicktracking="off" href="{{.AuthUrl}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Confirm Email</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
</body>
</html>
`
data := make(map[string]interface{}, 3)
data["OrgLogo"] = constants.EnvData.ORGANIZATION_LOGO
data["OrgName"] = constants.EnvData.ORGANIZATION_NAME
data["AuthUrl"] = constants.EnvData.AUTHORIZER_URL + "/verify_email?token=" + token
message = AddEmailTemplate(message, data, "verify_email.tmpl")
// bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
return email.SendMail(Receiver, Subject, message)
}
// SendForgotPasswordMail to send verification email
func SendForgotPasswordMail(toEmail, token, host string) error {
if constants.EnvData.RESET_PASSWORD_URL == "" {
constants.EnvData.RESET_PASSWORD_URL = constants.EnvData.AUTHORIZER_URL + "/app/reset-password"
}
// The receiver needs to be in slice as the receive supports multiple receiver
Receiver := []string{toEmail}
Subject := "Reset Password"
message := `
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<meta name="x-apple-disable-message-reformatting">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="telephone=no" name="format-detection">
<title></title>
<!--[if (mso 16)]>
<style type="text/css">
a {}
</style>
<![endif]-->
<!--[if gte mso 9]><style>sup { font-size: 100%% !important; }</style><![endif]-->
<!--[if gte mso 9]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG></o:AllowPNG>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
</head>
<body style="font-family: sans-serif;">
<div class="es-wrapper-color">
<!--[if gte mso 9]>
<v:background xmlns:v="urn:schemas-microsoft-com:vml" fill="t">
<v:fill type="tile" color="#ffffff"></v:fill>
</v:background>
<![endif]-->
<table class="es-wrapper" width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-email-paddings" valign="top">
<table class="es-content esd-footer-popover" cellspacing="0" cellpadding="0" align="center">
<tbody>
<tr>
<td class="esd-stripe" align="center">
<table class="es-content-body" style="border-left:1px solid transparent;border-right:1px solid transparent;border-top:1px solid transparent;border-bottom:1px solid transparent;padding:20px 0px;" width="600" cellspacing="0" cellpadding="0" bgcolor="#ffffff" align="center">
<tbody>
<tr>
<td class="esd-structure es-p20t es-p40b es-p40r es-p40l" esd-custom-block-id="8537" align="left">
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-container-frame" width="518" align="left">
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.OrgLogo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
</tr>
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
<p>Hey there 👋</p>
<p>We have received a request to reset password for email: <b>{{.ToEmail}}</b>. If this is correct, please reset the password clicking the button below.</p> <br/>
<a clicktracking="off" href="{{.AuthUrl}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Reset Password</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
</body>
</html>
`
data := make(map[string]interface{}, 3)
data["OrgLogo"] = constants.EnvData.ORGANIZATION_LOGO
data["ToEmail"] = constants.EnvData.ORGANIZATION_NAME
data["AuthUrl"] = constants.EnvData.RESET_PASSWORD_URL + "?token=" + token
message = AddEmailTemplate(message, data, "reset_password_email.tmpl")
return email.SendMail(Receiver, Subject, message)
}
func AddEmailTemplate(a string, b map[string]interface{}, templateName string) string {
tmpl, err := template.New(templateName).Parse(a)
if err != nil {
output, _ := json.Marshal(b)
return string(output)
}
buf := &bytes.Buffer{}
err = tmpl.Execute(buf, b)
if err != nil {
panic(err)
}
s := buf.String()
return s
}

View File

@@ -3,7 +3,7 @@ package utils
import (
"encoding/json"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
)
func EncryptConfig(data map[string]interface{}) ([]byte, error) {
@@ -12,12 +12,14 @@ func EncryptConfig(data map[string]interface{}) ([]byte, error) {
return []byte{}, err
}
err = json.Unmarshal(jsonBytes, &constants.EnvData)
envData := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
err = json.Unmarshal(jsonBytes, &envData)
if err != nil {
return []byte{}, err
}
configData, err := json.Marshal(constants.EnvData)
configData, err := json.Marshal(envData)
if err != nil {
return []byte{}, err
}

View File

@@ -7,6 +7,9 @@ import (
"github.com/authorizerdev/authorizer/server/graph/model"
)
// TODO move this to provider
// rename it to AsAPIUser
func GetResponseUserData(user db.User) *model.User {
isEmailVerified := user.EmailVerifiedAt != nil
isPhoneVerified := user.PhoneNumberVerifiedAt != nil

View File

@@ -7,6 +7,9 @@ import (
"github.com/gin-gonic/gin"
)
// TODO renamae GinContextKey -> GinContext
// GinContext to get gin context from context
func GinContextFromContext(ctx context.Context) (*gin.Context, error) {
ginContext := ctx.Value("GinContextKey")
if ginContext == nil {

View File

@@ -1,12 +0,0 @@
package utils
import "golang.org/x/crypto/bcrypt"
func HashPassword(password string) (string, error) {
pw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(pw), nil
}

View File

@@ -1,6 +0,0 @@
package utils
// any jobs that we want to run at start of server can be executed here
func InitServer() {
}

View File

@@ -2,19 +2,19 @@ package utils
import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model"
)
// GetMeta helps in getting the meta data about the deployment
// version,
// GetMeta helps in getting the meta data about the deployment from EnvData
func GetMetaInfo() model.Meta {
return model.Meta{
Version: constants.VERSION,
IsGoogleLoginEnabled: constants.GOOGLE_CLIENT_ID != "" && constants.GOOGLE_CLIENT_SECRET != "",
IsGithubLoginEnabled: constants.GITHUB_CLIENT_ID != "" && constants.GITHUB_CLIENT_SECRET != "",
IsFacebookLoginEnabled: constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "",
IsBasicAuthenticationEnabled: !constants.DISABLE_BASIC_AUTHENTICATION,
IsEmailVerificationEnabled: !constants.DISABLE_EMAIL_VERIFICATION,
IsMagicLinkLoginEnabled: !constants.DISABLE_MAGIC_LINK_LOGIN,
Version: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyVersion).(string),
IsGoogleLoginEnabled: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGoogleClientID).(string) != "" && envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGoogleClientSecret).(string) != "",
IsGithubLoginEnabled: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGithubClientID).(string) != "" && envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGithubClientSecret).(string) != "",
IsFacebookLoginEnabled: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyFacebookClientID).(string) != "" && envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyFacebookClientSecret).(string) != "",
IsBasicAuthenticationEnabled: !envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableBasicAuthentication).(bool),
IsEmailVerificationEnabled: !envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableEmailVerification).(bool),
IsMagicLinkLoginEnabled: !envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableMagicLinkLogin).(bool),
}
}

View File

@@ -2,6 +2,7 @@ package utils
import "net/http"
// GetIP helps in getting the IP address from the request
func GetIP(r *http.Request) string {
IPAddress := r.Header.Get("X-Real-Ip")
if IPAddress == "" {
@@ -14,6 +15,7 @@ func GetIP(r *http.Request) string {
return IPAddress
}
// GetUserAgent helps in getting the user agent from the request
func GetUserAgent(r *http.Request) string {
return r.UserAgent()
}

View File

@@ -6,17 +6,20 @@ import (
"strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/gin-gonic/gin"
)
// IsValidEmail validates email
func IsValidEmail(email string) bool {
_, err := mail.ParseAddress(email)
return err == nil
}
// IsValidOrigin validates origin based on ALLOWED_ORIGINS
func IsValidOrigin(url string) bool {
if len(constants.EnvData.ALLOWED_ORIGINS) == 1 && constants.EnvData.ALLOWED_ORIGINS[0] == "*" {
allowedOrigins := envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAllowedOrigins).([]string)
if len(allowedOrigins) == 1 && allowedOrigins[0] == "*" {
return true
}
@@ -24,7 +27,7 @@ func IsValidOrigin(url string) bool {
hostName, port := GetHostParts(url)
currentOrigin := hostName + ":" + port
for _, origin := range constants.EnvData.ALLOWED_ORIGINS {
for _, origin := range allowedOrigins {
replacedString := origin
// if has regex whitelisted domains
if strings.Contains(origin, "*") {
@@ -49,6 +52,7 @@ func IsValidOrigin(url string) bool {
return hasValidURL
}
// IsSuperAdmin checks if user is super admin
func IsSuperAdmin(gc *gin.Context) bool {
token, err := GetAdminAuthToken(gc)
if err != nil {
@@ -57,12 +61,13 @@ func IsSuperAdmin(gc *gin.Context) bool {
return false
}
return secret == constants.EnvData.ADMIN_SECRET
return secret == envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string)
}
return token != ""
}
// IsValidRoles validates roles
func IsValidRoles(userRoles []string, roles []string) bool {
valid := true
for _, role := range roles {
@@ -75,13 +80,17 @@ func IsValidRoles(userRoles []string, roles []string) bool {
return valid
}
// IsValidVerificationIdentifier validates verification identifier that is used to identify
// the type of verification request
func IsValidVerificationIdentifier(identifier string) bool {
if identifier != enum.BasicAuthSignup.String() && identifier != enum.ForgotPassword.String() && identifier != enum.UpdateEmail.String() {
if identifier != constants.VerificationTypeBasicAuthSignup && identifier != constants.VerificationTypeForgotPassword && identifier != constants.VerificationTypeUpdateEmail {
return false
}
return true
}
// IsStringArrayEqual validates if string array are equal.
// This does check if the order is same
func IsStringArrayEqual(a, b []string) bool {
if len(a) != len(b) {
return false

View File

@@ -4,39 +4,46 @@ import (
"time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/golang-jwt/jwt"
)
// TODO see if we can move this to different service
// UserInfo is the user info that is stored in the JWT of verification request
type UserInfo struct {
Email string `json:"email"`
Host string `json:"host"`
RedirectURL string `json:"redirect_url"`
}
// CustomClaim is the custom claim that is stored in the JWT of verification request
type CustomClaim struct {
*jwt.StandardClaims
TokenType string `json:"token_type"`
UserInfo
}
// CreateVerificationToken creates a verification JWT token
func CreateVerificationToken(email string, tokenType string) (string, error) {
t := jwt.New(jwt.GetSigningMethod(constants.EnvData.JWT_TYPE))
t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyJwtType).(string)))
t.Claims = &CustomClaim{
&jwt.StandardClaims{
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
},
tokenType,
UserInfo{Email: email, Host: constants.EnvData.AUTHORIZER_URL, RedirectURL: constants.EnvData.APP_URL},
UserInfo{Email: email, Host: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string), RedirectURL: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAppURL).(string)},
}
return t.SignedString([]byte(constants.EnvData.JWT_SECRET))
return t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyJwtSecret).(string)))
}
// VerifyVerificationToken verifies the verification JWT token
func VerifyVerificationToken(token string) (*CustomClaim, error) {
claims := &CustomClaim{}
_, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
return []byte(constants.EnvData.JWT_SECRET), nil
return []byte(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyJwtSecret).(string)), nil
})
if err != nil {
return claims, err