mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-08 23:28:39 +03:00
@@ -719,6 +719,11 @@ func (u *User) CanManageMFA() bool {
|
|||||||
return len(mfa.GetAvailableTOTPConfigs()) > 0
|
return len(mfa.GetAvailableTOTPConfigs()) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CanChangePassword returns true if this user is allowed to change its password
|
||||||
|
func (u *User) CanChangePassword() bool {
|
||||||
|
return !util.IsStringInSlice(sdk.WebClientPasswordChangeDisabled, u.Filters.WebClient)
|
||||||
|
}
|
||||||
|
|
||||||
// CanManagePublicKeys returns true if this user is allowed to manage public keys
|
// CanManagePublicKeys returns true if this user is allowed to manage public keys
|
||||||
// from the web client. Used in web client UI
|
// from the web client. Used in web client UI
|
||||||
func (u *User) CanManagePublicKeys() bool {
|
func (u *User) CanManagePublicKeys() bool {
|
||||||
|
|||||||
@@ -304,19 +304,6 @@ then SFTPGo will try to create `id_rsa`, `id_ecdsa` and `id_ed25519`, if they ar
|
|||||||
|
|
||||||
The configuration can be read from JSON, TOML, YAML, HCL, envfile and Java properties config files. If your `config-file` flag is set to `sftpgo` (default value), you need to create a configuration file called `sftpgo.json` or `sftpgo.yaml` and so on inside `config-dir`.
|
The configuration can be read from JSON, TOML, YAML, HCL, envfile and Java properties config files. If your `config-file` flag is set to `sftpgo` (default value), you need to create a configuration file called `sftpgo.json` or `sftpgo.yaml` and so on inside `config-dir`.
|
||||||
|
|
||||||
## Binding to privileged ports
|
|
||||||
|
|
||||||
On Linux, if you want to use Internet domain privileged ports (port numbers less than 1024) instead of running the SFTPGo service as root user you can set the `cap_net_bind_service` capability on the `sftpgo` binary. To set the capability you can use the following command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ sudo setcap cap_net_bind_service=+ep /usr/bin/sftpgo
|
|
||||||
# Check that the capability is added:
|
|
||||||
$ getcap /usr/bin/sftpgo
|
|
||||||
/usr/bin/sftpgo cap_net_bind_service=ep
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you can use privileged ports such as 21, 22, 443 etc.. without running the SFTPGo service as root user. You have to set the `cap_net_bind_service` capability each time you update the `sftpgo` binary.
|
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
You can also override all the available configuration options using environment variables. SFTPGo will check for environment variables with a name matching the key uppercased and prefixed with the `SFTPGO_`. You need to use `__` to traverse a struct.
|
You can also override all the available configuration options using environment variables. SFTPGo will check for environment variables with a name matching the key uppercased and prefixed with the `SFTPGO_`. You need to use `__` to traverse a struct.
|
||||||
@@ -335,6 +322,26 @@ You can select `sha256-simd` setting the environment variable `SFTPGO_MINIO_SHA2
|
|||||||
|
|
||||||
`sha256-simd` is particularly useful if you have an Intel CPU with SHA extensions or an ARM CPU with Cryptography Extensions.
|
`sha256-simd` is particularly useful if you have an Intel CPU with SHA extensions or an ARM CPU with Cryptography Extensions.
|
||||||
|
|
||||||
|
## Binding to privileged ports
|
||||||
|
|
||||||
|
On Linux, if you want to use Internet domain privileged ports (port numbers less than 1024) instead of running the SFTPGo service as root user you can set the `cap_net_bind_service` capability on the `sftpgo` binary. To set the capability you can use the following command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ sudo setcap cap_net_bind_service=+ep /usr/bin/sftpgo
|
||||||
|
# Check that the capability is added
|
||||||
|
$ getcap /usr/bin/sftpgo
|
||||||
|
/usr/bin/sftpgo cap_net_bind_service=ep
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can use privileged ports such as 21, 22, 443 etc.. without running the SFTPGo service as root user. You have to set the `cap_net_bind_service` capability each time you update the `sftpgo` binary.
|
||||||
|
|
||||||
|
An alternative method is to use `iptables`, for example you run the SFTP service on port `2022` and redirect traffic from port `22` to port `2022`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo iptables -t nat -A PREROUTING -d <ip> -p tcp --dport 22 -m addrtype --dst-type LOCAL -j DNAT --to-destination <ip>:2022
|
||||||
|
sudo iptables -t nat -A OUTPUT -d <ip> -p tcp --dport 22 -m addrtype --dst-type LOCAL -j DNAT --to-destination <ip>:2022
|
||||||
|
```
|
||||||
|
|
||||||
## Telemetry Server
|
## Telemetry Server
|
||||||
|
|
||||||
The telemetry server exposes the following endpoints:
|
The telemetry server exposes the following endpoints:
|
||||||
|
|||||||
@@ -5854,6 +5854,27 @@ func TestWebAPIChangeUserPwdMock(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, token)
|
assert.NotEmpty(t, token)
|
||||||
|
|
||||||
|
// remove the change password permission
|
||||||
|
user.Filters.WebClient = []string{sdk.WebClientPasswordChangeDisabled}
|
||||||
|
user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, user.Filters.WebClient, 1)
|
||||||
|
assert.Contains(t, user.Filters.WebClient, sdk.WebClientPasswordChangeDisabled)
|
||||||
|
|
||||||
|
token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, altAdminPassword)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, token)
|
||||||
|
|
||||||
|
pwd["current_password"] = altAdminPassword
|
||||||
|
pwd["new_password"] = defaultPassword
|
||||||
|
asJSON, err = json.Marshal(pwd)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
req, err = http.NewRequest(http.MethodPut, userPwdPath, bytes.NewBuffer(asJSON))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
setBearerForReq(req, token)
|
||||||
|
rr = executeRequest(req)
|
||||||
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
err = os.RemoveAll(user.GetHomeDir())
|
err = os.RemoveAll(user.GetHomeDir())
|
||||||
@@ -7568,6 +7589,24 @@ func TestWebClientChangePwd(t *testing.T) {
|
|||||||
_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword+"1")
|
_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword+"1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// remove the change password permission
|
||||||
|
user.Filters.WebClient = []string{sdk.WebClientPasswordChangeDisabled}
|
||||||
|
user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, user.Filters.WebClient, 1)
|
||||||
|
assert.Contains(t, user.Filters.WebClient, sdk.WebClientPasswordChangeDisabled)
|
||||||
|
|
||||||
|
webToken, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword+"1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
form.Set("current_password", defaultPassword+"1")
|
||||||
|
form.Set("new_password1", defaultPassword)
|
||||||
|
form.Set("new_password2", defaultPassword)
|
||||||
|
req, _ = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode())))
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
setJWTCookieForReq(req, webToken)
|
||||||
|
rr = executeRequest(req)
|
||||||
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
err = os.RemoveAll(user.GetHomeDir())
|
err = os.RemoveAll(user.GetHomeDir())
|
||||||
|
|||||||
@@ -3025,11 +3025,13 @@ components:
|
|||||||
- publickey-change-disabled
|
- publickey-change-disabled
|
||||||
- write-disabled
|
- write-disabled
|
||||||
- mfa-disabled
|
- mfa-disabled
|
||||||
|
- password-change-disabled
|
||||||
description: |
|
description: |
|
||||||
Options:
|
Options:
|
||||||
* `publickey-change-disabled` - changing SSH public keys is not allowed
|
* `publickey-change-disabled` - changing SSH public keys is not allowed
|
||||||
* `write-disabled` - upload, rename, delete are not allowed even if the user has permissions for these actions
|
* `write-disabled` - upload, rename, delete are not allowed even if the user has permissions for these actions
|
||||||
* `mfa-disabled` - the user cannot enable multi-factor authentication. This option cannot be set if the user has MFA already enabled
|
* `mfa-disabled` - enabling multi-factor authentication is not allowed. This option cannot be set if the user has MFA already enabled
|
||||||
|
* `password-change-disabled` - changing password is not allowed
|
||||||
APIKeyScope:
|
APIKeyScope:
|
||||||
type: integer
|
type: integer
|
||||||
enum:
|
enum:
|
||||||
|
|||||||
@@ -988,7 +988,8 @@ func (s *httpdServer) initializeRouter() {
|
|||||||
router.Use(jwtAuthenticatorAPIUser)
|
router.Use(jwtAuthenticatorAPIUser)
|
||||||
|
|
||||||
router.With(forbidAPIKeyAuthentication).Get(userLogoutPath, s.logout)
|
router.With(forbidAPIKeyAuthentication).Get(userLogoutPath, s.logout)
|
||||||
router.With(forbidAPIKeyAuthentication).Put(userPwdPath, changeUserPassword)
|
router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientPasswordChangeDisabled)).
|
||||||
|
Put(userPwdPath, changeUserPassword)
|
||||||
router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).
|
router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).
|
||||||
Get(userPublicKeysPath, getUserPublicKeys)
|
Get(userPublicKeysPath, getUserPublicKeys)
|
||||||
router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).
|
router.With(forbidAPIKeyAuthentication, checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).
|
||||||
@@ -1089,7 +1090,8 @@ func (s *httpdServer) initializeRouter() {
|
|||||||
Delete(webClientDirsPath, deleteUserDir)
|
Delete(webClientDirsPath, deleteUserDir)
|
||||||
router.With(s.refreshCookie).Get(webClientDownloadZipPath, handleWebClientDownloadZip)
|
router.With(s.refreshCookie).Get(webClientDownloadZipPath, handleWebClientDownloadZip)
|
||||||
router.With(s.refreshCookie).Get(webClientCredentialsPath, handleClientGetCredentials)
|
router.With(s.refreshCookie).Get(webClientCredentialsPath, handleClientGetCredentials)
|
||||||
router.Post(webChangeClientPwdPath, handleWebClientChangePwdPost)
|
router.With(checkHTTPUserPerm(sdk.WebClientPasswordChangeDisabled)).
|
||||||
|
Post(webChangeClientPwdPath, handleWebClientChangePwdPost)
|
||||||
router.Post(webChangeClientAPIKeyAccessPath, handleWebClientManageAPIKeyPost)
|
router.Post(webChangeClientAPIKeyAccessPath, handleWebClientManageAPIKeyPost)
|
||||||
router.With(checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).
|
router.With(checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).
|
||||||
Post(webChangeClientKeysPath, handleWebClientManageKeysPost)
|
Post(webChangeClientKeysPath, handleWebClientManageKeysPost)
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ const (
|
|||||||
WebClientPubKeyChangeDisabled = "publickey-change-disabled"
|
WebClientPubKeyChangeDisabled = "publickey-change-disabled"
|
||||||
WebClientWriteDisabled = "write-disabled"
|
WebClientWriteDisabled = "write-disabled"
|
||||||
WebClientMFADisabled = "mfa-disabled"
|
WebClientMFADisabled = "mfa-disabled"
|
||||||
|
WebClientPasswordChangeDisabled = "password-change-disabled"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// WebClientOptions defines the available options for the web client interface/user REST API
|
// WebClientOptions defines the available options for the web client interface/user REST API
|
||||||
WebClientOptions = []string{WebClientPubKeyChangeDisabled, WebClientWriteDisabled, WebClientMFADisabled}
|
WebClientOptions = []string{WebClientPubKeyChangeDisabled, WebClientWriteDisabled, WebClientMFADisabled,
|
||||||
|
WebClientPasswordChangeDisabled}
|
||||||
// UserTypes defines the supported user type hints for auth plugins
|
// UserTypes defines the supported user type hints for auth plugins
|
||||||
UserTypes = []string{string(UserTypeLDAP), string(UserTypeOS)}
|
UserTypes = []string{string(UserTypeLDAP), string(UserTypeOS)}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
{{define "page_body"}}
|
{{define "page_body"}}
|
||||||
|
|
||||||
|
{{if .LoggedUser.CanChangePassword}}
|
||||||
<div class="card shadow mb-4">
|
<div class="card shadow mb-4">
|
||||||
<div class="card-header py-3">
|
<div class="card-header py-3">
|
||||||
<h6 class="m-0 font-weight-bold text-primary">Change password</h6>
|
<h6 class="m-0 font-weight-bold text-primary">Change password</h6>
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
{{if .LoggedUser.CanManagePublicKeys}}
|
{{if .LoggedUser.CanManagePublicKeys}}
|
||||||
<div class="card shadow mb-4">
|
<div class="card shadow mb-4">
|
||||||
<div class="card-header py-3">
|
<div class="card-header py-3">
|
||||||
|
|||||||
Reference in New Issue
Block a user