feat: add support for database cert, key, ca-cert

This commit is contained in:
Lakhan Samani 2022-04-23 17:52:02 +05:30
parent 4778827545
commit 075c287f34
12 changed files with 163 additions and 35 deletions

View File

@ -9,3 +9,4 @@ build
data.db
app/node_modules
app/build
certs/

3
.gitignore vendored
View File

@ -13,4 +13,5 @@ data.db
*.tar.gz
.vscode/
.yalc
yalc.lock
yalc.lock
certs/

View File

@ -38,6 +38,12 @@ const (
EnvKeyDatabasePort = "DATABASE_PORT"
// EnvKeyDatabaseHost key for env variable DATABASE_HOST
EnvKeyDatabaseHost = "DATABASE_HOST"
// EnvKeyDatabaseCert key for env variable DATABASE_CERT
EnvKeyDatabaseCert = "DATABASE_CERT"
// EnvKeyDatabaseCertKey key for env variable DATABASE_KEY
EnvKeyDatabaseCertKey = "DATABASE_CERT_KEY"
// EnvKeyDatabaseCACert key for env variable DATABASE_CA_CERT
EnvKeyDatabaseCACert = "DATABASE_CA_CERT"
// EnvKeySmtpHost key for env variable SMTP_HOST
EnvKeySmtpHost = "SMTP_HOST"
// EnvKeySmtpPort key for env variable SMTP_PORT

View File

@ -1,13 +1,17 @@
package cassandradb
import (
"crypto/tls"
"crypto/x509"
"fmt"
"log"
"strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/gocql/gocql"
cansandraDriver "github.com/gocql/gocql"
)
@ -21,6 +25,13 @@ var KeySpace string
// NewProvider to initialize arangodb connection
func NewProvider() (*provider, error) {
dbURL := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)
if dbURL == "" {
dbURL = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseHost)
if envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabasePort) != "" {
dbURL = fmt.Sprintf("%s:%s", dbURL, envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabasePort))
}
}
KeySpace = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName)
clusterURL := []string{}
if strings.Contains(dbURL, ",") {
@ -36,10 +47,44 @@ func NewProvider() (*provider, error) {
}
}
if envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCert) != "" && envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCACert) != "" && envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCertKey) != "" {
certString, err := crypto.DecryptB64(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCert))
if err != nil {
return nil, err
}
keyString, err := crypto.DecryptB64(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCertKey))
if err != nil {
return nil, err
}
caString, err := crypto.DecryptB64(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseCACert))
if err != nil {
return nil, err
}
cert, err := tls.X509KeyPair([]byte(certString), []byte(keyString))
if err != nil {
return nil, err
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM([]byte(caString))
cassandraClient.SslOpts = &cansandraDriver.SslOptions{
Config: &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
InsecureSkipVerify: true,
},
EnableHostVerification: false,
}
}
cassandraClient.RetryPolicy = &cansandraDriver.SimpleRetryPolicy{
NumRetries: 3,
}
cassandraClient.Consistency = cansandraDriver.Quorum
cassandraClient.Consistency = gocql.LocalQuorum
session, err := cassandraClient.CreateSession()
if err != nil {
@ -47,12 +92,31 @@ func NewProvider() (*provider, error) {
return nil, err
}
keyspaceQuery := fmt.Sprintf("CREATE KEYSPACE IF NOT EXISTS %s WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor':1}",
KeySpace)
err = session.Query(keyspaceQuery).Exec()
if err != nil {
log.Println("Unable to create keyspace:", err)
return nil, err
// Note for astra keyspaces can only be created from there console
// https://docs.datastax.com/en/astra/docs/datastax-astra-faq.html#_i_am_trying_to_create_a_keyspace_in_the_cql_shell_and_i_am_running_into_an_error_how_do_i_fix_this
getKeyspaceQuery := fmt.Sprintf("SELECT keyspace_name FROM system_schema.keyspaces;")
scanner := session.Query(getKeyspaceQuery).Iter().Scanner()
hasAuthorizerKeySpace := false
for scanner.Next() {
var keySpace string
err := scanner.Scan(&keySpace)
if err != nil {
log.Println("Error while getting keyspace information", err)
return nil, err
}
if keySpace == KeySpace {
hasAuthorizerKeySpace = true
break
}
}
if !hasAuthorizerKeySpace {
createKeySpaceQuery := fmt.Sprintf("CREATE KEYSPACE %s WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1};", KeySpace)
err = session.Query(createKeySpaceQuery).Exec()
if err != nil {
log.Println("Error while creating keyspace", err)
return nil, err
}
}
// make sure collections are present

7
server/env/env.go vendored
View File

@ -42,6 +42,9 @@ func InitRequiredEnv() error {
dbHost := os.Getenv(constants.EnvKeyDatabaseHost)
dbUsername := os.Getenv(constants.EnvKeyDatabaseUsername)
dbPassword := os.Getenv(constants.EnvKeyDatabasePassword)
dbCert := os.Getenv(constants.EnvKeyDatabaseCert)
dbCertKey := os.Getenv(constants.EnvKeyDatabaseCertKey)
dbCACert := os.Getenv(constants.EnvKeyDatabaseCACert)
if strings.TrimSpace(dbType) == "" {
if envstore.ARG_DB_TYPE != nil && *envstore.ARG_DB_TYPE != "" {
@ -77,6 +80,10 @@ func InitRequiredEnv() error {
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabasePort, dbPort)
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseUsername, dbUsername)
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabasePassword, dbPassword)
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseCert, dbCert)
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseCertKey, dbCertKey)
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseCACert, dbCACert)
return nil
}

