Skip to content

Commit

Permalink
Ws password (#1006)
Browse files Browse the repository at this point in the history
* generate password for internal ws use

* fix

* fix

* allowedPasswordChars
  • Loading branch information
shay23b authored Jun 20, 2023
1 parent a52ca1f commit 2992385
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 64 deletions.
22 changes: 12 additions & 10 deletions db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func createTables(MetadataDbClient MetadataStorage) error {
id SERIAL NOT NULL,
name VARCHAR NOT NULL UNIQUE DEFAULT '$G',
firebase_organization_id VARCHAR NOT NULL DEFAULT '' ,
internal_ws_pass VARCHAR NOT NULL,
PRIMARY KEY (id));`

alterAuditLogsTable := `
Expand Down Expand Up @@ -5337,7 +5338,7 @@ func DeleteDlsMsgsByTenant(tenantName string) error {
}

// Tenants functions
func UpsertTenant(name string) (models.Tenant, error) {
func UpsertTenant(name string, encryptrdInternalWSPass string) (models.Tenant, error) {
ctx, cancelfunc := context.WithTimeout(context.Background(), DbOperationTimeout*time.Second)
defer cancelfunc()

Expand All @@ -5347,15 +5348,15 @@ func UpsertTenant(name string) (models.Tenant, error) {
}
defer conn.Release()

query := `INSERT INTO tenants (name) VALUES($1) ON CONFLICT (name) DO NOTHING`
query := `INSERT INTO tenants (name, internal_ws_pass) VALUES($1, $2) ON CONFLICT (name) DO NOTHING`

stmt, err := conn.Conn().Prepare(ctx, "upsert_tenant", query)
if err != nil {
return models.Tenant{}, err
}

var tenantId int
rows, err := conn.Conn().Query(ctx, stmt.Name, name)
rows, err := conn.Conn().Query(ctx, stmt.Name, name, encryptrdInternalWSPass)
if err != nil {
return models.Tenant{}, err
}
Expand Down Expand Up @@ -5416,7 +5417,7 @@ func UpsertTenant(name string) (models.Tenant, error) {
return newTenant, nil
}

func UpsertBatchOfTenants(tenants []string) error {
func UpsertBatchOfTenants(tenants []models.TenantForUpsert) error {
ctx, cancelfunc := context.WithTimeout(context.Background(), DbOperationTimeout*time.Second)
defer cancelfunc()
conn, err := MetadataDbClient.Client.Acquire(ctx)
Expand All @@ -5428,10 +5429,11 @@ func UpsertBatchOfTenants(tenants []string) error {
valueStrings := make([]string, 0, len(tenants))
valueArgs := make([]interface{}, 0, len(tenants))
for i, tenant := range tenants {
valueStrings = append(valueStrings, fmt.Sprintf("($%d)", i+1))
valueArgs = append(valueArgs, tenant)
valueStrings = append(valueStrings, fmt.Sprintf("($%d, $%d)", i*2+1, i*2+2))
valueArgs = append(valueArgs, tenant.Name)
valueArgs = append(valueArgs, tenant.InternalWSPass)
}
query := fmt.Sprintf("INSERT INTO tenants (name) VALUES %s ON CONFLICT (name) DO NOTHING", strings.Join(valueStrings, ","))
query := fmt.Sprintf("INSERT INTO tenants (name, internal_ws_pass) VALUES %s ON CONFLICT (name) DO NOTHING", strings.Join(valueStrings, ","))
stmt, err := conn.Conn().Prepare(ctx, "upsert_tenants", query)
if err != nil {
return err
Expand Down Expand Up @@ -5587,7 +5589,7 @@ func GetTenantByName(name string) (bool, models.Tenant, error) {
return true, tenants[0], nil
}

func CreateTenant(name, firebaseOrganizationId string) (models.Tenant, error) {
func CreateTenant(name, firebaseOrganizationId, encryptrdInternalWSPass string) (models.Tenant, error) {
ctx, cancelfunc := context.WithTimeout(context.Background(), DbOperationTimeout*time.Second)
defer cancelfunc()

Expand All @@ -5597,15 +5599,15 @@ func CreateTenant(name, firebaseOrganizationId string) (models.Tenant, error) {
}
defer conn.Release()

query := `INSERT INTO tenants (name, firebase_organization_id) VALUES($1, $2)`
query := `INSERT INTO tenants (name, firebase_organization_id, internal_ws_pass) VALUES($1, $2, $3)`

stmt, err := conn.Conn().Prepare(ctx, "create_new_tenant", query)
if err != nil {
return models.Tenant{}, err
}

var tenantId int
rows, err := conn.Conn().Query(ctx, stmt.Name, name, firebaseOrganizationId)
rows, err := conn.Conn().Query(ctx, stmt.Name, name, firebaseOrganizationId, encryptrdInternalWSPass)
if err != nil {
return models.Tenant{}, err
}
Expand Down
6 changes: 6 additions & 0 deletions models/tenants.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,10 @@ type Tenant struct {
ID int `json:"id"`
Name string `json:"name"`
FirebaseOrganizationId string `json:"firebase_organization_id"`
InternalWSPass string `json:"internal_ws_pass"`
}

type TenantForUpsert struct {
Name string `json:"name"`
InternalWSPass string `json:"internal_ws_pass"`
}
24 changes: 21 additions & 3 deletions server/memphis_cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const shouldCreateRootUserforGlobalAcc = true

type BillingHandler struct{ S *Server }
type TenantHandler struct{ S *Server }
type LoginSchema struct {
Expand Down Expand Up @@ -1147,6 +1149,13 @@ func (umh UserMgmtHandler) Login(c *gin.Context) {
c.AbortWithStatusJSON(500, gin.H{"message": "Server error"})
return
}
decriptionKey := getAESKey()
decryptedUserPassword, err := DecryptAES(decriptionKey, tenant.InternalWSPass)
if err != nil {
serv.Errorf("Login: User " + body.Username + ": " + err.Error())
c.AbortWithStatusJSON(500, gin.H{"message": "Server error"})
return
}

domain := ""
secure := false
Expand Down Expand Up @@ -1175,6 +1184,7 @@ func (umh UserMgmtHandler) Login(c *gin.Context) {
"user_pass_based_auth": configuration.USER_PASS_BASED_AUTH,
"connection_token": configuration.CONNECTION_TOKEN,
"account_id": tenant.ID,
"internal_ws_pass": decryptedUserPassword,
})
}

Expand Down Expand Up @@ -1550,7 +1560,7 @@ func (mh MonitoringHandler) getMainOverviewDataDetails(tenantName string) (MainO
func (umh UserMgmtHandler) RefreshToken(c *gin.Context) {
user, err := getUserDetailsFromMiddleware(c)
if err != nil {
serv.Errorf("refreshToken: " + err.Error())
serv.Errorf("RefreshToken: " + err.Error())
c.AbortWithStatusJSON(401, gin.H{"message": "Unauthorized"})
return
}
Expand All @@ -1569,7 +1579,7 @@ func (umh UserMgmtHandler) RefreshToken(c *gin.Context) {
return
}
if !exist {
serv.Warnf("refreshToken: user " + username + " does not exist")
serv.Warnf("RefreshToken: user " + username + " does not exist")
c.AbortWithStatusJSON(401, gin.H{"message": "Unauthorized"})
return
}
Expand All @@ -1593,7 +1603,14 @@ func (umh UserMgmtHandler) RefreshToken(c *gin.Context) {
return
}
if !exist {
serv.Warnf("Login: User " + username + ": tenant " + user.TenantName + " does not exist")
serv.Warnf("RefreshToken: User " + username + ": tenant " + user.TenantName + " does not exist")
c.AbortWithStatusJSON(500, gin.H{"message": "Server error"})
return
}
decriptionKey := getAESKey()
decryptedUserPassword, err := DecryptAES(decriptionKey, tenant.InternalWSPass)
if err != nil {
serv.Errorf("RefreshToken: User " + username + ": " + err.Error())
c.AbortWithStatusJSON(500, gin.H{"message": "Server error"})
return
}
Expand Down Expand Up @@ -1626,5 +1643,6 @@ func (umh UserMgmtHandler) RefreshToken(c *gin.Context) {
"user_pass_based_auth": configuration.USER_PASS_BASED_AUTH,
"connection_token": configuration.CONNECTION_TOKEN,
"account_id": tenant.ID,
"internal_ws_pass": decryptedUserPassword,
})
}
6 changes: 5 additions & 1 deletion server/memphis_handlers_tenants.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import (
)

func CreateGlobalTenantOnFirstSystemLoad() error {
_, err := db.UpsertTenant(globalAccountName)
encryptedPass, err := EncryptAES([]byte(generateRandomPassword(12)))
if err != nil {
return err
}
_, err = db.UpsertTenant(globalAccountName, encryptedPass)
if err != nil {
return err
}
Expand Down
97 changes: 64 additions & 33 deletions server/memphis_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ package server
import (
"bufio"
"bytes"
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"math/big"
"memphis/conf"
"memphis/db"
"memphis/models"
Expand Down Expand Up @@ -1161,6 +1163,8 @@ func GetMemphisOpts(opts Options, reload bool) (*Account, Options, error) {
return &Account{}, Options{}, err
}

decriptionKey := getAESKey()

for _, conf := range configs {
switch conf.Key {
case "dls_retention":
Expand Down Expand Up @@ -1193,12 +1197,16 @@ func GetMemphisOpts(opts Options, reload bool) (*Account, Options, error) {
if configuration.USER_PASS_BASED_AUTH {
if !reload {
if len(opts.Accounts) > 0 {
tenantsToUpsert := []string{globalAccountName}
tenantsToUpsert := []models.TenantForUpsert{}
for _, account := range opts.Accounts {
name := account.GetName()
if account.GetName() != DEFAULT_SYSTEM_ACCOUNT {
name = strings.ToLower(name)
tenantsToUpsert = append(tenantsToUpsert, name)
encryptedPass, err := EncryptAES([]byte(generateRandomPassword(12)))
if err != nil {
return &Account{}, Options{}, err
}
tenantsToUpsert = append(tenantsToUpsert, models.TenantForUpsert{Name: name, InternalWSPass: encryptedPass})
}
}
err = db.UpsertBatchOfTenants(tenantsToUpsert)
Expand Down Expand Up @@ -1306,7 +1314,7 @@ func GetMemphisOpts(opts Options, reload bool) (*Account, Options, error) {
if err != nil {
return &Account{}, Options{}, err
}

tenantsId := map[string]int{}
appUsers := []*User{}
accounts := []*Account{}
Expand All @@ -1323,10 +1331,13 @@ func GetMemphisOpts(opts Options, reload bool) (*Account, Options, error) {
streams: siList,
},
}
// generate random password for each tenant
decryptedUserPassword, err := DecryptAES(decriptionKey, tenant.InternalWSPass)
if err != nil {
return &Account{}, Options{}, err
}
appUsers = append(appUsers, &User{
Username: MEMPHIS_USERNAME + "$" + strconv.Itoa(tenant.ID),
Password: configuration.CONNECTION_TOKEN,
Password: decryptedUserPassword,
Account: account,
})
accounts = append(accounts, account)
Expand All @@ -1352,38 +1363,45 @@ func GetMemphisOpts(opts Options, reload bool) (*Account, Options, error) {
}
accounts = append(accounts, gacc)
}
// ** not relevant for cloud
if reload {
appUsers = append(appUsers, &User{
Username: "root$1",
Password: configuration.ROOT_PASSWORD,
Account: serv.gacc,
})
appUsers = append(appUsers, &User{
Username: MEMPHIS_USERNAME + "$" + strconv.Itoa(1),
Password: configuration.CONNECTION_TOKEN,
Account: serv.gacc,
})
addedTenant[conf.GlobalAccountName] = serv.gacc
} else {
appUsers = append(appUsers, &User{
Username: "root$1",
Password: configuration.ROOT_PASSWORD,
Account: gacc,
})
appUsers = append(appUsers, &User{
Username: MEMPHIS_USERNAME + "$" + strconv.Itoa(1),
Password: configuration.CONNECTION_TOKEN,
Account: gacc,
})
addedTenant[conf.GlobalAccountName] = gacc
if shouldCreateRootUserforGlobalAcc {
_, globalT, err := db.GetGlobalTenant()
if err != nil {
return &Account{}, Options{}, err
}
decryptedPass, err := DecryptAES(decriptionKey, globalT.InternalWSPass)
if err != nil {
return &Account{}, Options{}, err
}
if reload {
appUsers = append(appUsers, &User{
Username: "root$1",
Password: configuration.ROOT_PASSWORD,
Account: serv.gacc,
})
appUsers = append(appUsers, &User{
Username: MEMPHIS_USERNAME + "$" + strconv.Itoa(1),
Password: decryptedPass,
Account: serv.gacc,
})
addedTenant[conf.GlobalAccountName] = serv.gacc
} else {
appUsers = append(appUsers, &User{
Username: "root$1",
Password: configuration.ROOT_PASSWORD,
Account: gacc,
})
appUsers = append(appUsers, &User{
Username: MEMPHIS_USERNAME + "$" + strconv.Itoa(1),
Password: decryptedPass,
Account: gacc,
})
addedTenant[conf.GlobalAccountName] = gacc
}
}
// not relevant for cloud **
tenantsId[globalAccountName] = 1
key := getAESKey()
for _, user := range users {
name := user.TenantName
decryptedUserPassword, err := DecryptAES(key, user.Password)
decryptedUserPassword, err := DecryptAES(decriptionKey, user.Password)
if err != nil {
return &Account{}, Options{}, err
}
Expand Down Expand Up @@ -1430,3 +1448,16 @@ func (s *Server) getTenantNameAndMessage(msg []byte) (string, string, error) {

return tenantName, message, nil
}

func generateRandomPassword(length int) string {
allowedPasswordChars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+,.?/:;{}[]~"
charsetLength := big.NewInt(int64(len(allowedPasswordChars)))
password := make([]byte, length)

for i := 0; i < length; i++ {
randomIndex, _ := rand.Int(rand.Reader, charsetLength)
password[i] = allowedPasswordChars[randomIndex.Int64()]
}

return string(password)
}
11 changes: 7 additions & 4 deletions ui_src/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { message } from 'antd';

import {
LOCAL_STORAGE_ACCOUNT_ID,
LOCAL_STORAGE_INTERNAL_WS_PASS,
LOCAL_STORAGE_CONNECTION_TOKEN,
LOCAL_STORAGE_TOKEN,
LOCAL_STORAGE_USER_PASS_BASED_AUTH,
Expand Down Expand Up @@ -75,16 +76,17 @@ const App = withRouter((props) => {
const ws_port = data.ws_port;
const SOCKET_URL = ENVIRONMENT === 'production' ? `${WS_PREFIX}://${WS_SERVER_URL_PRODUCTION}:${ws_port}` : `${WS_PREFIX}://localhost:${ws_port}`;
let conn;
const connection_token = localStorage.getItem(LOCAL_STORAGE_CONNECTION_TOKEN);
if (localStorage.getItem(LOCAL_STORAGE_USER_PASS_BASED_AUTH) === 'true') {
const account_id = localStorage.getItem(LOCAL_STORAGE_ACCOUNT_ID);
const internal_ws_pass = localStorage.getItem(LOCAL_STORAGE_INTERNAL_WS_PASS);
conn = await connect({
servers: [SOCKET_URL],
user: '$memphis_user$' + account_id,
pass: connection_token,
pass: internal_ws_pass,
timeout: '5000'
});
} else {
const connection_token = localStorage.getItem(LOCAL_STORAGE_CONNECTION_TOKEN);
conn = await connect({
servers: [SOCKET_URL],
token: '::' + connection_token,
Expand Down Expand Up @@ -140,16 +142,17 @@ const App = withRouter((props) => {
if (firstTime) {
try {
let conn;
const connection_token = localStorage.getItem(LOCAL_STORAGE_CONNECTION_TOKEN);
if (localStorage.getItem(LOCAL_STORAGE_USER_PASS_BASED_AUTH) === 'true') {
const account_id = localStorage.getItem(LOCAL_STORAGE_ACCOUNT_ID);
const internal_ws_pass = localStorage.getItem(LOCAL_STORAGE_INTERNAL_WS_PASS);
conn = await connect({
servers: [SOCKET_URL],
user: '$memphis_user$' + account_id,
pass: connection_token,
pass: internal_ws_pass,
timeout: '5000'
});
} else {
const connection_token = localStorage.getItem(LOCAL_STORAGE_CONNECTION_TOKEN);
conn = await connect({
servers: [SOCKET_URL],
token: '::' + connection_token,
Expand Down
1 change: 1 addition & 0 deletions ui_src/src/const/localStorageConsts.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const LOCAL_STORAGE_EXPIRED_TOKEN = 'expires_in';
export const LOCAL_STORAGE_CLIENTS_PORT = 'client_port';
export const LOCAL_STORAGE_BROKER_HOST = 'broker_host';
export const LOCAL_STORAGE_ACCOUNT_ID = 'account_id';
export const LOCAL_STORAGE_INTERNAL_WS_PASS = 'internal_ws_pass';
export const LOCAL_STORAGE_AVATAR_ID = 'avatar_id';
export const LOCAL_STORAGE_USER_NAME = 'user_name';
export const LOCAL_STORAGE_FULL_NAME = 'full_name';
Expand Down
Loading

0 comments on commit 2992385

Please sign in to comment.