work on determining which secrets accessible to user
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -226,85 +226,93 @@ func UpdateSecret(c *gin.Context) {
|
||||
s.DeviceName = input.DeviceName
|
||||
s.DeviceCategory = input.DeviceCategory
|
||||
|
||||
// TODO:
|
||||
// Get a list of matching secrets - SecretsSearchAllSafes
|
||||
//secretList, err := models.SecretsSearchAllSafes(&s)
|
||||
// Check if user has access to the safes containing those secrets - something like UserGetSafesAllowed but not quite
|
||||
//allowedSafes, err := models.UserGetSafesAllowed(user_id)
|
||||
// Make sure that the access is not readonly
|
||||
// If user has access to more than one safe containing the secret, generate an error
|
||||
// Otherwise, update the secret
|
||||
secretList, err := models.SecretsGetAllowedForGroup(&s, user_id)
|
||||
|
||||
allowedUpdate, err := CheckUpdateSecretAllowed(&s, int(user_id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("error determining secret : '%s'", err)})
|
||||
return
|
||||
}
|
||||
|
||||
if allowedUpdate != 0 {
|
||||
s.SafeId = allowedUpdate
|
||||
}
|
||||
|
||||
// Query which safes the current user is allowed to access
|
||||
|
||||
/*
|
||||
safeId := SecretCheckSafeAllowed(int(user_id), input)
|
||||
if safeId == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "error determining safe"})
|
||||
return
|
||||
}
|
||||
|
||||
s.SafeId = safeId
|
||||
*/
|
||||
|
||||
// TODO - replace this with a call to SecretsGetMultipleSafes
|
||||
|
||||
// Confirm that the secret already exists
|
||||
checkExists, err := models.GetSecrets(&s, false)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
if len(secretList) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "no secret matching search parameters"})
|
||||
return
|
||||
}
|
||||
if len(checkExists) == 0 {
|
||||
err = errors.New("UpdateSecret could not find existing secret to update")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
} else if len(checkExists) == 1 {
|
||||
// Set the secret id with the one retrieved from the database
|
||||
s.SecretId = checkExists[0].SecretId
|
||||
|
||||
// check for empty fields in the update request and update from the existing record
|
||||
if s.UserName == "" {
|
||||
s.UserName = checkExists[0].UserName
|
||||
}
|
||||
if s.DeviceCategory == "" {
|
||||
s.DeviceCategory = checkExists[0].DeviceCategory
|
||||
}
|
||||
if s.DeviceName == "" {
|
||||
s.DeviceName = checkExists[0].DeviceName
|
||||
}
|
||||
|
||||
// Encrypt secret
|
||||
s.Secret = input.SecretValue
|
||||
_, err = s.EncryptSecret()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "UpdateSecret error encrypting secret : " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.UpdateSecret()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "UpdateSecret error saving secret : " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
} else if len(secretList) == 1 {
|
||||
// Update secret
|
||||
log.Printf("mock updating secret\n")
|
||||
c.JSON(http.StatusOK, gin.H{"message": "secret updated successfully"})
|
||||
} else {
|
||||
err = errors.New("UpdateSecret found multiple secrets matching input data, be more specific")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "multiple secrets matched search parameters, be more specific"})
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO:
|
||||
// Get a list of matching secrets - SecretsSearchAllSafes
|
||||
//secretList, err := models.SecretsSearchAllSafes(&s)
|
||||
// Check if user has access to the safes containing those secrets - something like UserGetSafesAllowed but not quite
|
||||
//allowedSafes, err := models.UserGetSafesAllowed(user_id)
|
||||
// Make sure that the access is not readonly
|
||||
// If user has access to more than one safe containing the secret, generate an error
|
||||
// Otherwise, update the secret
|
||||
|
||||
allowedUpdate, err := CheckUpdateSecretAllowed(&s, int(user_id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("error determining secret : '%s'", err)})
|
||||
return
|
||||
}
|
||||
|
||||
if allowedUpdate != 0 {
|
||||
s.SafeId = allowedUpdate
|
||||
}
|
||||
// TODO - replace this with a call to SecretsGetMultipleSafes
|
||||
|
||||
// Confirm that the secret already exists
|
||||
checkExists, err := models.GetSecrets(&s, false)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if len(checkExists) == 0 {
|
||||
err = errors.New("UpdateSecret could not find existing secret to update")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
} else if len(checkExists) == 1 {
|
||||
// Set the secret id with the one retrieved from the database
|
||||
s.SecretId = checkExists[0].SecretId
|
||||
|
||||
// check for empty fields in the update request and update from the existing record
|
||||
if s.UserName == "" {
|
||||
s.UserName = checkExists[0].UserName
|
||||
}
|
||||
if s.DeviceCategory == "" {
|
||||
s.DeviceCategory = checkExists[0].DeviceCategory
|
||||
}
|
||||
if s.DeviceName == "" {
|
||||
s.DeviceName = checkExists[0].DeviceName
|
||||
}
|
||||
|
||||
// Encrypt secret
|
||||
s.Secret = input.SecretValue
|
||||
_, err = s.EncryptSecret()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "UpdateSecret error encrypting secret : " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.UpdateSecret()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "UpdateSecret error saving secret : " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "secret updated successfully"})
|
||||
} else {
|
||||
err = errors.New("UpdateSecret found multiple secrets matching input data, be more specific")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
func SecretCheckSafeAllowed(user_id int, input StoreInput) int {
|
||||
|
@@ -1,8 +1,10 @@
|
||||
package models
|
||||
|
||||
type Permission struct {
|
||||
PermissionId int `db:"PermissionId"`
|
||||
RoleId int `db:"RoleId"`
|
||||
SafeId int `db:"SafeId"`
|
||||
GroupId int `db:"GroupId"`
|
||||
PermissionId int `db:"PermissionId"`
|
||||
Description string `db:"Description"`
|
||||
ReadOnly bool `db:"ReadOnly"`
|
||||
RoleId int `db:"RoleId"`
|
||||
SafeId int `db:"SafeId"`
|
||||
GroupId int `db:"GroupId"`
|
||||
}
|
||||
|
@@ -16,8 +16,7 @@ import (
|
||||
|
||||
// We use the json:"-" field tag to prevent showing these details to the user
|
||||
type Secret struct {
|
||||
SecretId int `db:"SecretId" json:"-"`
|
||||
//RoleId int `db:"RoleId" json:"-"`
|
||||
SecretId int `db:"SecretId" json:"-"`
|
||||
SafeId int `db:"SafeId"`
|
||||
DeviceName string `db:"DeviceName"`
|
||||
DeviceCategory string `db:"DeviceCategory"`
|
||||
@@ -46,6 +45,81 @@ func (s *Secret) SaveSecret() (*Secret, error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func SecretsGetAllowedForUser(s *Secret, userId string) ([]UserSecret, error) {
|
||||
// Query based on group
|
||||
// SELECT users.UserId, users.GroupId, permissions.ReadOnly, permissions.SafeId, safes.SafeName, secrets.* FROM users INNER JOIN groups ON users.GroupId = groups.GroupId INNER JOIN permissions ON groups.GroupId = permissions.GroupId INNER JOIN safes on permissions.SafeId = safes.SafeId INNER JOIN secrets on secrets.SafeId = safes.SafeId WHERE users.UserId = 2
|
||||
var secretResults []UserSecret
|
||||
|
||||
return secretResults, nil
|
||||
}
|
||||
|
||||
func SecretsGetAllowedForGroup(s *Secret, userId int) ([]UserSecret, error) {
|
||||
// Query based on group
|
||||
// SELECT users.UserId, users.GroupId, permissions.ReadOnly, permissions.SafeId, safes.SafeName, secrets.* FROM users INNER JOIN groups ON users.GroupId = groups.GroupId INNER JOIN permissions ON groups.GroupId = permissions.GroupId INNER JOIN safes on permissions.SafeId = safes.SafeId INNER JOIN secrets on secrets.SafeId = safes.SafeId WHERE users.UserId = 2
|
||||
var err error
|
||||
var secretResults []UserSecret
|
||||
|
||||
args := []interface{}{}
|
||||
query := "users.UserId, users.GroupId, permissions.ReadOnly, permissions.SafeId, safes.SafeName, secrets.* FROM users INNER JOIN groups ON users.GroupId = groups.GroupId INNER JOIN permissions ON groups.GroupId = permissions.GroupId INNER JOIN safes on permissions.SafeId = safes.SafeId INNER JOIN secrets on secrets.SafeId = safes.SafeId WHERE users.UserId = ? "
|
||||
args = append(args, userId)
|
||||
|
||||
// Make sure at least one parameter was specified
|
||||
if s.DeviceName == "" && s.DeviceCategory == "" && s.UserName == "" {
|
||||
err = errors.New("no search parameters specified")
|
||||
log.Println(err)
|
||||
return secretResults, err
|
||||
}
|
||||
|
||||
// Add any other arguments to the query if they were specified
|
||||
if s.DeviceName != "" {
|
||||
query += " AND DeviceName LIKE ? "
|
||||
args = append(args, s.DeviceName)
|
||||
}
|
||||
|
||||
if s.DeviceCategory != "" {
|
||||
query += " AND DeviceCategory LIKE ? "
|
||||
args = append(args, s.DeviceCategory)
|
||||
}
|
||||
|
||||
if s.UserName != "" {
|
||||
query += " AND UserName LIKE ? "
|
||||
args = append(args, s.UserName)
|
||||
}
|
||||
|
||||
// Execute the query
|
||||
log.Printf("SecretsGetAllowedForGroup query string : '%s'\n%+v\n", query, args)
|
||||
rows, err := db.Queryx(query, args...)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("SecretsGetAllowedForGroup error executing sql record : '%s'\n", err)
|
||||
return secretResults, err
|
||||
} else {
|
||||
// parse all the results into a slice
|
||||
for rows.Next() {
|
||||
var r UserSecret
|
||||
err = rows.StructScan(&r)
|
||||
if err != nil {
|
||||
log.Printf("SecretsGetAllowedForGroup error parsing sql record : '%s'\n", err)
|
||||
return secretResults, err
|
||||
}
|
||||
|
||||
// Decrypt the secret
|
||||
_, err = r.DecryptSecret()
|
||||
if err != nil {
|
||||
//log.Printf("GetSecret unable to decrypt stored secret '%v' : '%s'\n", r.Secret, err)
|
||||
log.Printf("SecretsGetAllowedForGroup unable to decrypt stored secret : '%s'\n", err)
|
||||
return secretResults, err
|
||||
} else {
|
||||
secretResults = append(secretResults, r)
|
||||
}
|
||||
|
||||
}
|
||||
log.Printf("SecretsGetAllowedForGroup retrieved '%d' results\n", len(secretResults))
|
||||
}
|
||||
|
||||
return secretResults, nil
|
||||
}
|
||||
|
||||
func SecretsSearchAllSafes(s *Secret) ([]Secret, error) {
|
||||
var err error
|
||||
var secretResults []Secret
|
||||
|
@@ -374,6 +374,8 @@ func CreateTables() {
|
||||
FOREIGN KEY (GroupId) REFERENCES groups(GroupId)
|
||||
);
|
||||
INSERT INTO permissions SELECT PermissionId, SafeId, UserId, GroupId, '' AS Description, 0 as ReadOnly FROM _permissions_old;
|
||||
UPDATE permissions SET ReadOnly = 0 WHERE ReadOnly is null;
|
||||
UPDATE permissions SET Description = '' WHERE Description is null;
|
||||
COMMIT;
|
||||
PRAGMA foreign_keys=on;
|
||||
DROP TABLE _permissions_old;
|
||||
|
@@ -35,6 +35,7 @@ type UserGroup struct {
|
||||
Admin bool `db:"Admin"`
|
||||
}
|
||||
|
||||
// Combine Users and Safes to determine which safes a user has access to
|
||||
type UserSafe struct {
|
||||
User
|
||||
SafeId int `db:"SafeId"`
|
||||
@@ -42,6 +43,13 @@ type UserSafe struct {
|
||||
GroupId int `db:"GroupId"`
|
||||
}
|
||||
|
||||
// Used for querying all secrets the user has access to
|
||||
type UserSecret struct {
|
||||
User
|
||||
Group
|
||||
Secret
|
||||
}
|
||||
|
||||
func (u *User) SaveUser() (*User, error) {
|
||||
|
||||
var err error
|
||||
|
Reference in New Issue
Block a user