View File

@ -174,7 +174,11 @@ func OAuthCallbackHandler() gin.HandlerFunc {
sessionstore.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
}
go utils.SaveSessionInDB(c, user.ID)
go db.Provider.AddSession(models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(c.Request),
IP: utils.GetIP(c.Request),
})
if strings.Contains(redirectURL, "?") {
redirectURL = redirectURL + "&" + params
} else {

View File

@ -8,6 +8,7 @@ import (
"github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/sessionstore"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
@ -109,7 +110,11 @@ func VerifyEmailHandler() gin.HandlerFunc {
redirectURL = redirectURL + "?" + params
}
go utils.SaveSessionInDB(c, user.ID)
go db.Provider.AddSession(models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(c.Request),
IP: utils.GetIP(c.Request),
})
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
}

View File

@ -10,6 +10,7 @@ import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/sessionstore"
@ -96,7 +97,11 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
sessionstore.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
}
go utils.SaveSessionInDB(gc, user.ID)
go db.Provider.AddSession(models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(gc.Request),
IP: utils.GetIP(gc.Request),
})
return res, nil
}

View File

@ -174,7 +174,11 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
sessionstore.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
cookie.SetSession(gc, authToken.FingerPrintHash)
go utils.SaveSessionInDB(gc, user.ID)
go db.Provider.AddSession(models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(gc.Request),
IP: utils.GetIP(gc.Request),
})
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {

View File

@ -8,6 +8,7 @@ import (
"github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/sessionstore"
"github.com/authorizerdev/authorizer/server/token"
@ -62,7 +63,11 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
sessionstore.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
cookie.SetSession(gc, authToken.FingerPrintHash)
go utils.SaveSessionInDB(gc, user.ID)
go db.Provider.AddSession(models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(gc.Request),
IP: utils.GetIP(gc.Request),
})
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {

View File

@ -1,12 +1,7 @@
package utils
import (
"log"
"reflect"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/gin-gonic/gin"
)
// StringSliceContains checks if a string slice contains a particular string
@ -19,23 +14,6 @@ func StringSliceContains(s []string, e string) bool {
return false
}
// SaveSessionInDB saves sessions generated for a given user with meta information
// Do not store token here as that could be security breach
func SaveSessionInDB(c *gin.Context, userId string) {
sessionData := models.Session{
UserID: userId,
UserAgent: GetUserAgent(c.Request),
IP: GetIP(c.Request),
}
err := db.Provider.AddSession(sessionData)
if err != nil {
log.Println("=> error saving session in db:", err)
} else {
log.Println("=> session saved in db:", sessionData)
}
}
// RemoveDuplicateString removes duplicate strings from a string slice
func RemoveDuplicateString(strSlice []string) []string {
allKeys := make(map[string]bool)

48
server/utils/file.go Normal file
View File

@ -0,0 +1,48 @@
package utils
import (
"errors"
"os"
)
// CreateFolder creates a folder in Current working dir
func CreateFolder(dir string) (string, error) {
pwd, err := os.Getwd()
if err != nil {
return "", err
}
path := pwd + "/" + dir
err = os.Mkdir(path, 0o755)
if err == nil {
return path, nil
}
if os.IsExist(err) {
// check that the existing path is a directory
info, err := os.Stat(path)
if err != nil {
return "", err
}
if !info.IsDir() {
return "", errors.New("path exists but is not a directory")
}
return path, nil
}
return path, err
}
// CreateFile creates a file on given path with given content
func CreateFile(filePath string, content string) error {
f, err := os.Create(filePath)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(content)
if err != nil {
return err
}
return nil
}