Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ws password #1006

Merged
merged 5 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1549,7 +1559,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 @@ -1568,7 +1578,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 @@ -1592,7 +1602,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 @@ -1625,5 +1642,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)))
shay23b marked this conversation as resolved.
Show resolved Hide resolved
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