web UI: improve user cloning

This commit is contained in:
Nicola Murino 2020-12-26 15:11:38 +01:00
parent bc397002d4
commit e536a638c9
No known key found for this signature in database
GPG key ID: 2F1FB59433D5A8CB
6 changed files with 96 additions and 11 deletions

View file

@ -261,6 +261,41 @@ func (u *User) HideConfidentialData() {
}
}
// DecryptSecrets tries to decrypts kms secrets
func (u *User) DecryptSecrets() error {
switch u.FsConfig.Provider {
case S3FilesystemProvider:
if u.FsConfig.S3Config.AccessSecret.IsEncrypted() {
return u.FsConfig.S3Config.AccessSecret.Decrypt()
}
case GCSFilesystemProvider:
if u.FsConfig.GCSConfig.Credentials.IsEncrypted() {
return u.FsConfig.GCSConfig.Credentials.Decrypt()
}
case AzureBlobFilesystemProvider:
if u.FsConfig.AzBlobConfig.AccountKey.IsEncrypted() {
return u.FsConfig.AzBlobConfig.AccountKey.Decrypt()
}
case CryptedFilesystemProvider:
if u.FsConfig.CryptConfig.Passphrase.IsEncrypted() {
return u.FsConfig.CryptConfig.Passphrase.Decrypt()
}
case SFTPFilesystemProvider:
if u.FsConfig.SFTPConfig.Password.IsEncrypted() {
if err := u.FsConfig.SFTPConfig.Password.Decrypt(); err != nil {
return err
}
}
if u.FsConfig.SFTPConfig.PrivateKey.IsEncrypted() {
if err := u.FsConfig.SFTPConfig.PrivateKey.Decrypt(); err != nil {
return err
}
}
}
return nil
}
// GetPermissionsForPath returns the permissions for the given path.
// The path must be an SFTP path
func (u *User) GetPermissionsForPath(p string) []string {

View file

@ -235,6 +235,7 @@ func TestMain(m *testing.M) {
waitTCPListening(ftpdConf.Bindings[0].GetAddress())
// ensure all the initial connections to check if the service is alive are disconnected
time.Sleep(100 * time.Millisecond)
for len(common.Connections.GetStats()) > 0 {
time.Sleep(50 * time.Millisecond)
}

View file

@ -2079,6 +2079,10 @@ func TestProviderErrors(t *testing.T) {
assert.NoError(t, err)
err = os.Remove(backupFilePath)
assert.NoError(t, err)
req, err := http.NewRequest(http.MethodGet, webUserPath+"?cloneFromId=1234", nil)
assert.NoError(t, err)
rr := executeRequest(req)
checkResponseCode(t, http.StatusInternalServerError, rr.Code)
err = config.LoadConfig(configDir, "")
assert.NoError(t, err)
providerConf := config.GetProviderConf()
@ -3320,6 +3324,47 @@ func TestWebUserUpdateMock(t *testing.T) {
checkResponseCode(t, http.StatusOK, rr.Code)
}
func TestRenderWebCloneUserMock(t *testing.T) {
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
assert.NoError(t, err)
req, err := http.NewRequest(http.MethodGet, webUserPath+"?cloneFromId=a", nil)
assert.NoError(t, err)
rr := executeRequest(req)
checkResponseCode(t, http.StatusBadRequest, rr.Code)
req, err = http.NewRequest(http.MethodGet, webUserPath+"?cloneFromId=1234", nil)
assert.NoError(t, err)
rr = executeRequest(req)
checkResponseCode(t, http.StatusNotFound, rr.Code)
req, err = http.NewRequest(http.MethodGet, webUserPath+fmt.Sprintf("?cloneFromId=%v", user.ID), nil)
assert.NoError(t, err)
rr = executeRequest(req)
checkResponseCode(t, http.StatusOK, rr.Code)
user.FsConfig = dataprovider.Filesystem{
Provider: dataprovider.CryptedFilesystemProvider,
CryptConfig: vfs.CryptFsConfig{
Passphrase: kms.NewPlainSecret("secret"),
},
}
err = user.FsConfig.CryptConfig.Passphrase.Encrypt()
assert.NoError(t, err)
user.FsConfig.CryptConfig.Passphrase.SetStatus(kms.SecretStatusAWS)
user.Password = defaultPassword
err = dataprovider.UpdateUser(user)
assert.NoError(t, err)
req, err = http.NewRequest(http.MethodGet, webUserPath+fmt.Sprintf("?cloneFromId=%v", user.ID), nil)
assert.NoError(t, err)
rr = executeRequest(req)
checkResponseCode(t, http.StatusInternalServerError, rr.Code)
_, err = httpd.RemoveUser(user, http.StatusOK)
assert.NoError(t, err)
}
func TestWebUserS3Mock(t *testing.T) {
user := getTestUser()
userAsJSON := getUserAsJSON(t, user)

View file

@ -688,6 +688,10 @@ func handleWebAddUserGet(w http.ResponseWriter, r *http.Request) {
if err == nil {
user.ID = 0
user.Username = ""
if err := user.DecryptSecrets(); err != nil {
renderInternalServerErrorPage(w, err)
return
}
renderAddUserPage(w, user, "")
} else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
renderNotFoundPage(w, err)

View file

@ -338,7 +338,7 @@
<div class="col-sm-2"></div>
<label for="idS3AccessSecret" class="col-sm-2 col-form-label">Access Secret</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="idS3AccessSecret" name="s3_access_secret" placeholder=""
<input type="password" class="form-control" id="idS3AccessSecret" name="s3_access_secret" placeholder=""
value="{{if .User.FsConfig.S3Config.AccessSecret.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.S3Config.AccessSecret.GetPayload}}{{end}}" maxlength="1000">
</div>
</div>
@ -449,7 +449,7 @@
<div class="form-group row azblob">
<label for="idAzAccountKey" class="col-sm-2 col-form-label">Account Key</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="idAzAccountKey" name="az_account_key" placeholder=""
<input type="password" class="form-control" id="idAzAccountKey" name="az_account_key" placeholder=""
value="{{if .User.FsConfig.AzBlobConfig.AccountKey.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.AzBlobConfig.AccountKey.GetPayload}}{{end}}" maxlength="1000">
</div>
</div>
@ -522,7 +522,7 @@
<div class="form-group row crypt">
<label for="idCryptPassphrase" class="col-sm-2 col-form-label">Passphrase</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="idCryptPassphrase" name="crypt_passphrase" placeholder=""
<input type="password" class="form-control" id="idCryptPassphrase" name="crypt_passphrase" placeholder=""
value="{{if .User.FsConfig.CryptConfig.Passphrase.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.CryptConfig.Passphrase.GetPayload}}{{end}}" maxlength="1000">
</div>
</div>
@ -544,7 +544,7 @@
<div class="form-group row sftp">
<label for="idSFTPPassword" class="col-sm-2 col-form-label">Password</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="idSFTPPassword" name="sftp_password" placeholder=""
<input type="password" class="form-control" id="idSFTPPassword" name="sftp_password" placeholder=""
value="{{if .User.FsConfig.SFTPConfig.Password.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.SFTPConfig.Password.GetPayload}}{{end}}" maxlength="1000">
</div>
</div>
@ -552,7 +552,7 @@
<div class="form-group row sftp">
<label for="idSFTPPrivateKey" class="col-sm-2 col-form-label">Private key</label>
<div class="col-sm-10">
<textarea type="text" class="form-control" id="idSFTPPrivateKey" name="sftp_private_key"
<textarea type="password" class="form-control" id="idSFTPPrivateKey" name="sftp_private_key"
rows="3">{{if .User.FsConfig.SFTPConfig.PrivateKey.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.SFTPConfig.PrivateKey.GetPayload}}{{end}}</textarea>
</div>
</div>

View file

@ -97,7 +97,7 @@
function deleteAction() {
var table = $('#dataTable').DataTable();
table.button(2).enable(false);
table.button(3).enable(false);
var userID = table.row({ selected: true }).data()[0];
var path = '{{.APIUserURL}}' + "/" + userID;
$('#deleteModal').modal('hide');
@ -107,12 +107,12 @@
dataType: 'json',
timeout: 15000,
success: function (result) {
table.button(2).enable(true);
table.button(3).enable(true);
window.location.href = '{{.UsersURL}}';
},
error: function ($xhr, textStatus, errorThrown) {
console.log("delete error")
table.button(2).enable(true);
table.button(3).enable(true);
var txt = "Unable to delete the selected user";
if ($xhr) {
var json = $xhr.responseJSON;
@ -173,7 +173,7 @@
$.fn.dataTable.ext.buttons.quota_scan = {
text: 'Quota scan',
action: function (e, dt, node, config) {
table.button(3).enable(false);
table.button(4).enable(false);
var username = dt.row({ selected: true }).data()[1];
var path = '{{.APIQuotaScanURL}}'
$.ajax({
@ -183,7 +183,7 @@
data: JSON.stringify({ "username": username }),
timeout: 15000,
success: function (result) {
table.button(3).enable(true);
table.button(4).enable(true);
$('#successTxt').text("Quota scan started for the selected user. Please reload the user's page to check when the scan ends");
$('#successMsg').show();
setTimeout(function () {
@ -192,7 +192,7 @@
},
error: function ($xhr, textStatus, errorThrown) {
console.log("quota scan error")
table.button(3).enable(true);
table.button(4).enable(true);
var txt = "Unable to update quota for the selected user";
if ($xhr) {
var json = $xhr.responseJSON;