1package httpd_test 2 3import ( 4 "bytes" 5 "crypto/rand" 6 "encoding/json" 7 "errors" 8 "fmt" 9 "io" 10 "math" 11 "mime/multipart" 12 "net" 13 "net/http" 14 "net/http/httptest" 15 "net/url" 16 "os" 17 "path" 18 "path/filepath" 19 "regexp" 20 "runtime" 21 "strconv" 22 "strings" 23 "sync" 24 "testing" 25 "time" 26 27 "github.com/go-chi/render" 28 _ "github.com/go-sql-driver/mysql" 29 _ "github.com/lib/pq" 30 "github.com/lithammer/shortuuid/v3" 31 _ "github.com/mattn/go-sqlite3" 32 "github.com/mhale/smtpd" 33 "github.com/pquerna/otp" 34 "github.com/pquerna/otp/totp" 35 "github.com/rs/xid" 36 "github.com/rs/zerolog" 37 "github.com/stretchr/testify/assert" 38 "github.com/stretchr/testify/require" 39 "golang.org/x/crypto/bcrypt" 40 "golang.org/x/net/html" 41 42 "github.com/drakkan/sftpgo/v2/common" 43 "github.com/drakkan/sftpgo/v2/config" 44 "github.com/drakkan/sftpgo/v2/dataprovider" 45 "github.com/drakkan/sftpgo/v2/httpclient" 46 "github.com/drakkan/sftpgo/v2/httpd" 47 "github.com/drakkan/sftpgo/v2/httpdtest" 48 "github.com/drakkan/sftpgo/v2/kms" 49 "github.com/drakkan/sftpgo/v2/logger" 50 "github.com/drakkan/sftpgo/v2/mfa" 51 "github.com/drakkan/sftpgo/v2/sdk" 52 "github.com/drakkan/sftpgo/v2/sdk/plugin" 53 "github.com/drakkan/sftpgo/v2/sftpd" 54 "github.com/drakkan/sftpgo/v2/smtp" 55 "github.com/drakkan/sftpgo/v2/util" 56 "github.com/drakkan/sftpgo/v2/vfs" 57) 58 59const ( 60 defaultUsername = "test_user" 61 defaultPassword = "test_password" 62 testPubKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1" 63 testPubKey1 = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCd60+/j+y8f0tLftihWV1YN9RSahMI9btQMDIMqts/jeNbD8jgoogM3nhF7KxfcaMKURuD47KC4Ey6iAJUJ0sWkSNNxOcIYuvA+5MlspfZDsa8Ag76Fe1vyz72WeHMHMeh/hwFo2TeIeIXg480T1VI6mzfDrVp2GzUx0SS0dMsQBjftXkuVR8YOiOwMCAH2a//M1OrvV7d/NBk6kBN0WnuIBb2jKm15PAA7+jQQG7tzwk2HedNH3jeL5GH31xkSRwlBczRK0xsCQXehAlx6cT/e/s44iJcJTHfpPKoSk6UAhPJYe7Z1QnuoawY9P9jQaxpyeImBZxxUEowhjpj2avBxKdRGBVK8R7EL8tSOeLbhdyWe5Mwc1+foEbq9Zz5j5Kd+hn3Wm1UnsGCrXUUUoZp1jnlNl0NakCto+5KmqnT9cHxaY+ix2RLUWAZyVFlRq71OYux1UHJnEJPiEI1/tr4jFBSL46qhQZv/TfpkfVW8FLz0lErfqu0gQEZnNHr3Fc= nicola@p1" 64 defaultTokenAuthUser = "admin" 65 defaultTokenAuthPass = "password" 66 altAdminUsername = "newTestAdmin" 67 altAdminPassword = "password1" 68 csrfFormToken = "_form_token" 69 tokenPath = "/api/v2/token" 70 userTokenPath = "/api/v2/user/token" 71 userLogoutPath = "/api/v2/user/logout" 72 userPath = "/api/v2/users" 73 adminPath = "/api/v2/admins" 74 adminPwdPath = "/api/v2/admin/changepwd" 75 folderPath = "/api/v2/folders" 76 activeConnectionsPath = "/api/v2/connections" 77 serverStatusPath = "/api/v2/status" 78 quotasBasePath = "/api/v2/quotas" 79 quotaScanPath = "/api/v2/quotas/users/scans" 80 quotaScanVFolderPath = "/api/v2/quotas/folders/scans" 81 quotaScanCompatPath = "/api/v2/quota-scans" 82 quotaScanVFolderCompatPath = "/api/v2/folder-quota-scans" 83 updateUsedQuotaCompatPath = "/api/v2/quota-update" 84 updateFolderUsedQuotaCompatPath = "/api/v2/folder-quota-update" 85 defenderHosts = "/api/v2/defender/hosts" 86 defenderUnban = "/api/v2/defender/unban" 87 versionPath = "/api/v2/version" 88 logoutPath = "/api/v2/logout" 89 userPwdPath = "/api/v2/user/changepwd" 90 userPublicKeysPath = "/api/v2/user/publickeys" 91 userDirsPath = "/api/v2/user/dirs" 92 userFilesPath = "/api/v2/user/files" 93 userStreamZipPath = "/api/v2/user/streamzip" 94 apiKeysPath = "/api/v2/apikeys" 95 adminTOTPConfigsPath = "/api/v2/admin/totp/configs" 96 adminTOTPGeneratePath = "/api/v2/admin/totp/generate" 97 adminTOTPValidatePath = "/api/v2/admin/totp/validate" 98 adminTOTPSavePath = "/api/v2/admin/totp/save" 99 admin2FARecoveryCodesPath = "/api/v2/admin/2fa/recoverycodes" 100 adminProfilePath = "/api/v2/admin/profile" 101 userTOTPConfigsPath = "/api/v2/user/totp/configs" 102 userTOTPGeneratePath = "/api/v2/user/totp/generate" 103 userTOTPValidatePath = "/api/v2/user/totp/validate" 104 userTOTPSavePath = "/api/v2/user/totp/save" 105 user2FARecoveryCodesPath = "/api/v2/user/2fa/recoverycodes" 106 userProfilePath = "/api/v2/user/profile" 107 userSharesPath = "/api/v2/user/shares" 108 retentionBasePath = "/api/v2/retention/users" 109 fsEventsPath = "/api/v2/events/fs" 110 providerEventsPath = "/api/v2/events/provider" 111 sharesPath = "/api/v2/shares" 112 healthzPath = "/healthz" 113 webBasePath = "/web" 114 webBasePathAdmin = "/web/admin" 115 webAdminSetupPath = "/web/admin/setup" 116 webLoginPath = "/web/admin/login" 117 webLogoutPath = "/web/admin/logout" 118 webUsersPath = "/web/admin/users" 119 webUserPath = "/web/admin/user" 120 webFoldersPath = "/web/admin/folders" 121 webFolderPath = "/web/admin/folder" 122 webConnectionsPath = "/web/admin/connections" 123 webStatusPath = "/web/admin/status" 124 webAdminsPath = "/web/admin/managers" 125 webAdminPath = "/web/admin/manager" 126 webMaintenancePath = "/web/admin/maintenance" 127 webRestorePath = "/web/admin/restore" 128 webChangeAdminPwdPath = "/web/admin/changepwd" 129 webAdminProfilePath = "/web/admin/profile" 130 webTemplateUser = "/web/admin/template/user" 131 webTemplateFolder = "/web/admin/template/folder" 132 webDefenderPath = "/web/admin/defender" 133 webAdminTwoFactorPath = "/web/admin/twofactor" 134 webAdminTwoFactorRecoveryPath = "/web/admin/twofactor-recovery" 135 webAdminMFAPath = "/web/admin/mfa" 136 webAdminTOTPSavePath = "/web/admin/totp/save" 137 webAdminForgotPwdPath = "/web/admin/forgot-password" 138 webAdminResetPwdPath = "/web/admin/reset-password" 139 webBasePathClient = "/web/client" 140 webClientLoginPath = "/web/client/login" 141 webClientFilesPath = "/web/client/files" 142 webClientEditFilePath = "/web/client/editfile" 143 webClientDirsPath = "/web/client/dirs" 144 webClientDownloadZipPath = "/web/client/downloadzip" 145 webChangeClientPwdPath = "/web/client/changepwd" 146 webClientProfilePath = "/web/client/profile" 147 webClientTwoFactorPath = "/web/client/twofactor" 148 webClientTwoFactorRecoveryPath = "/web/client/twofactor-recovery" 149 webClientLogoutPath = "/web/client/logout" 150 webClientMFAPath = "/web/client/mfa" 151 webClientTOTPSavePath = "/web/client/totp/save" 152 webClientSharesPath = "/web/client/shares" 153 webClientSharePath = "/web/client/share" 154 webClientPubSharesPath = "/web/client/pubshares" 155 webClientForgotPwdPath = "/web/client/forgot-password" 156 webClientResetPwdPath = "/web/client/reset-password" 157 webClientViewPDFPath = "/web/client/viewpdf" 158 httpBaseURL = "http://127.0.0.1:8081" 159 sftpServerAddr = "127.0.0.1:8022" 160 smtpServerAddr = "127.0.0.1:3525" 161 configDir = ".." 162 httpsCert = `-----BEGIN CERTIFICATE----- 163MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw 164RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu 165dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw 166OTUzMDRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD 167VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQA 168IgNiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVqWvrJ51t5OxV0v25NsOgR82CA 169NXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIVCzgWkxiz7XE4lgUwX44FCXZM 1703+JeUbKjUzBRMB0GA1UdDgQWBBRhLw+/o3+Z02MI/d4tmaMui9W16jAfBgNVHSME 171GDAWgBRhLw+/o3+Z02MI/d4tmaMui9W16jAPBgNVHRMBAf8EBTADAQH/MAoGCCqG 172SM49BAMCA2kAMGYCMQDqLt2lm8mE+tGgtjDmtFgdOcI72HSbRQ74D5rYTzgST1rY 173/8wTi5xl8TiFUyLMUsICMQC5ViVxdXbhuG7gX6yEqSkMKZICHpO8hqFwOD/uaFVI 174dV4vKmHUzwK/eIx+8Ay3neE= 175-----END CERTIFICATE-----` 176 httpsKey = `-----BEGIN EC PARAMETERS----- 177BgUrgQQAIg== 178-----END EC PARAMETERS----- 179-----BEGIN EC PRIVATE KEY----- 180MIGkAgEBBDCfMNsN6miEE3rVyUPwElfiJSWaR5huPCzUenZOfJT04GAcQdWvEju3 181UM2lmBLIXpGgBwYFK4EEACKhZANiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVq 182WvrJ51t5OxV0v25NsOgR82CANXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIV 183CzgWkxiz7XE4lgUwX44FCXZM3+JeUbI= 184-----END EC PRIVATE KEY-----` 185 sftpPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- 186b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW 187QyNTUxOQAAACB+RB4yNTZz9mHOkawwUibNdemijVV3ErMeLxWUBlCN/gAAAJA7DjpfOw46 188XwAAAAtzc2gtZWQyNTUxOQAAACB+RB4yNTZz9mHOkawwUibNdemijVV3ErMeLxWUBlCN/g 189AAAEA0E24gi8ab/XRSvJ85TGZJMe6HVmwxSG4ExPfTMwwe2n5EHjI1NnP2Yc6RrDBSJs11 1906aKNVXcSsx4vFZQGUI3+AAAACW5pY29sYUBwMQECAwQ= 191-----END OPENSSH PRIVATE KEY-----` 192 sftpPkeyFingerprint = "SHA256:QVQ06XHZZbYZzqfrsZcf3Yozy2WTnqQPeLOkcJCdbP0" 193 redactedSecret = "[**redacted**]" 194 osWindows = "windows" 195) 196 197var ( 198 defaultPerms = []string{dataprovider.PermAny} 199 homeBasePath string 200 backupsPath string 201 credentialsPath string 202 testServer *httptest.Server 203 providerDriverName string 204 postConnectPath string 205 preActionPath string 206 lastResetCode string 207) 208 209type fakeConnection struct { 210 *common.BaseConnection 211 command string 212} 213 214func (c *fakeConnection) Disconnect() error { 215 common.Connections.Remove(c.GetID()) 216 return nil 217} 218 219func (c *fakeConnection) GetClientVersion() string { 220 return "" 221} 222 223func (c *fakeConnection) GetCommand() string { 224 return c.command 225} 226 227func (c *fakeConnection) GetLocalAddress() string { 228 return "" 229} 230 231func (c *fakeConnection) GetRemoteAddress() string { 232 return "" 233} 234 235type generateTOTPRequest struct { 236 ConfigName string `json:"config_name"` 237} 238 239type generateTOTPResponse struct { 240 ConfigName string `json:"config_name"` 241 Issuer string `json:"issuer"` 242 Secret string `json:"secret"` 243 QRCode []byte `json:"qr_code"` 244} 245 246type validateTOTPRequest struct { 247 ConfigName string `json:"config_name"` 248 Passcode string `json:"passcode"` 249 Secret string `json:"secret"` 250} 251 252type recoveryCode struct { 253 Code string `json:"code"` 254 Used bool `json:"used"` 255} 256 257func TestMain(m *testing.M) { 258 homeBasePath = os.TempDir() 259 logfilePath := filepath.Join(configDir, "sftpgo_api_test.log") 260 logger.InitLogger(logfilePath, 5, 1, 28, false, false, zerolog.DebugLevel) 261 os.Setenv("SFTPGO_COMMON__UPLOAD_MODE", "2") 262 os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1") 263 os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin") 264 os.Setenv("SFTPGO_DEFAULT_ADMIN_PASSWORD", "password") 265 err := config.LoadConfig(configDir, "") 266 if err != nil { 267 logger.WarnToConsole("error loading configuration: %v", err) 268 os.Exit(1) 269 } 270 wdPath, err := os.Getwd() 271 if err != nil { 272 logger.WarnToConsole("error getting exe path: %v", err) 273 os.Exit(1) 274 } 275 pluginsConfig := []plugin.Config{ 276 { 277 Type: "eventsearcher", 278 Cmd: filepath.Join(wdPath, "..", "tests", "eventsearcher", "eventsearcher"), 279 AutoMTLS: true, 280 }, 281 } 282 if runtime.GOOS == osWindows { 283 pluginsConfig[0].Cmd += ".exe" 284 } 285 providerConf := config.GetProviderConf() 286 credentialsPath = filepath.Join(os.TempDir(), "test_credentials") 287 providerConf.CredentialsPath = credentialsPath 288 providerDriverName = providerConf.Driver 289 os.RemoveAll(credentialsPath) //nolint:errcheck 290 logger.InfoToConsole("Starting HTTPD tests, provider: %v", providerConf.Driver) 291 292 err = common.Initialize(config.GetCommonConfig()) 293 if err != nil { 294 logger.WarnToConsole("error initializing common: %v", err) 295 os.Exit(1) 296 } 297 298 err = dataprovider.Initialize(providerConf, configDir, true) 299 if err != nil { 300 logger.WarnToConsole("error initializing data provider: %v", err) 301 os.Exit(1) 302 } 303 304 postConnectPath = filepath.Join(homeBasePath, "postconnect.sh") 305 preActionPath = filepath.Join(homeBasePath, "preaction.sh") 306 307 httpConfig := config.GetHTTPConfig() 308 httpConfig.Initialize(configDir) //nolint:errcheck 309 kmsConfig := config.GetKMSConfig() 310 err = kmsConfig.Initialize() 311 if err != nil { 312 logger.ErrorToConsole("error initializing kms: %v", err) 313 os.Exit(1) 314 } 315 mfaConfig := config.GetMFAConfig() 316 err = mfaConfig.Initialize() 317 if err != nil { 318 logger.ErrorToConsole("error initializing MFA: %v", err) 319 os.Exit(1) 320 } 321 err = plugin.Initialize(pluginsConfig, true) 322 if err != nil { 323 logger.ErrorToConsole("error initializing plugin: %v", err) 324 os.Exit(1) 325 } 326 327 httpdConf := config.GetHTTPDConfig() 328 329 httpdConf.Bindings[0].Port = 8081 330 httpdtest.SetBaseURL(httpBaseURL) 331 backupsPath = filepath.Join(os.TempDir(), "test_backups") 332 httpdConf.BackupsPath = backupsPath 333 err = os.MkdirAll(backupsPath, os.ModePerm) 334 if err != nil { 335 logger.ErrorToConsole("error creating backups path: %v", err) 336 os.Exit(1) 337 } 338 339 // required to test sftpfs 340 sftpdConf := config.GetSFTPDConfig() 341 sftpdConf.Bindings = []sftpd.Binding{ 342 { 343 Port: 8022, 344 }, 345 } 346 hostKeyPath := filepath.Join(os.TempDir(), "id_rsa") 347 sftpdConf.HostKeys = []string{hostKeyPath} 348 349 go func() { 350 if err := httpdConf.Initialize(configDir); err != nil { 351 logger.ErrorToConsole("could not start HTTP server: %v", err) 352 os.Exit(1) 353 } 354 }() 355 356 go func() { 357 if err := sftpdConf.Initialize(configDir); err != nil { 358 logger.ErrorToConsole("could not start SFTP server: %v", err) 359 os.Exit(1) 360 } 361 }() 362 363 startSMTPServer() 364 365 waitTCPListening(httpdConf.Bindings[0].GetAddress()) 366 waitTCPListening(sftpdConf.Bindings[0].GetAddress()) 367 httpd.ReloadCertificateMgr() //nolint:errcheck 368 // now start an https server 369 certPath := filepath.Join(os.TempDir(), "test.crt") 370 keyPath := filepath.Join(os.TempDir(), "test.key") 371 err = os.WriteFile(certPath, []byte(httpsCert), os.ModePerm) 372 if err != nil { 373 logger.ErrorToConsole("error writing HTTPS certificate: %v", err) 374 os.Exit(1) 375 } 376 err = os.WriteFile(keyPath, []byte(httpsKey), os.ModePerm) 377 if err != nil { 378 logger.ErrorToConsole("error writing HTTPS private key: %v", err) 379 os.Exit(1) 380 } 381 httpdConf.Bindings[0].Port = 8443 382 httpdConf.Bindings[0].EnableHTTPS = true 383 httpdConf.CertificateFile = certPath 384 httpdConf.CertificateKeyFile = keyPath 385 httpdConf.Bindings = append(httpdConf.Bindings, httpd.Binding{}) 386 387 go func() { 388 if err := httpdConf.Initialize(configDir); err != nil { 389 logger.ErrorToConsole("could not start HTTPS server: %v", err) 390 os.Exit(1) 391 } 392 }() 393 waitTCPListening(httpdConf.Bindings[0].GetAddress()) 394 httpd.ReloadCertificateMgr() //nolint:errcheck 395 396 testServer = httptest.NewServer(httpd.GetHTTPRouter()) 397 defer testServer.Close() 398 399 exitCode := m.Run() 400 os.Remove(logfilePath) 401 os.RemoveAll(backupsPath) 402 os.RemoveAll(credentialsPath) 403 os.Remove(certPath) 404 os.Remove(keyPath) 405 os.Remove(hostKeyPath) 406 os.Remove(hostKeyPath + ".pub") 407 os.Remove(postConnectPath) 408 os.Remove(preActionPath) 409 os.Exit(exitCode) 410} 411 412func TestInitialization(t *testing.T) { 413 err := config.LoadConfig(configDir, "") 414 assert.NoError(t, err) 415 invalidFile := "invalid file" 416 httpdConf := config.GetHTTPDConfig() 417 defaultTemplatesPath := httpdConf.TemplatesPath 418 defaultStaticPath := httpdConf.StaticFilesPath 419 httpdConf.BackupsPath = backupsPath 420 httpdConf.CertificateFile = invalidFile 421 httpdConf.CertificateKeyFile = invalidFile 422 err = httpdConf.Initialize(configDir) 423 assert.Error(t, err) 424 httpdConf.CertificateFile = "" 425 httpdConf.CertificateKeyFile = "" 426 httpdConf.TemplatesPath = "." 427 err = httpdConf.Initialize(configDir) 428 assert.Error(t, err) 429 httpdConf = config.GetHTTPDConfig() 430 httpdConf.TemplatesPath = defaultTemplatesPath 431 httpdConf.BackupsPath = ".." 432 err = httpdConf.Initialize(configDir) 433 assert.Error(t, err) 434 httpdConf.BackupsPath = backupsPath 435 httpdConf.CertificateFile = invalidFile 436 httpdConf.CertificateKeyFile = invalidFile 437 httpdConf.StaticFilesPath = "" 438 httpdConf.TemplatesPath = "" 439 err = httpdConf.Initialize(configDir) 440 assert.Error(t, err) 441 httpdConf.StaticFilesPath = defaultStaticPath 442 httpdConf.TemplatesPath = defaultTemplatesPath 443 httpdConf.CertificateFile = filepath.Join(os.TempDir(), "test.crt") 444 httpdConf.CertificateKeyFile = filepath.Join(os.TempDir(), "test.key") 445 httpdConf.CACertificates = append(httpdConf.CACertificates, invalidFile) 446 err = httpdConf.Initialize(configDir) 447 assert.Error(t, err) 448 httpdConf.CACertificates = nil 449 httpdConf.CARevocationLists = append(httpdConf.CARevocationLists, invalidFile) 450 err = httpdConf.Initialize(configDir) 451 assert.Error(t, err) 452 httpdConf.CARevocationLists = nil 453 httpdConf.Bindings[0].ProxyAllowed = []string{"invalid ip/network"} 454 err = httpdConf.Initialize(configDir) 455 if assert.Error(t, err) { 456 assert.Contains(t, err.Error(), "is not a valid IP range") 457 } 458 httpdConf.Bindings[0].ProxyAllowed = nil 459 httpdConf.Bindings[0].EnableWebAdmin = false 460 httpdConf.Bindings[0].EnableWebClient = false 461 httpdConf.Bindings[0].Port = 8081 462 httpdConf.Bindings[0].EnableHTTPS = true 463 httpdConf.Bindings[0].ClientAuthType = 1 464 err = httpdConf.Initialize(configDir) 465 assert.Error(t, err) 466} 467 468func TestBasicUserHandling(t *testing.T) { 469 u := getTestUser() 470 u.Email = "user@user.com" 471 user, resp, err := httpdtest.AddUser(u, http.StatusCreated) 472 assert.NoError(t, err, string(resp)) 473 user.MaxSessions = 10 474 user.QuotaSize = 4096 475 user.QuotaFiles = 2 476 user.UploadBandwidth = 128 477 user.DownloadBandwidth = 64 478 user.ExpirationDate = util.GetTimeAsMsSinceEpoch(time.Now()) 479 user.AdditionalInfo = "some free text" 480 user.Filters.TLSUsername = sdk.TLSUsernameCN 481 user.Email = "user@example.net" 482 user.Filters.WebClient = append(user.Filters.WebClient, sdk.WebClientPubKeyChangeDisabled, 483 sdk.WebClientWriteDisabled) 484 originalUser := user 485 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 486 assert.NoError(t, err) 487 assert.Equal(t, originalUser.ID, user.ID) 488 489 user, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusOK) 490 assert.NoError(t, err) 491 492 user.Email = "invalid@email" 493 _, body, err := httpdtest.UpdateUser(user, http.StatusBadRequest, "") 494 assert.NoError(t, err) 495 assert.Contains(t, string(body), "Validation error: email") 496 497 _, err = httpdtest.RemoveUser(user, http.StatusOK) 498 assert.NoError(t, err) 499} 500 501func TestUserTimestamps(t *testing.T) { 502 user, resp, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 503 assert.NoError(t, err, string(resp)) 504 createdAt := user.CreatedAt 505 updatedAt := user.UpdatedAt 506 assert.Equal(t, int64(0), user.LastLogin) 507 assert.Greater(t, createdAt, int64(0)) 508 assert.Greater(t, updatedAt, int64(0)) 509 mappedPath := filepath.Join(os.TempDir(), "mapped_dir") 510 folderName := filepath.Base(mappedPath) 511 user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{ 512 BaseVirtualFolder: vfs.BaseVirtualFolder{ 513 Name: folderName, 514 MappedPath: mappedPath, 515 }, 516 VirtualPath: "/vdir", 517 }) 518 time.Sleep(10 * time.Millisecond) 519 user, resp, err = httpdtest.UpdateUser(user, http.StatusOK, "") 520 assert.NoError(t, err, string(resp)) 521 assert.Equal(t, int64(0), user.LastLogin) 522 assert.Equal(t, createdAt, user.CreatedAt) 523 assert.Greater(t, user.UpdatedAt, updatedAt) 524 updatedAt = user.UpdatedAt 525 // after a folder update or delete the user updated_at field should change 526 folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK) 527 assert.NoError(t, err) 528 assert.Len(t, folder.Users, 1) 529 time.Sleep(10 * time.Millisecond) 530 _, _, err = httpdtest.UpdateFolder(folder, http.StatusOK) 531 assert.NoError(t, err) 532 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 533 assert.NoError(t, err) 534 assert.Equal(t, int64(0), user.LastLogin) 535 assert.Equal(t, createdAt, user.CreatedAt) 536 assert.Greater(t, user.UpdatedAt, updatedAt) 537 updatedAt = user.UpdatedAt 538 time.Sleep(10 * time.Millisecond) 539 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 540 assert.NoError(t, err) 541 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 542 assert.NoError(t, err) 543 assert.Equal(t, int64(0), user.LastLogin) 544 assert.Equal(t, createdAt, user.CreatedAt) 545 assert.Greater(t, user.UpdatedAt, updatedAt) 546 547 err = os.RemoveAll(user.GetHomeDir()) 548 assert.NoError(t, err) 549 _, err = httpdtest.RemoveUser(user, http.StatusOK) 550 assert.NoError(t, err) 551} 552 553func TestAdminTimestamps(t *testing.T) { 554 admin := getTestAdmin() 555 admin.Username = altAdminUsername 556 admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) 557 assert.NoError(t, err) 558 createdAt := admin.CreatedAt 559 updatedAt := admin.UpdatedAt 560 assert.Equal(t, int64(0), admin.LastLogin) 561 assert.Greater(t, createdAt, int64(0)) 562 assert.Greater(t, updatedAt, int64(0)) 563 time.Sleep(10 * time.Millisecond) 564 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 565 assert.NoError(t, err) 566 assert.Equal(t, int64(0), admin.LastLogin) 567 assert.Equal(t, createdAt, admin.CreatedAt) 568 assert.Greater(t, admin.UpdatedAt, updatedAt) 569 570 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 571 assert.NoError(t, err) 572} 573 574func TestHTTPUserAuthentication(t *testing.T) { 575 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 576 assert.NoError(t, err) 577 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 578 assert.NoError(t, err) 579 req.SetBasicAuth(defaultUsername, defaultPassword) 580 c := httpclient.GetHTTPClient() 581 resp, err := c.Do(req) 582 c.CloseIdleConnections() 583 assert.NoError(t, err) 584 assert.Equal(t, http.StatusOK, resp.StatusCode) 585 responseHolder := make(map[string]interface{}) 586 err = render.DecodeJSON(resp.Body, &responseHolder) 587 assert.NoError(t, err) 588 userToken := responseHolder["access_token"].(string) 589 assert.NotEmpty(t, userToken) 590 err = resp.Body.Close() 591 assert.NoError(t, err) 592 // login with wrong credentials 593 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 594 assert.NoError(t, err) 595 req.SetBasicAuth(defaultUsername, "") 596 resp, err = httpclient.GetHTTPClient().Do(req) 597 assert.NoError(t, err) 598 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 599 err = resp.Body.Close() 600 assert.NoError(t, err) 601 602 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 603 assert.NoError(t, err) 604 resp, err = httpclient.GetHTTPClient().Do(req) 605 assert.NoError(t, err) 606 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 607 err = resp.Body.Close() 608 assert.NoError(t, err) 609 610 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 611 assert.NoError(t, err) 612 req.SetBasicAuth(defaultUsername, "wrong pwd") 613 resp, err = httpclient.GetHTTPClient().Do(req) 614 assert.NoError(t, err) 615 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 616 respBody, err := io.ReadAll(resp.Body) 617 assert.NoError(t, err) 618 assert.Contains(t, string(respBody), "invalid credentials") 619 err = resp.Body.Close() 620 assert.NoError(t, err) 621 622 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 623 assert.NoError(t, err) 624 req.SetBasicAuth("wrong username", defaultPassword) 625 resp, err = httpclient.GetHTTPClient().Do(req) 626 assert.NoError(t, err) 627 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 628 respBody, err = io.ReadAll(resp.Body) 629 assert.NoError(t, err) 630 assert.Contains(t, string(respBody), "invalid credentials") 631 err = resp.Body.Close() 632 assert.NoError(t, err) 633 634 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil) 635 assert.NoError(t, err) 636 req.SetBasicAuth(defaultTokenAuthUser, defaultTokenAuthPass) 637 resp, err = httpclient.GetHTTPClient().Do(req) 638 assert.NoError(t, err) 639 assert.Equal(t, http.StatusOK, resp.StatusCode) 640 responseHolder = make(map[string]interface{}) 641 err = render.DecodeJSON(resp.Body, &responseHolder) 642 assert.NoError(t, err) 643 adminToken := responseHolder["access_token"].(string) 644 assert.NotEmpty(t, adminToken) 645 err = resp.Body.Close() 646 assert.NoError(t, err) 647 648 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, versionPath), nil) 649 assert.NoError(t, err) 650 req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", adminToken)) 651 resp, err = httpclient.GetHTTPClient().Do(req) 652 assert.NoError(t, err) 653 assert.Equal(t, http.StatusOK, resp.StatusCode) 654 err = resp.Body.Close() 655 assert.NoError(t, err) 656 // using the user token should not work 657 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, versionPath), nil) 658 assert.NoError(t, err) 659 req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken)) 660 resp, err = httpclient.GetHTTPClient().Do(req) 661 assert.NoError(t, err) 662 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 663 err = resp.Body.Close() 664 assert.NoError(t, err) 665 666 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userPublicKeysPath), nil) 667 assert.NoError(t, err) 668 req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken)) 669 resp, err = httpclient.GetHTTPClient().Do(req) 670 assert.NoError(t, err) 671 assert.Equal(t, http.StatusOK, resp.StatusCode) 672 err = resp.Body.Close() 673 assert.NoError(t, err) 674 // using the admin token should not work 675 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userPublicKeysPath), nil) 676 assert.NoError(t, err) 677 req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", adminToken)) 678 resp, err = httpclient.GetHTTPClient().Do(req) 679 assert.NoError(t, err) 680 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 681 err = resp.Body.Close() 682 assert.NoError(t, err) 683 684 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userLogoutPath), nil) 685 assert.NoError(t, err) 686 req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", adminToken)) 687 resp, err = httpclient.GetHTTPClient().Do(req) 688 assert.NoError(t, err) 689 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 690 err = resp.Body.Close() 691 assert.NoError(t, err) 692 693 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userLogoutPath), nil) 694 assert.NoError(t, err) 695 req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken)) 696 resp, err = httpclient.GetHTTPClient().Do(req) 697 assert.NoError(t, err) 698 assert.Equal(t, http.StatusOK, resp.StatusCode) 699 err = resp.Body.Close() 700 assert.NoError(t, err) 701 702 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userPublicKeysPath), nil) 703 assert.NoError(t, err) 704 req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken)) 705 resp, err = httpclient.GetHTTPClient().Do(req) 706 assert.NoError(t, err) 707 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 708 err = resp.Body.Close() 709 assert.NoError(t, err) 710 711 _, err = httpdtest.RemoveUser(user, http.StatusOK) 712 assert.NoError(t, err) 713 err = os.RemoveAll(user.GetHomeDir()) 714 assert.NoError(t, err) 715} 716 717func TestPermMFADisabled(t *testing.T) { 718 u := getTestUser() 719 u.Filters.WebClient = []string{sdk.WebClientMFADisabled} 720 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 721 assert.NoError(t, err) 722 723 configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) 724 assert.NoError(t, err) 725 token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 726 assert.NoError(t, err) 727 userTOTPConfig := sdk.TOTPConfig{ 728 Enabled: true, 729 ConfigName: configName, 730 Secret: kms.NewPlainSecret(secret), 731 Protocols: []string{common.ProtocolSSH}, 732 } 733 asJSON, err := json.Marshal(userTOTPConfig) 734 assert.NoError(t, err) 735 req, err := http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 736 assert.NoError(t, err) 737 setBearerForReq(req, token) 738 rr := executeRequest(req) 739 checkResponseCode(t, http.StatusForbidden, rr) // MFA is disabled for this user 740 741 user.Filters.WebClient = []string{sdk.WebClientWriteDisabled} 742 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 743 assert.NoError(t, err) 744 745 token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 746 assert.NoError(t, err) 747 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 748 assert.NoError(t, err) 749 setBearerForReq(req, token) 750 rr = executeRequest(req) 751 checkResponseCode(t, http.StatusOK, rr) 752 // now we cannot disable MFA for this user 753 user.Filters.WebClient = []string{sdk.WebClientMFADisabled} 754 _, resp, err := httpdtest.UpdateUser(user, http.StatusBadRequest, "") 755 assert.NoError(t, err) 756 assert.Contains(t, string(resp), "multi-factor authentication cannot be disabled for a user with an active configuration") 757 758 saveReq := make(map[string]bool) 759 saveReq["enabled"] = false 760 asJSON, err = json.Marshal(saveReq) 761 assert.NoError(t, err) 762 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 763 assert.NoError(t, err) 764 setBearerForReq(req, token) 765 rr = executeRequest(req) 766 checkResponseCode(t, http.StatusOK, rr) 767 768 user.Filters.RecoveryCodes = []sdk.RecoveryCode{ 769 { 770 Secret: kms.NewPlainSecret(util.GenerateUniqueID()), 771 }, 772 } 773 user, resp, err = httpdtest.UpdateUser(user, http.StatusOK, "") 774 assert.NoError(t, err, string(resp)) 775 assert.Contains(t, user.Filters.WebClient, sdk.WebClientMFADisabled) 776 assert.Len(t, user.Filters.RecoveryCodes, 12) 777 778 req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil) 779 assert.NoError(t, err) 780 setBearerForReq(req, token) 781 rr = executeRequest(req) 782 checkResponseCode(t, http.StatusOK, rr) 783 var recCodes []recoveryCode 784 err = json.Unmarshal(rr.Body.Bytes(), &recCodes) 785 assert.NoError(t, err) 786 assert.Len(t, recCodes, 12) 787 788 _, err = httpdtest.RemoveUser(user, http.StatusOK) 789 assert.NoError(t, err) 790 err = os.RemoveAll(user.GetHomeDir()) 791 assert.NoError(t, err) 792} 793 794func TestLoginUserAPITOTP(t *testing.T) { 795 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 796 assert.NoError(t, err) 797 798 configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) 799 assert.NoError(t, err) 800 token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 801 assert.NoError(t, err) 802 userTOTPConfig := sdk.TOTPConfig{ 803 Enabled: true, 804 ConfigName: configName, 805 Secret: kms.NewPlainSecret(secret), 806 Protocols: []string{common.ProtocolHTTP}, 807 } 808 asJSON, err := json.Marshal(userTOTPConfig) 809 assert.NoError(t, err) 810 req, err := http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 811 assert.NoError(t, err) 812 setBearerForReq(req, token) 813 rr := executeRequest(req) 814 checkResponseCode(t, http.StatusOK, rr) 815 816 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 817 assert.NoError(t, err) 818 req.SetBasicAuth(defaultUsername, defaultPassword) 819 resp, err := httpclient.GetHTTPClient().Do(req) 820 assert.NoError(t, err) 821 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 822 err = resp.Body.Close() 823 assert.NoError(t, err) 824 825 passcode, err := generateTOTPPasscode(secret) 826 assert.NoError(t, err) 827 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 828 assert.NoError(t, err) 829 req.Header.Set("X-SFTPGO-OTP", passcode) 830 req.SetBasicAuth(defaultUsername, defaultPassword) 831 resp, err = httpclient.GetHTTPClient().Do(req) 832 assert.NoError(t, err) 833 assert.Equal(t, http.StatusOK, resp.StatusCode) 834 responseHolder := make(map[string]interface{}) 835 err = render.DecodeJSON(resp.Body, &responseHolder) 836 assert.NoError(t, err) 837 adminToken := responseHolder["access_token"].(string) 838 assert.NotEmpty(t, adminToken) 839 err = resp.Body.Close() 840 assert.NoError(t, err) 841 842 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 843 assert.NoError(t, err) 844 req.Header.Set("X-SFTPGO-OTP", passcode) 845 req.SetBasicAuth(defaultUsername, defaultPassword) 846 resp, err = httpclient.GetHTTPClient().Do(req) 847 assert.NoError(t, err) 848 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 849 err = resp.Body.Close() 850 assert.NoError(t, err) 851 852 _, err = httpdtest.RemoveUser(user, http.StatusOK) 853 assert.NoError(t, err) 854 err = os.RemoveAll(user.GetHomeDir()) 855 assert.NoError(t, err) 856} 857 858func TestLoginAdminAPITOTP(t *testing.T) { 859 admin := getTestAdmin() 860 admin.Username = altAdminUsername 861 admin.Password = altAdminPassword 862 admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) 863 assert.NoError(t, err) 864 865 configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], admin.Username) 866 assert.NoError(t, err) 867 altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword) 868 assert.NoError(t, err) 869 adminTOTPConfig := dataprovider.TOTPConfig{ 870 Enabled: true, 871 ConfigName: configName, 872 Secret: kms.NewPlainSecret(secret), 873 } 874 asJSON, err := json.Marshal(adminTOTPConfig) 875 assert.NoError(t, err) 876 req, err := http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON)) 877 assert.NoError(t, err) 878 setBearerForReq(req, altToken) 879 rr := executeRequest(req) 880 checkResponseCode(t, http.StatusOK, rr) 881 882 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil) 883 assert.NoError(t, err) 884 req.SetBasicAuth(altAdminUsername, altAdminPassword) 885 resp, err := httpclient.GetHTTPClient().Do(req) 886 assert.NoError(t, err) 887 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 888 err = resp.Body.Close() 889 assert.NoError(t, err) 890 891 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil) 892 assert.NoError(t, err) 893 req.Header.Set("X-SFTPGO-OTP", "passcode") 894 req.SetBasicAuth(altAdminUsername, altAdminPassword) 895 resp, err = httpclient.GetHTTPClient().Do(req) 896 assert.NoError(t, err) 897 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 898 err = resp.Body.Close() 899 assert.NoError(t, err) 900 901 passcode, err := generateTOTPPasscode(secret) 902 assert.NoError(t, err) 903 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil) 904 assert.NoError(t, err) 905 req.Header.Set("X-SFTPGO-OTP", passcode) 906 req.SetBasicAuth(altAdminUsername, altAdminPassword) 907 resp, err = httpclient.GetHTTPClient().Do(req) 908 assert.NoError(t, err) 909 assert.Equal(t, http.StatusOK, resp.StatusCode) 910 responseHolder := make(map[string]interface{}) 911 err = render.DecodeJSON(resp.Body, &responseHolder) 912 assert.NoError(t, err) 913 adminToken := responseHolder["access_token"].(string) 914 assert.NotEmpty(t, adminToken) 915 err = resp.Body.Close() 916 assert.NoError(t, err) 917 918 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, versionPath), nil) 919 assert.NoError(t, err) 920 setBearerForReq(req, adminToken) 921 resp, err = httpclient.GetHTTPClient().Do(req) 922 assert.NoError(t, err) 923 assert.Equal(t, http.StatusOK, resp.StatusCode) 924 err = resp.Body.Close() 925 assert.NoError(t, err) 926 927 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 928 assert.NoError(t, err) 929} 930 931func TestHTTPStreamZipError(t *testing.T) { 932 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 933 assert.NoError(t, err) 934 935 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 936 assert.NoError(t, err) 937 req.SetBasicAuth(defaultUsername, defaultPassword) 938 resp, err := httpclient.GetHTTPClient().Do(req) 939 assert.NoError(t, err) 940 assert.Equal(t, http.StatusOK, resp.StatusCode) 941 responseHolder := make(map[string]interface{}) 942 err = render.DecodeJSON(resp.Body, &responseHolder) 943 assert.NoError(t, err) 944 userToken := responseHolder["access_token"].(string) 945 assert.NotEmpty(t, userToken) 946 err = resp.Body.Close() 947 assert.NoError(t, err) 948 949 filesList := []string{"missing"} 950 asJSON, err := json.Marshal(filesList) 951 assert.NoError(t, err) 952 req, err = http.NewRequest(http.MethodPost, fmt.Sprintf("%v%v", httpBaseURL, userStreamZipPath), bytes.NewBuffer(asJSON)) 953 assert.NoError(t, err) 954 req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken)) 955 resp, err = httpclient.GetHTTPClient().Do(req) 956 if !assert.Error(t, err) { // the connection will be closed 957 err = resp.Body.Close() 958 assert.NoError(t, err) 959 } 960 _, err = httpdtest.RemoveUser(user, http.StatusOK) 961 assert.NoError(t, err) 962 err = os.RemoveAll(user.GetHomeDir()) 963 assert.NoError(t, err) 964} 965 966func TestBasicAdminHandling(t *testing.T) { 967 // we have one admin by default 968 admins, _, err := httpdtest.GetAdmins(0, 0, http.StatusOK) 969 assert.NoError(t, err) 970 assert.GreaterOrEqual(t, len(admins), 1) 971 admin := getTestAdmin() 972 // the default admin already exists 973 _, _, err = httpdtest.AddAdmin(admin, http.StatusInternalServerError) 974 assert.NoError(t, err) 975 976 admin.Username = altAdminUsername 977 admin, _, err = httpdtest.AddAdmin(admin, http.StatusCreated) 978 assert.NoError(t, err) 979 980 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 981 assert.NoError(t, err) 982 983 admin.AdditionalInfo = "test info" 984 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 985 assert.NoError(t, err) 986 assert.Equal(t, "test info", admin.AdditionalInfo) 987 988 admins, _, err = httpdtest.GetAdmins(1, 0, http.StatusOK) 989 assert.NoError(t, err) 990 assert.Len(t, admins, 1) 991 assert.NotEqual(t, admin.Username, admins[0].Username) 992 993 admins, _, err = httpdtest.GetAdmins(1, 1, http.StatusOK) 994 assert.NoError(t, err) 995 assert.Len(t, admins, 1) 996 assert.Equal(t, admin.Username, admins[0].Username) 997 998 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 999 assert.NoError(t, err) 1000 1001 _, err = httpdtest.RemoveAdmin(admin, http.StatusNotFound) 1002 assert.NoError(t, err) 1003 1004 admin, _, err = httpdtest.GetAdminByUsername(admin.Username+"123", http.StatusNotFound) 1005 assert.NoError(t, err) 1006 1007 admin.Username = defaultTokenAuthUser 1008 _, err = httpdtest.RemoveAdmin(admin, http.StatusBadRequest) 1009 assert.NoError(t, err) 1010} 1011 1012func TestChangeAdminPassword(t *testing.T) { 1013 _, err := httpdtest.ChangeAdminPassword("wrong", defaultTokenAuthPass, http.StatusBadRequest) 1014 assert.NoError(t, err) 1015 _, err = httpdtest.ChangeAdminPassword(defaultTokenAuthPass, defaultTokenAuthPass, http.StatusBadRequest) 1016 assert.NoError(t, err) 1017 _, err = httpdtest.ChangeAdminPassword(defaultTokenAuthPass, defaultTokenAuthPass+"1", http.StatusOK) 1018 assert.NoError(t, err) 1019 _, err = httpdtest.ChangeAdminPassword(defaultTokenAuthPass+"1", defaultTokenAuthPass, http.StatusUnauthorized) 1020 assert.NoError(t, err) 1021 admin, err := dataprovider.AdminExists(defaultTokenAuthUser) 1022 assert.NoError(t, err) 1023 admin.Password = defaultTokenAuthPass 1024 err = dataprovider.UpdateAdmin(&admin, "", "") 1025 assert.NoError(t, err) 1026} 1027 1028func TestPasswordValidations(t *testing.T) { 1029 if config.GetProviderConf().Driver == dataprovider.MemoryDataProviderName { 1030 t.Skip("this test is not supported with the memory provider") 1031 } 1032 err := dataprovider.Close() 1033 assert.NoError(t, err) 1034 err = config.LoadConfig(configDir, "") 1035 providerConf := config.GetProviderConf() 1036 assert.NoError(t, err) 1037 providerConf.PasswordValidation.Admins.MinEntropy = 50 1038 providerConf.PasswordValidation.Users.MinEntropy = 70 1039 err = dataprovider.Initialize(providerConf, configDir, true) 1040 assert.NoError(t, err) 1041 1042 a := getTestAdmin() 1043 a.Username = altAdminUsername 1044 a.Password = altAdminPassword 1045 1046 _, resp, err := httpdtest.AddAdmin(a, http.StatusBadRequest) 1047 assert.NoError(t, err, string(resp)) 1048 assert.Contains(t, string(resp), "insecure password") 1049 1050 _, resp, err = httpdtest.AddUser(getTestUser(), http.StatusBadRequest) 1051 assert.NoError(t, err, string(resp)) 1052 assert.Contains(t, string(resp), "insecure password") 1053 1054 err = dataprovider.Close() 1055 assert.NoError(t, err) 1056 err = config.LoadConfig(configDir, "") 1057 assert.NoError(t, err) 1058 providerConf = config.GetProviderConf() 1059 providerConf.CredentialsPath = credentialsPath 1060 err = os.RemoveAll(credentialsPath) 1061 assert.NoError(t, err) 1062 err = dataprovider.Initialize(providerConf, configDir, true) 1063 assert.NoError(t, err) 1064} 1065 1066func TestAdminPasswordHashing(t *testing.T) { 1067 if config.GetProviderConf().Driver == dataprovider.MemoryDataProviderName { 1068 t.Skip("this test is not supported with the memory provider") 1069 } 1070 err := dataprovider.Close() 1071 assert.NoError(t, err) 1072 err = config.LoadConfig(configDir, "") 1073 providerConf := config.GetProviderConf() 1074 assert.NoError(t, err) 1075 providerConf.PasswordHashing.Algo = dataprovider.HashingAlgoArgon2ID 1076 err = dataprovider.Initialize(providerConf, configDir, true) 1077 assert.NoError(t, err) 1078 1079 currentAdmin, err := dataprovider.AdminExists(defaultTokenAuthUser) 1080 assert.NoError(t, err) 1081 assert.True(t, strings.HasPrefix(currentAdmin.Password, "$2a$")) 1082 1083 a := getTestAdmin() 1084 a.Username = altAdminUsername 1085 a.Password = altAdminPassword 1086 1087 admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated) 1088 assert.NoError(t, err) 1089 1090 newAdmin, err := dataprovider.AdminExists(altAdminUsername) 1091 assert.NoError(t, err) 1092 assert.True(t, strings.HasPrefix(newAdmin.Password, "$argon2id$")) 1093 1094 token, _, err := httpdtest.GetToken(altAdminUsername, altAdminPassword) 1095 assert.NoError(t, err) 1096 httpdtest.SetJWTToken(token) 1097 _, _, err = httpdtest.GetStatus(http.StatusOK) 1098 assert.NoError(t, err) 1099 1100 httpdtest.SetJWTToken("") 1101 _, _, err = httpdtest.GetStatus(http.StatusOK) 1102 assert.NoError(t, err) 1103 1104 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 1105 assert.NoError(t, err) 1106 1107 err = dataprovider.Close() 1108 assert.NoError(t, err) 1109 err = config.LoadConfig(configDir, "") 1110 assert.NoError(t, err) 1111 providerConf = config.GetProviderConf() 1112 providerConf.CredentialsPath = credentialsPath 1113 err = os.RemoveAll(credentialsPath) 1114 assert.NoError(t, err) 1115 err = dataprovider.Initialize(providerConf, configDir, true) 1116 assert.NoError(t, err) 1117} 1118 1119func TestAdminInvalidCredentials(t *testing.T) { 1120 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil) 1121 assert.NoError(t, err) 1122 req.SetBasicAuth(defaultTokenAuthUser, defaultTokenAuthPass) 1123 resp, err := httpclient.GetHTTPClient().Do(req) 1124 assert.NoError(t, err) 1125 assert.Equal(t, http.StatusOK, resp.StatusCode) 1126 err = resp.Body.Close() 1127 assert.NoError(t, err) 1128 // wrong password 1129 req.SetBasicAuth(defaultTokenAuthUser, "wrong pwd") 1130 resp, err = httpclient.GetHTTPClient().Do(req) 1131 assert.NoError(t, err) 1132 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 1133 responseHolder := make(map[string]interface{}) 1134 err = render.DecodeJSON(resp.Body, &responseHolder) 1135 assert.NoError(t, err) 1136 err = resp.Body.Close() 1137 assert.NoError(t, err) 1138 assert.Equal(t, dataprovider.ErrInvalidCredentials.Error(), responseHolder["error"].(string)) 1139 // wrong username 1140 req.SetBasicAuth("wrong username", defaultTokenAuthPass) 1141 resp, err = httpclient.GetHTTPClient().Do(req) 1142 assert.NoError(t, err) 1143 assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) 1144 responseHolder = make(map[string]interface{}) 1145 err = render.DecodeJSON(resp.Body, &responseHolder) 1146 assert.NoError(t, err) 1147 err = resp.Body.Close() 1148 assert.NoError(t, err) 1149 assert.Equal(t, dataprovider.ErrInvalidCredentials.Error(), responseHolder["error"].(string)) 1150} 1151 1152func TestAdminLastLogin(t *testing.T) { 1153 a := getTestAdmin() 1154 a.Username = altAdminUsername 1155 a.Password = altAdminPassword 1156 1157 admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated) 1158 assert.NoError(t, err) 1159 assert.Equal(t, int64(0), admin.LastLogin) 1160 1161 _, _, err = httpdtest.GetToken(altAdminUsername, altAdminPassword) 1162 assert.NoError(t, err) 1163 1164 admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK) 1165 assert.NoError(t, err) 1166 assert.Greater(t, admin.LastLogin, int64(0)) 1167 1168 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 1169 assert.NoError(t, err) 1170} 1171 1172func TestAdminAllowList(t *testing.T) { 1173 a := getTestAdmin() 1174 a.Username = altAdminUsername 1175 a.Password = altAdminPassword 1176 1177 admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated) 1178 assert.NoError(t, err) 1179 1180 token, _, err := httpdtest.GetToken(altAdminUsername, altAdminPassword) 1181 assert.NoError(t, err) 1182 httpdtest.SetJWTToken(token) 1183 _, _, err = httpdtest.GetStatus(http.StatusOK) 1184 assert.NoError(t, err) 1185 1186 httpdtest.SetJWTToken("") 1187 1188 admin.Password = altAdminPassword 1189 admin.Filters.AllowList = []string{"10.6.6.0/32"} 1190 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 1191 assert.NoError(t, err) 1192 1193 _, _, err = httpdtest.GetToken(altAdminUsername, altAdminPassword) 1194 assert.EqualError(t, err, "wrong status code: got 401 want 200") 1195 1196 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 1197 assert.NoError(t, err) 1198} 1199 1200func TestUserStatus(t *testing.T) { 1201 u := getTestUser() 1202 u.Status = 3 1203 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1204 assert.NoError(t, err) 1205 u.Status = 0 1206 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 1207 assert.NoError(t, err) 1208 user.Status = 2 1209 _, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "") 1210 assert.NoError(t, err) 1211 user.Status = 1 1212 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 1213 assert.NoError(t, err) 1214 _, err = httpdtest.RemoveUser(user, http.StatusOK) 1215 assert.NoError(t, err) 1216} 1217 1218func TestUidGidLimits(t *testing.T) { 1219 u := getTestUser() 1220 u.UID = math.MaxInt32 1221 u.GID = math.MaxInt32 1222 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 1223 assert.NoError(t, err) 1224 assert.Equal(t, math.MaxInt32, user.GetUID()) 1225 assert.Equal(t, math.MaxInt32, user.GetGID()) 1226 1227 _, err = httpdtest.RemoveUser(user, http.StatusOK) 1228 assert.NoError(t, err) 1229} 1230 1231func TestAddUserNoCredentials(t *testing.T) { 1232 u := getTestUser() 1233 u.Password = "" 1234 u.PublicKeys = []string{} 1235 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1236 assert.NoError(t, err) 1237} 1238 1239func TestAddUserNoUsername(t *testing.T) { 1240 u := getTestUser() 1241 u.Username = "" 1242 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1243 assert.NoError(t, err) 1244} 1245 1246func TestAddUserNoHomeDir(t *testing.T) { 1247 u := getTestUser() 1248 u.HomeDir = "" 1249 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1250 assert.NoError(t, err) 1251} 1252 1253func TestAddUserInvalidHomeDir(t *testing.T) { 1254 u := getTestUser() 1255 u.HomeDir = "relative_path" //nolint:goconst 1256 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1257 assert.NoError(t, err) 1258} 1259 1260func TestAddUserNoPerms(t *testing.T) { 1261 u := getTestUser() 1262 u.Permissions = make(map[string][]string) 1263 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1264 assert.NoError(t, err) 1265 u.Permissions["/"] = []string{} 1266 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1267 assert.NoError(t, err) 1268} 1269 1270func TestAddUserInvalidEmail(t *testing.T) { 1271 u := getTestUser() 1272 u.Email = "invalid_email" 1273 _, body, err := httpdtest.AddUser(u, http.StatusBadRequest) 1274 assert.NoError(t, err) 1275 assert.Contains(t, string(body), "Validation error: email") 1276} 1277 1278func TestAddUserInvalidPerms(t *testing.T) { 1279 u := getTestUser() 1280 u.Permissions["/"] = []string{"invalidPerm"} 1281 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1282 assert.NoError(t, err) 1283 // permissions for root dir are mandatory 1284 u.Permissions["/"] = []string{} 1285 u.Permissions["/somedir"] = []string{dataprovider.PermAny} 1286 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1287 assert.NoError(t, err) 1288 u.Permissions["/"] = []string{dataprovider.PermAny} 1289 u.Permissions["/subdir/.."] = []string{dataprovider.PermAny} 1290 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1291 assert.NoError(t, err) 1292} 1293 1294func TestAddUserInvalidFilters(t *testing.T) { 1295 u := getTestUser() 1296 u.Filters.AllowedIP = []string{"192.168.1.0/24", "192.168.2.0"} 1297 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1298 assert.NoError(t, err) 1299 u.Filters.AllowedIP = []string{} 1300 u.Filters.DeniedIP = []string{"192.168.3.0/16", "invalid"} 1301 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1302 assert.NoError(t, err) 1303 u.Filters.DeniedIP = []string{} 1304 u.Filters.DeniedLoginMethods = []string{"invalid"} 1305 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1306 assert.NoError(t, err) 1307 u.Filters.DeniedLoginMethods = dataprovider.ValidLoginMethods 1308 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1309 assert.NoError(t, err) 1310 u.Filters.DeniedLoginMethods = []string{} 1311 u.Filters.FilePatterns = []sdk.PatternsFilter{ 1312 { 1313 Path: "relative", 1314 AllowedPatterns: []string{}, 1315 DeniedPatterns: []string{}, 1316 }, 1317 } 1318 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1319 assert.NoError(t, err) 1320 u.Filters.FilePatterns = []sdk.PatternsFilter{ 1321 { 1322 Path: "/", 1323 AllowedPatterns: []string{}, 1324 DeniedPatterns: []string{}, 1325 }, 1326 } 1327 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1328 assert.NoError(t, err) 1329 u.Filters.FilePatterns = []sdk.PatternsFilter{ 1330 { 1331 Path: "/subdir", 1332 AllowedPatterns: []string{"*.zip"}, 1333 DeniedPatterns: []string{}, 1334 }, 1335 { 1336 Path: "/subdir", 1337 AllowedPatterns: []string{"*.rar"}, 1338 DeniedPatterns: []string{"*.jpg"}, 1339 }, 1340 } 1341 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1342 assert.NoError(t, err) 1343 u.Filters.FilePatterns = []sdk.PatternsFilter{ 1344 { 1345 Path: "relative", 1346 AllowedPatterns: []string{}, 1347 DeniedPatterns: []string{}, 1348 }, 1349 } 1350 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1351 assert.NoError(t, err) 1352 u.Filters.FilePatterns = []sdk.PatternsFilter{ 1353 { 1354 Path: "/", 1355 AllowedPatterns: []string{}, 1356 DeniedPatterns: []string{}, 1357 }, 1358 } 1359 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1360 assert.NoError(t, err) 1361 u.Filters.FilePatterns = []sdk.PatternsFilter{ 1362 { 1363 Path: "/subdir", 1364 AllowedPatterns: []string{"*.zip"}, 1365 }, 1366 { 1367 Path: "/subdir", 1368 AllowedPatterns: []string{"*.rar"}, 1369 DeniedPatterns: []string{"*.jpg"}, 1370 }, 1371 } 1372 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1373 assert.NoError(t, err) 1374 u.Filters.FilePatterns = []sdk.PatternsFilter{ 1375 { 1376 Path: "/subdir", 1377 AllowedPatterns: []string{"a\\"}, 1378 }, 1379 } 1380 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1381 assert.NoError(t, err) 1382 u.Filters.DeniedProtocols = []string{"invalid"} 1383 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1384 assert.NoError(t, err) 1385 u.Filters.DeniedProtocols = dataprovider.ValidProtocols 1386 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1387 assert.NoError(t, err) 1388 u.Filters.DeniedProtocols = nil 1389 u.Filters.TLSUsername = "not a supported attribute" 1390 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1391 assert.NoError(t, err) 1392 u.Filters.TLSUsername = "" 1393 u.Filters.WebClient = []string{"not a valid web client options"} 1394 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1395 assert.NoError(t, err) 1396} 1397 1398func TestAddUserInvalidFsConfig(t *testing.T) { 1399 u := getTestUser() 1400 u.FsConfig.Provider = sdk.S3FilesystemProvider 1401 u.FsConfig.S3Config.Bucket = "" 1402 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1403 assert.NoError(t, err) 1404 err = os.RemoveAll(credentialsPath) 1405 assert.NoError(t, err) 1406 err = os.MkdirAll(credentialsPath, 0700) 1407 assert.NoError(t, err) 1408 u.FsConfig.S3Config.Bucket = "testbucket" 1409 u.FsConfig.S3Config.Region = "eu-west-1" //nolint:goconst 1410 u.FsConfig.S3Config.AccessKey = "access-key" //nolint:goconst 1411 u.FsConfig.S3Config.AccessSecret = kms.NewSecret(kms.SecretStatusRedacted, "access-secret", "", "") 1412 u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b" 1413 u.FsConfig.S3Config.StorageClass = "Standard" //nolint:goconst 1414 u.FsConfig.S3Config.KeyPrefix = "/adir/subdir/" 1415 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1416 assert.NoError(t, err) 1417 u.FsConfig.S3Config.AccessSecret.SetStatus(kms.SecretStatusPlain) 1418 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1419 assert.NoError(t, err) 1420 u.FsConfig.S3Config.KeyPrefix = "" 1421 u.FsConfig.S3Config.UploadPartSize = 3 1422 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1423 assert.NoError(t, err) 1424 u.FsConfig.S3Config.UploadPartSize = 5001 1425 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1426 assert.NoError(t, err) 1427 u.FsConfig.S3Config.UploadPartSize = 0 1428 u.FsConfig.S3Config.UploadConcurrency = -1 1429 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1430 assert.NoError(t, err) 1431 u.FsConfig.S3Config.UploadConcurrency = 0 1432 u.FsConfig.S3Config.DownloadPartSize = -1 1433 _, resp, err := httpdtest.AddUser(u, http.StatusBadRequest) 1434 if assert.NoError(t, err) { 1435 assert.Contains(t, string(resp), "download_part_size cannot be") 1436 } 1437 u.FsConfig.S3Config.DownloadPartSize = 5001 1438 _, resp, err = httpdtest.AddUser(u, http.StatusBadRequest) 1439 if assert.NoError(t, err) { 1440 assert.Contains(t, string(resp), "download_part_size cannot be") 1441 } 1442 u.FsConfig.S3Config.DownloadPartSize = 0 1443 u.FsConfig.S3Config.DownloadConcurrency = 100 1444 _, resp, err = httpdtest.AddUser(u, http.StatusBadRequest) 1445 if assert.NoError(t, err) { 1446 assert.Contains(t, string(resp), "invalid download concurrency") 1447 } 1448 u.FsConfig.S3Config.DownloadConcurrency = -1 1449 _, resp, err = httpdtest.AddUser(u, http.StatusBadRequest) 1450 if assert.NoError(t, err) { 1451 assert.Contains(t, string(resp), "invalid download concurrency") 1452 } 1453 u = getTestUser() 1454 u.FsConfig.Provider = sdk.GCSFilesystemProvider 1455 u.FsConfig.GCSConfig.Bucket = "" 1456 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1457 assert.NoError(t, err) 1458 u.FsConfig.GCSConfig.Bucket = "abucket" 1459 u.FsConfig.GCSConfig.StorageClass = "Standard" 1460 u.FsConfig.GCSConfig.KeyPrefix = "/somedir/subdir/" 1461 u.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusRedacted, "test", "", "") //nolint:goconst 1462 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1463 assert.NoError(t, err) 1464 u.FsConfig.GCSConfig.Credentials.SetStatus(kms.SecretStatusPlain) 1465 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1466 assert.NoError(t, err) 1467 u.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/" //nolint:goconst 1468 u.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret() 1469 u.FsConfig.GCSConfig.AutomaticCredentials = 0 1470 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1471 assert.NoError(t, err) 1472 u.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusSecretBox, "invalid", "", "") 1473 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1474 assert.NoError(t, err) 1475 1476 u = getTestUser() 1477 u.FsConfig.Provider = sdk.AzureBlobFilesystemProvider 1478 u.FsConfig.AzBlobConfig.SASURL = kms.NewPlainSecret("http://foo\x7f.com/") 1479 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1480 assert.NoError(t, err) 1481 u.FsConfig.AzBlobConfig.SASURL = kms.NewSecret(kms.SecretStatusRedacted, "key", "", "") 1482 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1483 assert.NoError(t, err) 1484 u.FsConfig.AzBlobConfig.SASURL = kms.NewEmptySecret() 1485 u.FsConfig.AzBlobConfig.AccountName = "name" 1486 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1487 assert.NoError(t, err) 1488 u.FsConfig.AzBlobConfig.Container = "container" 1489 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1490 assert.NoError(t, err) 1491 u.FsConfig.AzBlobConfig.AccountKey = kms.NewSecret(kms.SecretStatusRedacted, "key", "", "") 1492 u.FsConfig.AzBlobConfig.KeyPrefix = "/amedir/subdir/" 1493 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1494 assert.NoError(t, err) 1495 u.FsConfig.AzBlobConfig.AccountKey.SetStatus(kms.SecretStatusPlain) 1496 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1497 assert.NoError(t, err) 1498 u.FsConfig.AzBlobConfig.KeyPrefix = "amedir/subdir/" 1499 u.FsConfig.AzBlobConfig.UploadPartSize = -1 1500 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1501 assert.NoError(t, err) 1502 u.FsConfig.AzBlobConfig.UploadPartSize = 101 1503 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1504 assert.NoError(t, err) 1505 1506 u = getTestUser() 1507 u.FsConfig.Provider = sdk.CryptedFilesystemProvider 1508 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1509 assert.NoError(t, err) 1510 u.FsConfig.CryptConfig.Passphrase = kms.NewSecret(kms.SecretStatusRedacted, "akey", "", "") 1511 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1512 assert.NoError(t, err) 1513 u = getTestUser() 1514 u.FsConfig.Provider = sdk.SFTPFilesystemProvider 1515 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1516 assert.NoError(t, err) 1517 u.FsConfig.SFTPConfig.Password = kms.NewSecret(kms.SecretStatusRedacted, "randompkey", "", "") 1518 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1519 assert.NoError(t, err) 1520 u.FsConfig.SFTPConfig.Password = kms.NewEmptySecret() 1521 u.FsConfig.SFTPConfig.PrivateKey = kms.NewSecret(kms.SecretStatusRedacted, "keyforpkey", "", "") 1522 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1523 assert.NoError(t, err) 1524 u.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret("pk") 1525 u.FsConfig.SFTPConfig.Endpoint = "127.1.1.1:22" 1526 u.FsConfig.SFTPConfig.Username = defaultUsername 1527 u.FsConfig.SFTPConfig.BufferSize = -1 1528 _, resp, err = httpdtest.AddUser(u, http.StatusBadRequest) 1529 if assert.NoError(t, err) { 1530 assert.Contains(t, string(resp), "invalid buffer_size") 1531 } 1532 u.FsConfig.SFTPConfig.BufferSize = 1000 1533 _, resp, err = httpdtest.AddUser(u, http.StatusBadRequest) 1534 if assert.NoError(t, err) { 1535 assert.Contains(t, string(resp), "invalid buffer_size") 1536 } 1537} 1538 1539func TestUserRedactedPassword(t *testing.T) { 1540 u := getTestUser() 1541 u.FsConfig.Provider = sdk.S3FilesystemProvider 1542 u.FsConfig.S3Config.Bucket = "b" 1543 u.FsConfig.S3Config.Region = "eu-west-1" 1544 u.FsConfig.S3Config.AccessKey = "access-key" 1545 u.FsConfig.S3Config.AccessSecret = kms.NewSecret(kms.SecretStatusRedacted, "access-secret", "", "") 1546 u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?k=m" 1547 u.FsConfig.S3Config.StorageClass = "Standard" 1548 u.FsConfig.S3Config.ACL = "bucket-owner-full-control" 1549 _, resp, err := httpdtest.AddUser(u, http.StatusBadRequest) 1550 assert.NoError(t, err, string(resp)) 1551 assert.Contains(t, string(resp), "cannot save a user with a redacted secret") 1552 err = dataprovider.AddUser(&u, "", "") 1553 if assert.Error(t, err) { 1554 assert.Contains(t, err.Error(), "cannot save a user with a redacted secret") 1555 } 1556 u.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("secret") 1557 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 1558 assert.NoError(t, err) 1559 1560 folderName := "folderName" 1561 vfolder := vfs.VirtualFolder{ 1562 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1563 Name: folderName, 1564 MappedPath: filepath.Join(os.TempDir(), "crypted"), 1565 FsConfig: vfs.Filesystem{ 1566 Provider: sdk.CryptedFilesystemProvider, 1567 CryptConfig: vfs.CryptFsConfig{ 1568 CryptFsConfig: sdk.CryptFsConfig{ 1569 Passphrase: kms.NewSecret(kms.SecretStatusRedacted, "crypted-secret", "", ""), 1570 }, 1571 }, 1572 }, 1573 }, 1574 VirtualPath: "/avpath", 1575 } 1576 1577 user.Password = defaultPassword 1578 user.VirtualFolders = append(user.VirtualFolders, vfolder) 1579 err = dataprovider.UpdateUser(&user, "", "") 1580 if assert.Error(t, err) { 1581 assert.Contains(t, err.Error(), "cannot save a user with a redacted secret") 1582 } 1583 1584 _, err = httpdtest.RemoveUser(user, http.StatusOK) 1585 assert.NoError(t, err) 1586} 1587 1588func TestUserType(t *testing.T) { 1589 u := getTestUser() 1590 u.Filters.UserType = string(sdk.UserTypeLDAP) 1591 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 1592 assert.NoError(t, err) 1593 assert.Equal(t, string(sdk.UserTypeLDAP), user.Filters.UserType) 1594 user.Filters.UserType = string(sdk.UserTypeOS) 1595 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 1596 assert.NoError(t, err) 1597 assert.Equal(t, string(sdk.UserTypeOS), user.Filters.UserType) 1598 1599 _, err = httpdtest.RemoveUser(user, http.StatusOK) 1600 assert.NoError(t, err) 1601} 1602 1603func TestRetentionAPI(t *testing.T) { 1604 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 1605 assert.NoError(t, err) 1606 1607 checks, _, err := httpdtest.GetRetentionChecks(http.StatusOK) 1608 assert.NoError(t, err) 1609 assert.Len(t, checks, 0) 1610 1611 localFilePath := filepath.Join(user.HomeDir, "testdir", "testfile") 1612 err = os.MkdirAll(filepath.Dir(localFilePath), os.ModePerm) 1613 assert.NoError(t, err) 1614 err = os.WriteFile(localFilePath, []byte("test data"), os.ModePerm) 1615 assert.NoError(t, err) 1616 1617 folderRetention := []common.FolderRetention{ 1618 { 1619 Path: "/", 1620 Retention: 0, 1621 DeleteEmptyDirs: true, 1622 }, 1623 } 1624 1625 _, err = httpdtest.StartRetentionCheck(altAdminUsername, folderRetention, http.StatusNotFound) 1626 assert.NoError(t, err) 1627 1628 resp, err := httpdtest.StartRetentionCheck(user.Username, folderRetention, http.StatusBadRequest) 1629 assert.NoError(t, err) 1630 assert.Contains(t, string(resp), "Invalid retention check") 1631 1632 folderRetention[0].Retention = 24 1633 _, err = httpdtest.StartRetentionCheck(user.Username, folderRetention, http.StatusAccepted) 1634 assert.NoError(t, err) 1635 1636 assert.Eventually(t, func() bool { 1637 return len(common.RetentionChecks.Get()) == 0 1638 }, 1000*time.Millisecond, 50*time.Millisecond) 1639 1640 assert.FileExists(t, localFilePath) 1641 1642 err = os.Chtimes(localFilePath, time.Now().Add(-48*time.Hour), time.Now().Add(-48*time.Hour)) 1643 assert.NoError(t, err) 1644 1645 _, err = httpdtest.StartRetentionCheck(user.Username, folderRetention, http.StatusAccepted) 1646 assert.NoError(t, err) 1647 1648 assert.Eventually(t, func() bool { 1649 return len(common.RetentionChecks.Get()) == 0 1650 }, 1000*time.Millisecond, 50*time.Millisecond) 1651 1652 assert.NoFileExists(t, localFilePath) 1653 assert.NoDirExists(t, filepath.Dir(localFilePath)) 1654 1655 check := common.RetentionCheck{ 1656 Folders: folderRetention, 1657 } 1658 c := common.RetentionChecks.Add(check, &user) 1659 assert.NotNil(t, c) 1660 1661 _, err = httpdtest.StartRetentionCheck(user.Username, folderRetention, http.StatusConflict) 1662 assert.NoError(t, err) 1663 1664 c.Start() 1665 assert.Len(t, common.RetentionChecks.Get(), 0) 1666 1667 admin := getTestAdmin() 1668 admin.Username = altAdminUsername 1669 admin.Password = altAdminPassword 1670 admin, _, err = httpdtest.AddAdmin(admin, http.StatusCreated) 1671 assert.NoError(t, err) 1672 1673 token, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword) 1674 assert.NoError(t, err) 1675 req, _ := http.NewRequest(http.MethodPost, retentionBasePath+"/"+user.Username+"/check", 1676 bytes.NewBuffer([]byte("invalid json"))) 1677 setBearerForReq(req, token) 1678 rr := executeRequest(req) 1679 checkResponseCode(t, http.StatusBadRequest, rr) 1680 1681 asJSON, err := json.Marshal(folderRetention) 1682 assert.NoError(t, err) 1683 req, _ = http.NewRequest(http.MethodPost, retentionBasePath+"/"+user.Username+"/check?notifications=Email,", 1684 bytes.NewBuffer(asJSON)) 1685 setBearerForReq(req, token) 1686 rr = executeRequest(req) 1687 checkResponseCode(t, http.StatusBadRequest, rr) 1688 assert.Contains(t, rr.Body.String(), "to notify results via email") 1689 1690 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 1691 assert.NoError(t, err) 1692 req, _ = http.NewRequest(http.MethodPost, retentionBasePath+"/"+user.Username+"/check?notifications=Email", 1693 bytes.NewBuffer(asJSON)) 1694 setBearerForReq(req, token) 1695 rr = executeRequest(req) 1696 checkResponseCode(t, http.StatusNotFound, rr) 1697 1698 _, err = httpdtest.RemoveUser(user, http.StatusOK) 1699 assert.NoError(t, err) 1700 err = os.RemoveAll(user.GetHomeDir()) 1701 assert.NoError(t, err) 1702} 1703 1704func TestAddUserInvalidVirtualFolders(t *testing.T) { 1705 u := getTestUser() 1706 folderName := "fname" 1707 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1708 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1709 MappedPath: filepath.Join(os.TempDir(), "mapped_dir"), 1710 Name: folderName, 1711 }, 1712 VirtualPath: "vdir", // invalid 1713 }) 1714 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1715 assert.NoError(t, err) 1716 u.VirtualFolders = nil 1717 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1718 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1719 MappedPath: filepath.Join(os.TempDir(), "mapped_dir"), 1720 Name: folderName, 1721 }, 1722 VirtualPath: "/", // invalid 1723 }) 1724 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1725 assert.NoError(t, err) 1726 u.VirtualFolders = nil 1727 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1728 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1729 MappedPath: filepath.Join(u.GetHomeDir(), "mapped_dir"), // invalid, inside home dir 1730 Name: folderName, 1731 }, 1732 VirtualPath: "/vdir", 1733 }) 1734 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1735 assert.NoError(t, err) 1736 u.VirtualFolders = nil 1737 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1738 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1739 MappedPath: u.GetHomeDir(), // invalid 1740 Name: folderName, 1741 }, 1742 VirtualPath: "/vdir", 1743 }) 1744 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1745 assert.NoError(t, err) 1746 u.VirtualFolders = nil 1747 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1748 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1749 MappedPath: filepath.Join(u.GetHomeDir(), ".."), // invalid, contains home dir 1750 Name: "tmp", 1751 }, 1752 VirtualPath: "/vdir", 1753 }) 1754 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1755 assert.NoError(t, err) 1756 u.VirtualFolders = nil 1757 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1758 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1759 MappedPath: filepath.Join(os.TempDir(), "mapped_dir"), 1760 Name: folderName, 1761 }, 1762 VirtualPath: "/vdir", 1763 }) 1764 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1765 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1766 MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"), 1767 Name: folderName + "1", 1768 }, 1769 VirtualPath: "/vdir", // invalid, already defined 1770 }) 1771 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1772 assert.NoError(t, err) 1773 u.VirtualFolders = nil 1774 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1775 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1776 MappedPath: filepath.Join(os.TempDir(), "mapped_dir"), 1777 Name: folderName, 1778 }, 1779 VirtualPath: "/vdir1", 1780 }) 1781 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1782 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1783 MappedPath: filepath.Join(os.TempDir(), "mapped_dir"), // invalid, already defined 1784 Name: folderName, 1785 }, 1786 VirtualPath: "/vdir2", 1787 }) 1788 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1789 assert.NoError(t, err) 1790 u.VirtualFolders = nil 1791 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1792 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1793 MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"), 1794 Name: folderName + "1", 1795 }, 1796 VirtualPath: "/vdir1/", 1797 QuotaSize: -1, 1798 QuotaFiles: 1, // invvalid, we cannot have -1 and > 0 1799 }) 1800 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1801 assert.NoError(t, err) 1802 u.VirtualFolders = nil 1803 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1804 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1805 MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"), 1806 Name: folderName + "1", 1807 }, 1808 VirtualPath: "/vdir1/", 1809 QuotaSize: 1, 1810 QuotaFiles: -1, 1811 }) 1812 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1813 assert.NoError(t, err) 1814 u.VirtualFolders = nil 1815 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1816 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1817 MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"), 1818 Name: folderName + "1", 1819 }, 1820 VirtualPath: "/vdir1/", 1821 QuotaSize: -2, // invalid 1822 QuotaFiles: 0, 1823 }) 1824 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1825 assert.NoError(t, err) 1826 u.VirtualFolders = nil 1827 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1828 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1829 MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"), 1830 Name: folderName + "1", 1831 }, 1832 VirtualPath: "/vdir1/", 1833 QuotaSize: 0, 1834 QuotaFiles: -2, // invalid 1835 }) 1836 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1837 assert.NoError(t, err) 1838 u.VirtualFolders = nil 1839 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 1840 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1841 MappedPath: filepath.Join(os.TempDir(), "mapped_dir"), 1842 }, 1843 VirtualPath: "/vdir1", 1844 }) 1845 // folder name is mandatory 1846 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) 1847 assert.NoError(t, err) 1848} 1849 1850func TestUserPublicKey(t *testing.T) { 1851 u := getTestUser() 1852 u.Password = "" 1853 invalidPubKey := "invalid" 1854 u.PublicKeys = []string{invalidPubKey} 1855 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 1856 assert.NoError(t, err) 1857 u.PublicKeys = []string{testPubKey} 1858 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 1859 assert.NoError(t, err) 1860 1861 dbUser, err := dataprovider.UserExists(u.Username) 1862 assert.NoError(t, err) 1863 assert.Empty(t, dbUser.Password) 1864 assert.False(t, dbUser.IsPasswordHashed()) 1865 1866 user.PublicKeys = []string{testPubKey, invalidPubKey} 1867 _, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "") 1868 assert.NoError(t, err) 1869 user.PublicKeys = []string{testPubKey, testPubKey, testPubKey} 1870 user.Password = defaultPassword 1871 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 1872 assert.NoError(t, err) 1873 1874 dbUser, err = dataprovider.UserExists(u.Username) 1875 assert.NoError(t, err) 1876 assert.NotEmpty(t, dbUser.Password) 1877 assert.True(t, dbUser.IsPasswordHashed()) 1878 1879 _, err = httpdtest.RemoveUser(user, http.StatusOK) 1880 assert.NoError(t, err) 1881} 1882 1883func TestUpdateUserEmptyPassword(t *testing.T) { 1884 u := getTestUser() 1885 u.PublicKeys = []string{testPubKey} 1886 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 1887 assert.NoError(t, err) 1888 1889 // the password is not empty 1890 dbUser, err := dataprovider.UserExists(u.Username) 1891 assert.NoError(t, err) 1892 assert.NotEmpty(t, dbUser.Password) 1893 assert.True(t, dbUser.IsPasswordHashed()) 1894 // now update the user and set an empty password 1895 customUser := make(map[string]interface{}) 1896 customUser["password"] = "" 1897 asJSON, err := json.Marshal(customUser) 1898 assert.NoError(t, err) 1899 userNoPwd, _, err := httpdtest.UpdateUserWithJSON(user, http.StatusOK, "", asJSON) 1900 assert.NoError(t, err) 1901 assert.Equal(t, user.Password, userNoPwd.Password) // the password is hidden 1902 // check the password within the data provider 1903 dbUser, err = dataprovider.UserExists(u.Username) 1904 assert.NoError(t, err) 1905 assert.Empty(t, dbUser.Password) 1906 assert.False(t, dbUser.IsPasswordHashed()) 1907 1908 _, err = httpdtest.RemoveUser(user, http.StatusOK) 1909 assert.NoError(t, err) 1910} 1911 1912func TestUpdateUser(t *testing.T) { 1913 u := getTestUser() 1914 u.UsedQuotaFiles = 1 1915 u.UsedQuotaSize = 2 1916 u.Filters.TLSUsername = sdk.TLSUsernameCN 1917 u.Filters.Hooks.CheckPasswordDisabled = true 1918 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 1919 assert.NoError(t, err) 1920 assert.Equal(t, 0, user.UsedQuotaFiles) 1921 assert.Equal(t, int64(0), user.UsedQuotaSize) 1922 user.HomeDir = filepath.Join(homeBasePath, "testmod") 1923 user.UID = 33 1924 user.GID = 101 1925 user.MaxSessions = 10 1926 user.QuotaSize = 4096 1927 user.QuotaFiles = 2 1928 user.Permissions["/"] = []string{dataprovider.PermCreateDirs, dataprovider.PermDelete, dataprovider.PermDownload} 1929 user.Permissions["/subdir"] = []string{dataprovider.PermListItems, dataprovider.PermUpload} 1930 user.Filters.AllowedIP = []string{"192.168.1.0/24", "192.168.2.0/24"} 1931 user.Filters.DeniedIP = []string{"192.168.3.0/24", "192.168.4.0/24"} 1932 user.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword} 1933 user.Filters.DeniedProtocols = []string{common.ProtocolWebDAV} 1934 user.Filters.TLSUsername = sdk.TLSUsernameNone 1935 user.Filters.Hooks.ExternalAuthDisabled = true 1936 user.Filters.Hooks.PreLoginDisabled = true 1937 user.Filters.Hooks.CheckPasswordDisabled = false 1938 user.Filters.DisableFsChecks = true 1939 user.Filters.FilePatterns = append(user.Filters.FilePatterns, sdk.PatternsFilter{ 1940 Path: "/subdir", 1941 AllowedPatterns: []string{"*.zip", "*.rar"}, 1942 DeniedPatterns: []string{"*.jpg", "*.png"}, 1943 }) 1944 user.Filters.MaxUploadFileSize = 4096 1945 user.UploadBandwidth = 1024 1946 user.DownloadBandwidth = 512 1947 user.VirtualFolders = nil 1948 mappedPath1 := filepath.Join(os.TempDir(), "mapped_dir1") 1949 mappedPath2 := filepath.Join(os.TempDir(), "mapped_dir2") 1950 folderName1 := filepath.Base(mappedPath1) 1951 folderName2 := filepath.Base(mappedPath2) 1952 user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{ 1953 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1954 Name: folderName1, 1955 MappedPath: mappedPath1, 1956 }, 1957 VirtualPath: "/vdir1", 1958 }) 1959 user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{ 1960 BaseVirtualFolder: vfs.BaseVirtualFolder{ 1961 Name: folderName2, 1962 MappedPath: mappedPath2, 1963 }, 1964 VirtualPath: "/vdir12/subdir", 1965 QuotaSize: 123, 1966 QuotaFiles: 2, 1967 }) 1968 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 1969 assert.NoError(t, err) 1970 1971 _, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "invalid") 1972 assert.NoError(t, err) 1973 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "0") 1974 assert.NoError(t, err) 1975 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "1") 1976 assert.NoError(t, err) 1977 user.Permissions["/subdir"] = []string{} 1978 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 1979 assert.NoError(t, err) 1980 assert.Len(t, user.Permissions["/subdir"], 0) 1981 assert.Len(t, user.VirtualFolders, 2) 1982 for _, folder := range user.VirtualFolders { 1983 assert.Greater(t, folder.ID, int64(0)) 1984 if folder.VirtualPath == "/vdir12/subdir" { 1985 assert.Equal(t, int64(123), folder.QuotaSize) 1986 assert.Equal(t, 2, folder.QuotaFiles) 1987 } 1988 } 1989 folder, _, err := httpdtest.GetFolderByName(folderName1, http.StatusOK) 1990 assert.NoError(t, err) 1991 assert.Len(t, folder.Users, 1) 1992 assert.Contains(t, folder.Users, user.Username) 1993 1994 _, err = httpdtest.RemoveUser(user, http.StatusOK) 1995 assert.NoError(t, err) 1996 // removing the user must remove folder mapping 1997 folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK) 1998 assert.NoError(t, err) 1999 assert.Len(t, folder.Users, 0) 2000 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 2001 assert.NoError(t, err) 2002 folder, _, err = httpdtest.GetFolderByName(folderName2, http.StatusOK) 2003 assert.NoError(t, err) 2004 assert.Len(t, folder.Users, 0) 2005 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 2006 assert.NoError(t, err) 2007} 2008 2009func TestUpdateUserQuotaUsage(t *testing.T) { 2010 u := getTestUser() 2011 usedQuotaFiles := 1 2012 usedQuotaSize := int64(65535) 2013 u.UsedQuotaFiles = usedQuotaFiles 2014 u.UsedQuotaSize = usedQuotaSize 2015 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 2016 assert.NoError(t, err) 2017 _, err = httpdtest.UpdateQuotaUsage(u, "invalid_mode", http.StatusBadRequest) 2018 assert.NoError(t, err) 2019 _, err = httpdtest.UpdateQuotaUsage(u, "", http.StatusOK) 2020 assert.NoError(t, err) 2021 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 2022 assert.NoError(t, err) 2023 assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles) 2024 assert.Equal(t, usedQuotaSize, user.UsedQuotaSize) 2025 _, err = httpdtest.UpdateQuotaUsage(u, "add", http.StatusBadRequest) 2026 assert.NoError(t, err, "user has no quota restrictions add mode should fail") 2027 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 2028 assert.NoError(t, err) 2029 assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles) 2030 assert.Equal(t, usedQuotaSize, user.UsedQuotaSize) 2031 user.QuotaFiles = 100 2032 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2033 assert.NoError(t, err) 2034 _, err = httpdtest.UpdateQuotaUsage(u, "add", http.StatusOK) 2035 assert.NoError(t, err) 2036 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 2037 assert.NoError(t, err) 2038 assert.Equal(t, 2*usedQuotaFiles, user.UsedQuotaFiles) 2039 assert.Equal(t, 2*usedQuotaSize, user.UsedQuotaSize) 2040 u.UsedQuotaFiles = -1 2041 _, err = httpdtest.UpdateQuotaUsage(u, "", http.StatusBadRequest) 2042 assert.NoError(t, err) 2043 u.UsedQuotaFiles = usedQuotaFiles 2044 u.Username = u.Username + "1" 2045 _, err = httpdtest.UpdateQuotaUsage(u, "", http.StatusNotFound) 2046 assert.NoError(t, err) 2047 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2048 assert.NoError(t, err) 2049} 2050 2051func TestUserFolderMapping(t *testing.T) { 2052 mappedPath1 := filepath.Join(os.TempDir(), "mapped_dir1") 2053 mappedPath2 := filepath.Join(os.TempDir(), "mapped_dir2") 2054 folderName1 := filepath.Base(mappedPath1) 2055 folderName2 := filepath.Base(mappedPath2) 2056 u1 := getTestUser() 2057 u1.VirtualFolders = append(u1.VirtualFolders, vfs.VirtualFolder{ 2058 BaseVirtualFolder: vfs.BaseVirtualFolder{ 2059 Name: folderName1, 2060 MappedPath: mappedPath1, 2061 UsedQuotaFiles: 2, 2062 UsedQuotaSize: 123, 2063 LastQuotaUpdate: 456, 2064 }, 2065 VirtualPath: "/vdir", 2066 QuotaSize: -1, 2067 QuotaFiles: -1, 2068 }) 2069 user1, _, err := httpdtest.AddUser(u1, http.StatusCreated) 2070 assert.NoError(t, err) 2071 // virtual folder must be auto created 2072 folder, _, err := httpdtest.GetFolderByName(folderName1, http.StatusOK) 2073 assert.NoError(t, err) 2074 assert.Len(t, folder.Users, 1) 2075 assert.Contains(t, folder.Users, user1.Username) 2076 assert.Equal(t, 0, folder.UsedQuotaFiles) 2077 assert.Equal(t, int64(0), folder.UsedQuotaSize) 2078 assert.Equal(t, int64(0), folder.LastQuotaUpdate) 2079 assert.Equal(t, 0, user1.VirtualFolders[0].UsedQuotaFiles) 2080 assert.Equal(t, int64(0), user1.VirtualFolders[0].UsedQuotaSize) 2081 assert.Equal(t, int64(0), user1.VirtualFolders[0].LastQuotaUpdate) 2082 2083 u2 := getTestUser() 2084 u2.Username = defaultUsername + "2" 2085 u2.VirtualFolders = append(u2.VirtualFolders, vfs.VirtualFolder{ 2086 BaseVirtualFolder: vfs.BaseVirtualFolder{ 2087 Name: folderName1, 2088 MappedPath: mappedPath1, 2089 }, 2090 VirtualPath: "/vdir1", 2091 QuotaSize: 0, 2092 QuotaFiles: 0, 2093 }) 2094 u2.VirtualFolders = append(u2.VirtualFolders, vfs.VirtualFolder{ 2095 BaseVirtualFolder: vfs.BaseVirtualFolder{ 2096 Name: folderName2, 2097 MappedPath: mappedPath2, 2098 }, 2099 VirtualPath: "/vdir2", 2100 QuotaSize: -1, 2101 QuotaFiles: -1, 2102 }) 2103 user2, _, err := httpdtest.AddUser(u2, http.StatusCreated) 2104 assert.NoError(t, err) 2105 folder, _, err = httpdtest.GetFolderByName(folderName2, http.StatusOK) 2106 assert.NoError(t, err) 2107 assert.Len(t, folder.Users, 1) 2108 assert.Contains(t, folder.Users, user2.Username) 2109 folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK) 2110 assert.NoError(t, err) 2111 assert.Len(t, folder.Users, 2) 2112 assert.Contains(t, folder.Users, user1.Username) 2113 assert.Contains(t, folder.Users, user2.Username) 2114 // now update user2 removing mappedPath1 2115 user2.VirtualFolders = nil 2116 user2.VirtualFolders = append(user2.VirtualFolders, vfs.VirtualFolder{ 2117 BaseVirtualFolder: vfs.BaseVirtualFolder{ 2118 Name: folderName2, 2119 MappedPath: mappedPath2, 2120 UsedQuotaFiles: 2, 2121 UsedQuotaSize: 123, 2122 }, 2123 VirtualPath: "/vdir", 2124 QuotaSize: 0, 2125 QuotaFiles: 0, 2126 }) 2127 user2, _, err = httpdtest.UpdateUser(user2, http.StatusOK, "") 2128 assert.NoError(t, err) 2129 folder, _, err = httpdtest.GetFolderByName(folderName2, http.StatusOK) 2130 assert.NoError(t, err) 2131 assert.Len(t, folder.Users, 1) 2132 assert.Contains(t, folder.Users, user2.Username) 2133 assert.Equal(t, 0, folder.UsedQuotaFiles) 2134 assert.Equal(t, int64(0), folder.UsedQuotaSize) 2135 folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK) 2136 assert.NoError(t, err) 2137 assert.Len(t, folder.Users, 1) 2138 assert.Contains(t, folder.Users, user1.Username) 2139 // add mappedPath1 again to user2 2140 user2.VirtualFolders = append(user2.VirtualFolders, vfs.VirtualFolder{ 2141 BaseVirtualFolder: vfs.BaseVirtualFolder{ 2142 Name: folderName1, 2143 MappedPath: mappedPath1, 2144 }, 2145 VirtualPath: "/vdir1", 2146 }) 2147 user2, _, err = httpdtest.UpdateUser(user2, http.StatusOK, "") 2148 assert.NoError(t, err) 2149 folder, _, err = httpdtest.GetFolderByName(folderName2, http.StatusOK) 2150 assert.NoError(t, err) 2151 assert.Len(t, folder.Users, 1) 2152 assert.Contains(t, folder.Users, user2.Username) 2153 // removing virtual folders should clear relations on both side 2154 _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName2}, http.StatusOK) 2155 assert.NoError(t, err) 2156 user2, _, err = httpdtest.GetUserByUsername(user2.Username, http.StatusOK) 2157 assert.NoError(t, err) 2158 if assert.Len(t, user2.VirtualFolders, 1) { 2159 folder := user2.VirtualFolders[0] 2160 assert.Equal(t, mappedPath1, folder.MappedPath) 2161 assert.Equal(t, folderName1, folder.Name) 2162 } 2163 user1, _, err = httpdtest.GetUserByUsername(user1.Username, http.StatusOK) 2164 assert.NoError(t, err) 2165 if assert.Len(t, user2.VirtualFolders, 1) { 2166 folder := user2.VirtualFolders[0] 2167 assert.Equal(t, mappedPath1, folder.MappedPath) 2168 } 2169 2170 folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK) 2171 assert.NoError(t, err) 2172 assert.Len(t, folder.Users, 2) 2173 // removing a user should clear virtual folder mapping 2174 _, err = httpdtest.RemoveUser(user1, http.StatusOK) 2175 assert.NoError(t, err) 2176 folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK) 2177 assert.NoError(t, err) 2178 assert.Len(t, folder.Users, 1) 2179 assert.Contains(t, folder.Users, user2.Username) 2180 // removing a folder should clear mapping on the user side too 2181 _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName1}, http.StatusOK) 2182 assert.NoError(t, err) 2183 user2, _, err = httpdtest.GetUserByUsername(user2.Username, http.StatusOK) 2184 assert.NoError(t, err) 2185 assert.Len(t, user2.VirtualFolders, 0) 2186 _, err = httpdtest.RemoveUser(user2, http.StatusOK) 2187 assert.NoError(t, err) 2188} 2189 2190func TestUserS3Config(t *testing.T) { 2191 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 2192 assert.NoError(t, err) 2193 user.FsConfig.Provider = sdk.S3FilesystemProvider 2194 user.FsConfig.S3Config.Bucket = "test" //nolint:goconst 2195 user.FsConfig.S3Config.Region = "us-east-1" //nolint:goconst 2196 user.FsConfig.S3Config.AccessKey = "Server-Access-Key" 2197 user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("Server-Access-Secret") 2198 user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000" 2199 user.FsConfig.S3Config.UploadPartSize = 8 2200 user.FsConfig.S3Config.DownloadPartMaxTime = 60 2201 user.FsConfig.S3Config.ForcePathStyle = true 2202 user.FsConfig.S3Config.DownloadPartSize = 6 2203 folderName := "vfolderName" 2204 user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{ 2205 BaseVirtualFolder: vfs.BaseVirtualFolder{ 2206 Name: folderName, 2207 MappedPath: filepath.Join(os.TempDir(), "folderName"), 2208 FsConfig: vfs.Filesystem{ 2209 Provider: sdk.CryptedFilesystemProvider, 2210 CryptConfig: vfs.CryptFsConfig{ 2211 CryptFsConfig: sdk.CryptFsConfig{ 2212 Passphrase: kms.NewPlainSecret("Crypted-Secret"), 2213 }, 2214 }, 2215 }, 2216 }, 2217 VirtualPath: "/folderPath", 2218 }) 2219 user, body, err := httpdtest.UpdateUser(user, http.StatusOK, "") 2220 assert.NoError(t, err, string(body)) 2221 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus()) 2222 assert.NotEmpty(t, user.FsConfig.S3Config.AccessSecret.GetPayload()) 2223 assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 2224 assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey()) 2225 assert.Equal(t, 60, user.FsConfig.S3Config.DownloadPartMaxTime) 2226 if assert.Len(t, user.VirtualFolders, 1) { 2227 folder := user.VirtualFolders[0] 2228 assert.Equal(t, kms.SecretStatusSecretBox, folder.FsConfig.CryptConfig.Passphrase.GetStatus()) 2229 assert.NotEmpty(t, folder.FsConfig.CryptConfig.Passphrase.GetPayload()) 2230 assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 2231 assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetKey()) 2232 } 2233 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2234 assert.NoError(t, err) 2235 folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK) 2236 assert.NoError(t, err) 2237 assert.Equal(t, kms.SecretStatusSecretBox, folder.FsConfig.CryptConfig.Passphrase.GetStatus()) 2238 assert.NotEmpty(t, folder.FsConfig.CryptConfig.Passphrase.GetPayload()) 2239 assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 2240 assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetKey()) 2241 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 2242 assert.NoError(t, err) 2243 user.Password = defaultPassword 2244 user.ID = 0 2245 user.CreatedAt = 0 2246 user.VirtualFolders = nil 2247 secret := kms.NewSecret(kms.SecretStatusSecretBox, "Server-Access-Secret", "", "") 2248 user.FsConfig.S3Config.AccessSecret = secret 2249 _, _, err = httpdtest.AddUser(user, http.StatusCreated) 2250 assert.Error(t, err) 2251 user.FsConfig.S3Config.AccessSecret.SetStatus(kms.SecretStatusPlain) 2252 user, _, err = httpdtest.AddUser(user, http.StatusCreated) 2253 assert.NoError(t, err) 2254 initialSecretPayload := user.FsConfig.S3Config.AccessSecret.GetPayload() 2255 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus()) 2256 assert.NotEmpty(t, initialSecretPayload) 2257 assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 2258 assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey()) 2259 user.FsConfig.Provider = sdk.S3FilesystemProvider 2260 user.FsConfig.S3Config.Bucket = "test-bucket" 2261 user.FsConfig.S3Config.Region = "us-east-1" //nolint:goconst 2262 user.FsConfig.S3Config.AccessKey = "Server-Access-Key1" 2263 user.FsConfig.S3Config.Endpoint = "http://localhost:9000" 2264 user.FsConfig.S3Config.KeyPrefix = "somedir/subdir" //nolint:goconst 2265 user.FsConfig.S3Config.UploadConcurrency = 5 2266 user.FsConfig.S3Config.DownloadConcurrency = 4 2267 user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "") 2268 assert.NoError(t, err, string(bb)) 2269 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus()) 2270 assert.Equal(t, initialSecretPayload, user.FsConfig.S3Config.AccessSecret.GetPayload()) 2271 assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 2272 assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey()) 2273 // test user without access key and access secret (shared config state) 2274 user.FsConfig.Provider = sdk.S3FilesystemProvider 2275 user.FsConfig.S3Config.Bucket = "testbucket" 2276 user.FsConfig.S3Config.Region = "us-east-1" 2277 user.FsConfig.S3Config.AccessKey = "" 2278 user.FsConfig.S3Config.AccessSecret = kms.NewEmptySecret() 2279 user.FsConfig.S3Config.Endpoint = "" 2280 user.FsConfig.S3Config.KeyPrefix = "somedir/subdir" 2281 user.FsConfig.S3Config.UploadPartSize = 6 2282 user.FsConfig.S3Config.UploadConcurrency = 4 2283 user, body, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2284 assert.NoError(t, err, string(body)) 2285 assert.Nil(t, user.FsConfig.S3Config.AccessSecret) 2286 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2287 assert.NoError(t, err) 2288 user.Password = defaultPassword 2289 user.ID = 0 2290 user.CreatedAt = 0 2291 // shared credential test for add instead of update 2292 user, _, err = httpdtest.AddUser(user, http.StatusCreated) 2293 assert.NoError(t, err) 2294 assert.Nil(t, user.FsConfig.S3Config.AccessSecret) 2295 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2296 assert.NoError(t, err) 2297} 2298 2299func TestUserGCSConfig(t *testing.T) { 2300 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 2301 assert.NoError(t, err) 2302 err = os.RemoveAll(credentialsPath) 2303 assert.NoError(t, err) 2304 err = os.MkdirAll(credentialsPath, 0700) 2305 assert.NoError(t, err) 2306 user.FsConfig.Provider = sdk.GCSFilesystemProvider 2307 user.FsConfig.GCSConfig.Bucket = "test" 2308 user.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials") //nolint:goconst 2309 user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "") 2310 assert.NoError(t, err, string(bb)) 2311 credentialFile := filepath.Join(credentialsPath, fmt.Sprintf("%v_gcs_credentials.json", user.Username)) 2312 assert.FileExists(t, credentialFile) 2313 creds, err := os.ReadFile(credentialFile) 2314 assert.NoError(t, err) 2315 secret := kms.NewEmptySecret() 2316 err = json.Unmarshal(creds, secret) 2317 assert.NoError(t, err) 2318 err = secret.Decrypt() 2319 assert.NoError(t, err) 2320 assert.Equal(t, "fake credentials", secret.GetPayload()) 2321 user.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusSecretBox, "fake encrypted credentials", "", "") 2322 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2323 assert.NoError(t, err) 2324 assert.FileExists(t, credentialFile) 2325 creds, err = os.ReadFile(credentialFile) 2326 assert.NoError(t, err) 2327 secret = kms.NewEmptySecret() 2328 err = json.Unmarshal(creds, secret) 2329 assert.NoError(t, err) 2330 err = secret.Decrypt() 2331 assert.NoError(t, err) 2332 assert.Equal(t, "fake credentials", secret.GetPayload()) 2333 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2334 assert.NoError(t, err) 2335 user.Password = defaultPassword 2336 user.ID = 0 2337 user.CreatedAt = 0 2338 user.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusSecretBox, "fake credentials", "", "") 2339 _, _, err = httpdtest.AddUser(user, http.StatusCreated) 2340 assert.Error(t, err) 2341 user.FsConfig.GCSConfig.Credentials.SetStatus(kms.SecretStatusPlain) 2342 user, body, err := httpdtest.AddUser(user, http.StatusCreated) 2343 assert.NoError(t, err, string(body)) 2344 err = os.RemoveAll(credentialsPath) 2345 assert.NoError(t, err) 2346 err = os.MkdirAll(credentialsPath, 0700) 2347 assert.NoError(t, err) 2348 user.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret() 2349 user.FsConfig.GCSConfig.AutomaticCredentials = 1 2350 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2351 assert.NoError(t, err) 2352 assert.NoFileExists(t, credentialFile) 2353 user.FsConfig.GCSConfig = vfs.GCSFsConfig{} 2354 user.FsConfig.Provider = sdk.S3FilesystemProvider 2355 user.FsConfig.S3Config.Bucket = "test1" 2356 user.FsConfig.S3Config.Region = "us-east-1" 2357 user.FsConfig.S3Config.AccessKey = "Server-Access-Key1" 2358 user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("secret") 2359 user.FsConfig.S3Config.Endpoint = "http://localhost:9000" 2360 user.FsConfig.S3Config.KeyPrefix = "somedir/subdir" 2361 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2362 assert.NoError(t, err) 2363 user.FsConfig.S3Config = vfs.S3FsConfig{} 2364 user.FsConfig.Provider = sdk.GCSFilesystemProvider 2365 user.FsConfig.GCSConfig.Bucket = "test1" 2366 user.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials") 2367 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2368 assert.NoError(t, err) 2369 2370 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2371 assert.NoError(t, err) 2372} 2373 2374func TestUserAzureBlobConfig(t *testing.T) { 2375 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 2376 assert.NoError(t, err) 2377 user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider 2378 user.FsConfig.AzBlobConfig.Container = "test" 2379 user.FsConfig.AzBlobConfig.AccountName = "Server-Account-Name" 2380 user.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("Server-Account-Key") 2381 user.FsConfig.AzBlobConfig.Endpoint = "http://127.0.0.1:9000" 2382 user.FsConfig.AzBlobConfig.UploadPartSize = 8 2383 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2384 assert.NoError(t, err) 2385 initialPayload := user.FsConfig.AzBlobConfig.AccountKey.GetPayload() 2386 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) 2387 assert.NotEmpty(t, initialPayload) 2388 assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) 2389 assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey()) 2390 user.FsConfig.AzBlobConfig.AccountKey.SetStatus(kms.SecretStatusSecretBox) 2391 user.FsConfig.AzBlobConfig.AccountKey.SetAdditionalData("data") 2392 user.FsConfig.AzBlobConfig.AccountKey.SetKey("fake key") 2393 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2394 assert.NoError(t, err) 2395 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) 2396 assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.AccountKey.GetPayload()) 2397 assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) 2398 assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey()) 2399 2400 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2401 assert.NoError(t, err) 2402 user.Password = defaultPassword 2403 user.ID = 0 2404 user.CreatedAt = 0 2405 secret := kms.NewSecret(kms.SecretStatusSecretBox, "Server-Account-Key", "", "") 2406 user.FsConfig.AzBlobConfig.AccountKey = secret 2407 _, _, err = httpdtest.AddUser(user, http.StatusCreated) 2408 assert.Error(t, err) 2409 user.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("Server-Account-Key-Test") 2410 user, _, err = httpdtest.AddUser(user, http.StatusCreated) 2411 assert.NoError(t, err) 2412 initialPayload = user.FsConfig.AzBlobConfig.AccountKey.GetPayload() 2413 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) 2414 assert.NotEmpty(t, initialPayload) 2415 assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) 2416 assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey()) 2417 user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider 2418 user.FsConfig.AzBlobConfig.Container = "test-container" 2419 user.FsConfig.AzBlobConfig.Endpoint = "http://localhost:9001" 2420 user.FsConfig.AzBlobConfig.KeyPrefix = "somedir/subdir" 2421 user.FsConfig.AzBlobConfig.UploadConcurrency = 5 2422 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2423 assert.NoError(t, err) 2424 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) 2425 assert.NotEmpty(t, initialPayload) 2426 assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.AccountKey.GetPayload()) 2427 assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) 2428 assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey()) 2429 // test user without access key and access secret (SAS) 2430 user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider 2431 user.FsConfig.AzBlobConfig.SASURL = kms.NewPlainSecret("https://myaccount.blob.core.windows.net/pictures/profile.jpg?sv=2012-02-12&st=2009-02-09&se=2009-02-10&sr=c&sp=r&si=YWJjZGVmZw%3d%3d&sig=dD80ihBh5jfNpymO5Hg1IdiJIEvHcJpCMiCMnN%2fRnbI%3d") 2432 user.FsConfig.AzBlobConfig.KeyPrefix = "somedir/subdir" 2433 user.FsConfig.AzBlobConfig.AccountName = "" 2434 user.FsConfig.AzBlobConfig.AccountKey = kms.NewEmptySecret() 2435 user.FsConfig.AzBlobConfig.UploadPartSize = 6 2436 user.FsConfig.AzBlobConfig.UploadConcurrency = 4 2437 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2438 assert.NoError(t, err) 2439 assert.Nil(t, user.FsConfig.AzBlobConfig.AccountKey) 2440 assert.NotNil(t, user.FsConfig.AzBlobConfig.SASURL) 2441 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2442 assert.NoError(t, err) 2443 user.Password = defaultPassword 2444 user.ID = 0 2445 user.CreatedAt = 0 2446 // sas test for add instead of update 2447 user.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{ 2448 AzBlobFsConfig: sdk.AzBlobFsConfig{ 2449 Container: user.FsConfig.AzBlobConfig.Container, 2450 SASURL: kms.NewPlainSecret("http://127.0.0.1/fake/sass/url"), 2451 }, 2452 } 2453 user, _, err = httpdtest.AddUser(user, http.StatusCreated) 2454 assert.NoError(t, err) 2455 assert.Nil(t, user.FsConfig.AzBlobConfig.AccountKey) 2456 initialPayload = user.FsConfig.AzBlobConfig.SASURL.GetPayload() 2457 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.SASURL.GetStatus()) 2458 assert.NotEmpty(t, initialPayload) 2459 assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetAdditionalData()) 2460 assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetKey()) 2461 user.FsConfig.AzBlobConfig.SASURL.SetStatus(kms.SecretStatusSecretBox) 2462 user.FsConfig.AzBlobConfig.SASURL.SetAdditionalData("data") 2463 user.FsConfig.AzBlobConfig.SASURL.SetKey("fake key") 2464 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2465 assert.NoError(t, err) 2466 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.SASURL.GetStatus()) 2467 assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.SASURL.GetPayload()) 2468 assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetAdditionalData()) 2469 assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetKey()) 2470 2471 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2472 assert.NoError(t, err) 2473} 2474 2475func TestUserCryptFs(t *testing.T) { 2476 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 2477 assert.NoError(t, err) 2478 user.FsConfig.Provider = sdk.CryptedFilesystemProvider 2479 user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("crypt passphrase") 2480 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2481 assert.NoError(t, err) 2482 initialPayload := user.FsConfig.CryptConfig.Passphrase.GetPayload() 2483 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) 2484 assert.NotEmpty(t, initialPayload) 2485 assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 2486 assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey()) 2487 user.FsConfig.CryptConfig.Passphrase.SetStatus(kms.SecretStatusSecretBox) 2488 user.FsConfig.CryptConfig.Passphrase.SetAdditionalData("data") 2489 user.FsConfig.CryptConfig.Passphrase.SetKey("fake pass key") 2490 user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "") 2491 assert.NoError(t, err, string(bb)) 2492 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) 2493 assert.Equal(t, initialPayload, user.FsConfig.CryptConfig.Passphrase.GetPayload()) 2494 assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 2495 assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey()) 2496 2497 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2498 assert.NoError(t, err) 2499 user.Password = defaultPassword 2500 user.ID = 0 2501 user.CreatedAt = 0 2502 secret := kms.NewSecret(kms.SecretStatusSecretBox, "invalid encrypted payload", "", "") 2503 user.FsConfig.CryptConfig.Passphrase = secret 2504 _, _, err = httpdtest.AddUser(user, http.StatusCreated) 2505 assert.Error(t, err) 2506 user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("passphrase test") 2507 user, _, err = httpdtest.AddUser(user, http.StatusCreated) 2508 assert.NoError(t, err) 2509 initialPayload = user.FsConfig.CryptConfig.Passphrase.GetPayload() 2510 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) 2511 assert.NotEmpty(t, initialPayload) 2512 assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 2513 assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey()) 2514 user.FsConfig.Provider = sdk.CryptedFilesystemProvider 2515 user.FsConfig.CryptConfig.Passphrase.SetKey("pass") 2516 user, bb, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2517 assert.NoError(t, err, string(bb)) 2518 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) 2519 assert.NotEmpty(t, initialPayload) 2520 assert.Equal(t, initialPayload, user.FsConfig.CryptConfig.Passphrase.GetPayload()) 2521 assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 2522 assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey()) 2523 2524 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2525 assert.NoError(t, err) 2526} 2527 2528func TestUserSFTPFs(t *testing.T) { 2529 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 2530 assert.NoError(t, err) 2531 user.FsConfig.Provider = sdk.SFTPFilesystemProvider 2532 user.FsConfig.SFTPConfig.Endpoint = "127.0.0.1" // missing port 2533 user.FsConfig.SFTPConfig.Username = "sftp_user" 2534 user.FsConfig.SFTPConfig.Password = kms.NewPlainSecret("sftp_pwd") 2535 user.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey) 2536 user.FsConfig.SFTPConfig.Fingerprints = []string{sftpPkeyFingerprint} 2537 user.FsConfig.SFTPConfig.BufferSize = 2 2538 _, resp, err := httpdtest.UpdateUser(user, http.StatusBadRequest, "") 2539 assert.NoError(t, err) 2540 assert.Contains(t, string(resp), "invalid endpoint") 2541 2542 user.FsConfig.SFTPConfig.Endpoint = "127.0.0.1:2022" 2543 user.FsConfig.SFTPConfig.DisableCouncurrentReads = true 2544 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2545 assert.NoError(t, err) 2546 assert.Equal(t, "/", user.FsConfig.SFTPConfig.Prefix) 2547 assert.True(t, user.FsConfig.SFTPConfig.DisableCouncurrentReads) 2548 assert.Equal(t, int64(2), user.FsConfig.SFTPConfig.BufferSize) 2549 initialPwdPayload := user.FsConfig.SFTPConfig.Password.GetPayload() 2550 initialPkeyPayload := user.FsConfig.SFTPConfig.PrivateKey.GetPayload() 2551 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.Password.GetStatus()) 2552 assert.NotEmpty(t, initialPwdPayload) 2553 assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetAdditionalData()) 2554 assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetKey()) 2555 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) 2556 assert.NotEmpty(t, initialPkeyPayload) 2557 assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) 2558 assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey()) 2559 user.FsConfig.SFTPConfig.Password.SetStatus(kms.SecretStatusSecretBox) 2560 user.FsConfig.SFTPConfig.Password.SetAdditionalData("adata") 2561 user.FsConfig.SFTPConfig.Password.SetKey("fake pwd key") 2562 user.FsConfig.SFTPConfig.PrivateKey.SetStatus(kms.SecretStatusSecretBox) 2563 user.FsConfig.SFTPConfig.PrivateKey.SetAdditionalData("adata") 2564 user.FsConfig.SFTPConfig.PrivateKey.SetKey("fake key") 2565 user.FsConfig.SFTPConfig.DisableCouncurrentReads = false 2566 user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "") 2567 assert.NoError(t, err, string(bb)) 2568 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.Password.GetStatus()) 2569 assert.Equal(t, initialPwdPayload, user.FsConfig.SFTPConfig.Password.GetPayload()) 2570 assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetAdditionalData()) 2571 assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetKey()) 2572 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) 2573 assert.Equal(t, initialPkeyPayload, user.FsConfig.SFTPConfig.PrivateKey.GetPayload()) 2574 assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) 2575 assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey()) 2576 assert.False(t, user.FsConfig.SFTPConfig.DisableCouncurrentReads) 2577 2578 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2579 assert.NoError(t, err) 2580 user.Password = defaultPassword 2581 user.ID = 0 2582 user.CreatedAt = 0 2583 secret := kms.NewSecret(kms.SecretStatusSecretBox, "invalid encrypted payload", "", "") 2584 user.FsConfig.SFTPConfig.Password = secret 2585 _, _, err = httpdtest.AddUser(user, http.StatusCreated) 2586 assert.Error(t, err) 2587 user.FsConfig.SFTPConfig.Password = kms.NewEmptySecret() 2588 user.FsConfig.SFTPConfig.PrivateKey = secret 2589 _, _, err = httpdtest.AddUser(user, http.StatusCreated) 2590 assert.Error(t, err) 2591 2592 user.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey) 2593 user, _, err = httpdtest.AddUser(user, http.StatusCreated) 2594 assert.NoError(t, err) 2595 initialPkeyPayload = user.FsConfig.SFTPConfig.PrivateKey.GetPayload() 2596 assert.Nil(t, user.FsConfig.SFTPConfig.Password) 2597 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) 2598 assert.NotEmpty(t, initialPkeyPayload) 2599 assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) 2600 assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey()) 2601 user.FsConfig.Provider = sdk.SFTPFilesystemProvider 2602 user.FsConfig.SFTPConfig.PrivateKey.SetKey("k") 2603 user, bb, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2604 assert.NoError(t, err, string(bb)) 2605 assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) 2606 assert.NotEmpty(t, initialPkeyPayload) 2607 assert.Equal(t, initialPkeyPayload, user.FsConfig.SFTPConfig.PrivateKey.GetPayload()) 2608 assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) 2609 assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey()) 2610 2611 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2612 assert.NoError(t, err) 2613} 2614 2615func TestUserHiddenFields(t *testing.T) { 2616 err := dataprovider.Close() 2617 assert.NoError(t, err) 2618 err = config.LoadConfig(configDir, "") 2619 assert.NoError(t, err) 2620 providerConf := config.GetProviderConf() 2621 providerConf.PreferDatabaseCredentials = true 2622 err = dataprovider.Initialize(providerConf, configDir, true) 2623 assert.NoError(t, err) 2624 2625 // sensitive data must be hidden but not deleted from the dataprovider 2626 usernames := []string{"user1", "user2", "user3", "user4", "user5"} 2627 u1 := getTestUser() 2628 u1.Username = usernames[0] 2629 u1.FsConfig.Provider = sdk.S3FilesystemProvider 2630 u1.FsConfig.S3Config.Bucket = "test" 2631 u1.FsConfig.S3Config.Region = "us-east-1" 2632 u1.FsConfig.S3Config.AccessKey = "S3-Access-Key" 2633 u1.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("S3-Access-Secret") 2634 user1, _, err := httpdtest.AddUser(u1, http.StatusCreated) 2635 assert.NoError(t, err) 2636 2637 u2 := getTestUser() 2638 u2.Username = usernames[1] 2639 u2.FsConfig.Provider = sdk.GCSFilesystemProvider 2640 u2.FsConfig.GCSConfig.Bucket = "test" 2641 u2.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials") 2642 u2.FsConfig.GCSConfig.ACL = "bucketOwnerRead" 2643 user2, _, err := httpdtest.AddUser(u2, http.StatusCreated) 2644 assert.NoError(t, err) 2645 2646 u3 := getTestUser() 2647 u3.Username = usernames[2] 2648 u3.FsConfig.Provider = sdk.AzureBlobFilesystemProvider 2649 u3.FsConfig.AzBlobConfig.Container = "test" 2650 u3.FsConfig.AzBlobConfig.AccountName = "Server-Account-Name" 2651 u3.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("Server-Account-Key") 2652 user3, _, err := httpdtest.AddUser(u3, http.StatusCreated) 2653 assert.NoError(t, err) 2654 2655 u4 := getTestUser() 2656 u4.Username = usernames[3] 2657 u4.FsConfig.Provider = sdk.CryptedFilesystemProvider 2658 u4.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("test passphrase") 2659 user4, _, err := httpdtest.AddUser(u4, http.StatusCreated) 2660 assert.NoError(t, err) 2661 2662 u5 := getTestUser() 2663 u5.Username = usernames[4] 2664 u5.FsConfig.Provider = sdk.SFTPFilesystemProvider 2665 u5.FsConfig.SFTPConfig.Endpoint = "127.0.0.1:2022" 2666 u5.FsConfig.SFTPConfig.Username = "sftp_user" 2667 u5.FsConfig.SFTPConfig.Password = kms.NewPlainSecret("apassword") 2668 u5.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey) 2669 u5.FsConfig.SFTPConfig.Fingerprints = []string{sftpPkeyFingerprint} 2670 u5.FsConfig.SFTPConfig.Prefix = "/prefix" 2671 user5, _, err := httpdtest.AddUser(u5, http.StatusCreated) 2672 assert.NoError(t, err) 2673 2674 users, _, err := httpdtest.GetUsers(0, 0, http.StatusOK) 2675 assert.NoError(t, err) 2676 assert.GreaterOrEqual(t, len(users), 5) 2677 for _, username := range usernames { 2678 user, _, err := httpdtest.GetUserByUsername(username, http.StatusOK) 2679 assert.NoError(t, err) 2680 assert.Empty(t, user.Password) 2681 } 2682 user1, _, err = httpdtest.GetUserByUsername(user1.Username, http.StatusOK) 2683 assert.NoError(t, err) 2684 assert.Empty(t, user1.Password) 2685 assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetKey()) 2686 assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 2687 assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetStatus()) 2688 assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetPayload()) 2689 2690 user2, _, err = httpdtest.GetUserByUsername(user2.Username, http.StatusOK) 2691 assert.NoError(t, err) 2692 assert.Empty(t, user2.Password) 2693 assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetKey()) 2694 assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData()) 2695 assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetStatus()) 2696 assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetPayload()) 2697 2698 user3, _, err = httpdtest.GetUserByUsername(user3.Username, http.StatusOK) 2699 assert.NoError(t, err) 2700 assert.Empty(t, user3.Password) 2701 assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey()) 2702 assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) 2703 assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus()) 2704 assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetPayload()) 2705 2706 user4, _, err = httpdtest.GetUserByUsername(user4.Username, http.StatusOK) 2707 assert.NoError(t, err) 2708 assert.Empty(t, user4.Password) 2709 assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetKey()) 2710 assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 2711 assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetStatus()) 2712 assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetPayload()) 2713 2714 user5, _, err = httpdtest.GetUserByUsername(user5.Username, http.StatusOK) 2715 assert.NoError(t, err) 2716 assert.Empty(t, user5.Password) 2717 assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetKey()) 2718 assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetAdditionalData()) 2719 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetStatus()) 2720 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetPayload()) 2721 assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetKey()) 2722 assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) 2723 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetStatus()) 2724 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetPayload()) 2725 assert.Equal(t, "/prefix", user5.FsConfig.SFTPConfig.Prefix) 2726 2727 // finally check that we have all the data inside the data provider 2728 user1, err = dataprovider.UserExists(user1.Username) 2729 assert.NoError(t, err) 2730 assert.NotEmpty(t, user1.Password) 2731 assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetKey()) 2732 assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 2733 assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetStatus()) 2734 assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetPayload()) 2735 err = user1.FsConfig.S3Config.AccessSecret.Decrypt() 2736 assert.NoError(t, err) 2737 assert.Equal(t, kms.SecretStatusPlain, user1.FsConfig.S3Config.AccessSecret.GetStatus()) 2738 assert.Equal(t, u1.FsConfig.S3Config.AccessSecret.GetPayload(), user1.FsConfig.S3Config.AccessSecret.GetPayload()) 2739 assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetKey()) 2740 assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 2741 2742 user2, err = dataprovider.UserExists(user2.Username) 2743 assert.NoError(t, err) 2744 assert.NotEmpty(t, user2.Password) 2745 assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetKey()) 2746 assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData()) 2747 assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetStatus()) 2748 assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetPayload()) 2749 err = user2.FsConfig.GCSConfig.Credentials.Decrypt() 2750 assert.NoError(t, err) 2751 assert.Equal(t, kms.SecretStatusPlain, user2.FsConfig.GCSConfig.Credentials.GetStatus()) 2752 assert.Equal(t, u2.FsConfig.GCSConfig.Credentials.GetPayload(), user2.FsConfig.GCSConfig.Credentials.GetPayload()) 2753 assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetKey()) 2754 assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData()) 2755 2756 user3, err = dataprovider.UserExists(user3.Username) 2757 assert.NoError(t, err) 2758 assert.NotEmpty(t, user3.Password) 2759 assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey()) 2760 assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) 2761 assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus()) 2762 assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetPayload()) 2763 err = user3.FsConfig.AzBlobConfig.AccountKey.Decrypt() 2764 assert.NoError(t, err) 2765 assert.Equal(t, kms.SecretStatusPlain, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus()) 2766 assert.Equal(t, u3.FsConfig.AzBlobConfig.AccountKey.GetPayload(), user3.FsConfig.AzBlobConfig.AccountKey.GetPayload()) 2767 assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey()) 2768 assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) 2769 2770 user4, err = dataprovider.UserExists(user4.Username) 2771 assert.NoError(t, err) 2772 assert.NotEmpty(t, user4.Password) 2773 assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetKey()) 2774 assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 2775 assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetStatus()) 2776 assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetPayload()) 2777 err = user4.FsConfig.CryptConfig.Passphrase.Decrypt() 2778 assert.NoError(t, err) 2779 assert.Equal(t, kms.SecretStatusPlain, user4.FsConfig.CryptConfig.Passphrase.GetStatus()) 2780 assert.Equal(t, u4.FsConfig.CryptConfig.Passphrase.GetPayload(), user4.FsConfig.CryptConfig.Passphrase.GetPayload()) 2781 assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetKey()) 2782 assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 2783 2784 user5, err = dataprovider.UserExists(user5.Username) 2785 assert.NoError(t, err) 2786 assert.NotEmpty(t, user5.Password) 2787 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetKey()) 2788 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetAdditionalData()) 2789 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetStatus()) 2790 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetPayload()) 2791 err = user5.FsConfig.SFTPConfig.Password.Decrypt() 2792 assert.NoError(t, err) 2793 assert.Equal(t, kms.SecretStatusPlain, user5.FsConfig.SFTPConfig.Password.GetStatus()) 2794 assert.Equal(t, u5.FsConfig.SFTPConfig.Password.GetPayload(), user5.FsConfig.SFTPConfig.Password.GetPayload()) 2795 assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetKey()) 2796 assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetAdditionalData()) 2797 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetKey()) 2798 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) 2799 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetStatus()) 2800 assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetPayload()) 2801 err = user5.FsConfig.SFTPConfig.PrivateKey.Decrypt() 2802 assert.NoError(t, err) 2803 assert.Equal(t, kms.SecretStatusPlain, user5.FsConfig.SFTPConfig.PrivateKey.GetStatus()) 2804 assert.Equal(t, u5.FsConfig.SFTPConfig.PrivateKey.GetPayload(), user5.FsConfig.SFTPConfig.PrivateKey.GetPayload()) 2805 assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetKey()) 2806 assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) 2807 2808 // update the GCS user and check that the credentials are preserved 2809 user2.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret() 2810 user2.FsConfig.GCSConfig.ACL = "private" 2811 _, _, err = httpdtest.UpdateUser(user2, http.StatusOK, "") 2812 assert.NoError(t, err) 2813 2814 user2, _, err = httpdtest.GetUserByUsername(user2.Username, http.StatusOK) 2815 assert.NoError(t, err) 2816 assert.Empty(t, user2.Password) 2817 assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetKey()) 2818 assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData()) 2819 assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetStatus()) 2820 assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetPayload()) 2821 2822 _, err = httpdtest.RemoveUser(user1, http.StatusOK) 2823 assert.NoError(t, err) 2824 _, err = httpdtest.RemoveUser(user2, http.StatusOK) 2825 assert.NoError(t, err) 2826 _, err = httpdtest.RemoveUser(user3, http.StatusOK) 2827 assert.NoError(t, err) 2828 _, err = httpdtest.RemoveUser(user4, http.StatusOK) 2829 assert.NoError(t, err) 2830 _, err = httpdtest.RemoveUser(user5, http.StatusOK) 2831 assert.NoError(t, err) 2832 2833 err = dataprovider.Close() 2834 assert.NoError(t, err) 2835 err = config.LoadConfig(configDir, "") 2836 assert.NoError(t, err) 2837 providerConf = config.GetProviderConf() 2838 providerConf.CredentialsPath = credentialsPath 2839 err = os.RemoveAll(credentialsPath) 2840 assert.NoError(t, err) 2841 err = dataprovider.Initialize(providerConf, configDir, true) 2842 assert.NoError(t, err) 2843} 2844 2845func TestSecretObject(t *testing.T) { 2846 s := kms.NewPlainSecret("test data") 2847 s.SetAdditionalData("username") 2848 require.True(t, s.IsValid()) 2849 err := s.Encrypt() 2850 require.NoError(t, err) 2851 require.Equal(t, kms.SecretStatusSecretBox, s.GetStatus()) 2852 require.NotEmpty(t, s.GetPayload()) 2853 require.NotEmpty(t, s.GetKey()) 2854 require.True(t, s.IsValid()) 2855 err = s.Decrypt() 2856 require.NoError(t, err) 2857 require.Equal(t, kms.SecretStatusPlain, s.GetStatus()) 2858 require.Equal(t, "test data", s.GetPayload()) 2859 require.Empty(t, s.GetKey()) 2860 2861 oldFormat := "$aes$5b97e3a3324a2f53e2357483383367c0$0ed3132b584742ab217866219da633266782b69b13e50ebc6ddfb7c4fbf2f2a414c6d5f813" 2862 s, err = kms.GetSecretFromCompatString(oldFormat) 2863 require.NoError(t, err) 2864 require.True(t, s.IsValid()) 2865 require.Equal(t, kms.SecretStatusPlain, s.GetStatus()) 2866 require.Equal(t, "test data", s.GetPayload()) 2867 require.Empty(t, s.GetKey()) 2868} 2869 2870func TestSecretObjectCompatibility(t *testing.T) { 2871 // this is manually tested against vault too 2872 testPayload := "test payload" 2873 s := kms.NewPlainSecret(testPayload) 2874 require.True(t, s.IsValid()) 2875 err := s.Encrypt() 2876 require.NoError(t, err) 2877 localAsJSON, err := json.Marshal(s) 2878 assert.NoError(t, err) 2879 2880 for _, secretStatus := range []string{kms.SecretStatusSecretBox} { 2881 kmsConfig := config.GetKMSConfig() 2882 assert.Empty(t, kmsConfig.Secrets.MasterKeyPath) 2883 if secretStatus == kms.SecretStatusVaultTransit { 2884 os.Setenv("VAULT_SERVER_URL", "http://127.0.0.1:8200") 2885 os.Setenv("VAULT_SERVER_TOKEN", "s.9lYGq83MbgG5KR5kfebXVyhJ") 2886 kmsConfig.Secrets.URL = "hashivault://mykey" 2887 } 2888 err := kmsConfig.Initialize() 2889 assert.NoError(t, err) 2890 // encrypt without a master key 2891 secret := kms.NewPlainSecret(testPayload) 2892 secret.SetAdditionalData("add data") 2893 err = secret.Encrypt() 2894 assert.NoError(t, err) 2895 assert.Equal(t, 0, secret.GetMode()) 2896 secretClone := secret.Clone() 2897 err = secretClone.Decrypt() 2898 assert.NoError(t, err) 2899 assert.Equal(t, testPayload, secretClone.GetPayload()) 2900 if secretStatus == kms.SecretStatusVaultTransit { 2901 // decrypt the local secret now that the provider is vault 2902 secretLocal := kms.NewEmptySecret() 2903 err = json.Unmarshal(localAsJSON, secretLocal) 2904 assert.NoError(t, err) 2905 assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus()) 2906 assert.Equal(t, 0, secretLocal.GetMode()) 2907 err = secretLocal.Decrypt() 2908 assert.NoError(t, err) 2909 assert.Equal(t, testPayload, secretLocal.GetPayload()) 2910 assert.Equal(t, kms.SecretStatusPlain, secretLocal.GetStatus()) 2911 err = secretLocal.Encrypt() 2912 assert.NoError(t, err) 2913 assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus()) 2914 assert.Equal(t, 0, secretLocal.GetMode()) 2915 } 2916 2917 asJSON, err := json.Marshal(secret) 2918 assert.NoError(t, err) 2919 2920 masterKeyPath := filepath.Join(os.TempDir(), "mkey") 2921 err = os.WriteFile(masterKeyPath, []byte("test key"), os.ModePerm) 2922 assert.NoError(t, err) 2923 config := kms.Configuration{ 2924 Secrets: kms.Secrets{ 2925 MasterKeyPath: masterKeyPath, 2926 }, 2927 } 2928 if secretStatus == kms.SecretStatusVaultTransit { 2929 config.Secrets.URL = "hashivault://mykey" 2930 } 2931 err = config.Initialize() 2932 assert.NoError(t, err) 2933 2934 // now build the secret from JSON 2935 secret = kms.NewEmptySecret() 2936 err = json.Unmarshal(asJSON, secret) 2937 assert.NoError(t, err) 2938 assert.Equal(t, 0, secret.GetMode()) 2939 err = secret.Decrypt() 2940 assert.NoError(t, err) 2941 assert.Equal(t, testPayload, secret.GetPayload()) 2942 err = secret.Encrypt() 2943 assert.NoError(t, err) 2944 assert.Equal(t, 1, secret.GetMode()) 2945 err = secret.Decrypt() 2946 assert.NoError(t, err) 2947 assert.Equal(t, testPayload, secret.GetPayload()) 2948 if secretStatus == kms.SecretStatusVaultTransit { 2949 // decrypt the local secret encryped without a master key now that 2950 // the provider is vault and a master key is set. 2951 // The provider will not change, the master key will be used 2952 secretLocal := kms.NewEmptySecret() 2953 err = json.Unmarshal(localAsJSON, secretLocal) 2954 assert.NoError(t, err) 2955 assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus()) 2956 assert.Equal(t, 0, secretLocal.GetMode()) 2957 err = secretLocal.Decrypt() 2958 assert.NoError(t, err) 2959 assert.Equal(t, testPayload, secretLocal.GetPayload()) 2960 assert.Equal(t, kms.SecretStatusPlain, secretLocal.GetStatus()) 2961 err = secretLocal.Encrypt() 2962 assert.NoError(t, err) 2963 assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus()) 2964 assert.Equal(t, 1, secretLocal.GetMode()) 2965 } 2966 2967 err = kmsConfig.Initialize() 2968 assert.NoError(t, err) 2969 err = os.Remove(masterKeyPath) 2970 assert.NoError(t, err) 2971 if secretStatus == kms.SecretStatusVaultTransit { 2972 os.Unsetenv("VAULT_SERVER_URL") 2973 os.Unsetenv("VAULT_SERVER_TOKEN") 2974 } 2975 } 2976} 2977 2978func TestUpdateUserNoCredentials(t *testing.T) { 2979 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 2980 assert.NoError(t, err) 2981 user.Password = "" 2982 user.PublicKeys = []string{} 2983 // password and public key will be omitted from json serialization if empty and so they will remain unchanged 2984 // and no validation error will be raised 2985 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 2986 assert.NoError(t, err) 2987 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2988 assert.NoError(t, err) 2989} 2990 2991func TestUpdateUserEmptyHomeDir(t *testing.T) { 2992 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 2993 assert.NoError(t, err) 2994 user.HomeDir = "" 2995 _, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "") 2996 assert.NoError(t, err) 2997 _, err = httpdtest.RemoveUser(user, http.StatusOK) 2998 assert.NoError(t, err) 2999} 3000 3001func TestUpdateUserInvalidHomeDir(t *testing.T) { 3002 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 3003 assert.NoError(t, err) 3004 user.HomeDir = "relative_path" 3005 _, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "") 3006 assert.NoError(t, err) 3007 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3008 assert.NoError(t, err) 3009} 3010 3011func TestUpdateNonExistentUser(t *testing.T) { 3012 _, _, err := httpdtest.UpdateUser(getTestUser(), http.StatusNotFound, "") 3013 assert.NoError(t, err) 3014} 3015 3016func TestGetNonExistentUser(t *testing.T) { 3017 _, _, err := httpdtest.GetUserByUsername("na", http.StatusNotFound) 3018 assert.NoError(t, err) 3019} 3020 3021func TestDeleteNonExistentUser(t *testing.T) { 3022 _, err := httpdtest.RemoveUser(getTestUser(), http.StatusNotFound) 3023 assert.NoError(t, err) 3024} 3025 3026func TestAddDuplicateUser(t *testing.T) { 3027 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 3028 assert.NoError(t, err) 3029 _, _, err = httpdtest.AddUser(getTestUser(), http.StatusInternalServerError) 3030 assert.NoError(t, err) 3031 _, _, err = httpdtest.AddUser(getTestUser(), http.StatusCreated) 3032 assert.Error(t, err, "adding a duplicate user must fail") 3033 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3034 assert.NoError(t, err) 3035} 3036 3037func TestGetUsers(t *testing.T) { 3038 user1, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 3039 assert.NoError(t, err) 3040 u := getTestUser() 3041 u.Username = defaultUsername + "1" 3042 user2, _, err := httpdtest.AddUser(u, http.StatusCreated) 3043 assert.NoError(t, err) 3044 users, _, err := httpdtest.GetUsers(0, 0, http.StatusOK) 3045 assert.NoError(t, err) 3046 assert.GreaterOrEqual(t, len(users), 2) 3047 users, _, err = httpdtest.GetUsers(1, 0, http.StatusOK) 3048 assert.NoError(t, err) 3049 assert.Equal(t, 1, len(users)) 3050 users, _, err = httpdtest.GetUsers(1, 1, http.StatusOK) 3051 assert.NoError(t, err) 3052 assert.Equal(t, 1, len(users)) 3053 _, _, err = httpdtest.GetUsers(1, 1, http.StatusInternalServerError) 3054 assert.Error(t, err) 3055 _, err = httpdtest.RemoveUser(user1, http.StatusOK) 3056 assert.NoError(t, err) 3057 _, err = httpdtest.RemoveUser(user2, http.StatusOK) 3058 assert.NoError(t, err) 3059} 3060 3061func TestGetQuotaScans(t *testing.T) { 3062 _, _, err := httpdtest.GetQuotaScans(http.StatusOK) 3063 assert.NoError(t, err) 3064 _, _, err = httpdtest.GetQuotaScans(http.StatusInternalServerError) 3065 assert.Error(t, err) 3066 _, _, err = httpdtest.GetFoldersQuotaScans(http.StatusOK) 3067 assert.NoError(t, err) 3068 _, _, err = httpdtest.GetFoldersQuotaScans(http.StatusInternalServerError) 3069 assert.Error(t, err) 3070} 3071 3072func TestStartQuotaScan(t *testing.T) { 3073 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 3074 assert.NoError(t, err) 3075 _, err = httpdtest.StartQuotaScan(user, http.StatusAccepted) 3076 assert.NoError(t, err) 3077 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3078 assert.NoError(t, err) 3079 folder := vfs.BaseVirtualFolder{ 3080 Name: "vfolder", 3081 MappedPath: filepath.Join(os.TempDir(), "folder"), 3082 Description: "virtual folder", 3083 } 3084 _, _, err = httpdtest.AddFolder(folder, http.StatusCreated) 3085 assert.NoError(t, err) 3086 _, err = httpdtest.StartFolderQuotaScan(folder, http.StatusAccepted) 3087 assert.NoError(t, err) 3088 for { 3089 quotaScan, _, err := httpdtest.GetFoldersQuotaScans(http.StatusOK) 3090 if !assert.NoError(t, err, "Error getting active scans") { 3091 break 3092 } 3093 if len(quotaScan) == 0 { 3094 break 3095 } 3096 time.Sleep(100 * time.Millisecond) 3097 } 3098 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 3099 assert.NoError(t, err) 3100} 3101 3102func TestEmbeddedFolders(t *testing.T) { 3103 u := getTestUser() 3104 mappedPath := filepath.Join(os.TempDir(), "mapped_path") 3105 name := filepath.Base(mappedPath) 3106 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 3107 BaseVirtualFolder: vfs.BaseVirtualFolder{ 3108 Name: name, 3109 UsedQuotaFiles: 1000, 3110 UsedQuotaSize: 8192, 3111 LastQuotaUpdate: 123, 3112 }, 3113 VirtualPath: "/vdir", 3114 QuotaSize: 4096, 3115 QuotaFiles: 1, 3116 }) 3117 _, _, err := httpdtest.AddUser(u, http.StatusBadRequest) 3118 assert.NoError(t, err) 3119 u.VirtualFolders[0].MappedPath = mappedPath 3120 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 3121 assert.NoError(t, err) 3122 // check that the folder was created 3123 folder, _, err := httpdtest.GetFolderByName(name, http.StatusOK) 3124 assert.NoError(t, err) 3125 assert.Equal(t, mappedPath, folder.MappedPath) 3126 assert.Equal(t, 0, folder.UsedQuotaFiles) 3127 assert.Equal(t, int64(0), folder.UsedQuotaSize) 3128 assert.Equal(t, int64(0), folder.LastQuotaUpdate) 3129 if assert.Len(t, user.VirtualFolders, 1) { 3130 assert.Equal(t, mappedPath, user.VirtualFolders[0].MappedPath) 3131 assert.Equal(t, u.VirtualFolders[0].VirtualPath, user.VirtualFolders[0].VirtualPath) 3132 assert.Equal(t, u.VirtualFolders[0].QuotaFiles, user.VirtualFolders[0].QuotaFiles) 3133 assert.Equal(t, u.VirtualFolders[0].QuotaSize, user.VirtualFolders[0].QuotaSize) 3134 } 3135 // if the folder already exists we can just reference it by name while adding/updating a user 3136 u.Username = u.Username + "1" 3137 u.VirtualFolders[0].MappedPath = "" 3138 user1, _, err := httpdtest.AddUser(u, http.StatusCreated) 3139 assert.EqualError(t, err, "mapped path mismatch") 3140 if assert.Len(t, user1.VirtualFolders, 1) { 3141 assert.Equal(t, mappedPath, user1.VirtualFolders[0].MappedPath) 3142 assert.Equal(t, u.VirtualFolders[0].VirtualPath, user1.VirtualFolders[0].VirtualPath) 3143 assert.Equal(t, u.VirtualFolders[0].QuotaFiles, user1.VirtualFolders[0].QuotaFiles) 3144 assert.Equal(t, u.VirtualFolders[0].QuotaSize, user1.VirtualFolders[0].QuotaSize) 3145 } 3146 user1.VirtualFolders = u.VirtualFolders 3147 user1, _, err = httpdtest.UpdateUser(user1, http.StatusOK, "") 3148 assert.EqualError(t, err, "mapped path mismatch") 3149 if assert.Len(t, user1.VirtualFolders, 1) { 3150 assert.Equal(t, mappedPath, user1.VirtualFolders[0].MappedPath) 3151 assert.Equal(t, u.VirtualFolders[0].VirtualPath, user1.VirtualFolders[0].VirtualPath) 3152 assert.Equal(t, u.VirtualFolders[0].QuotaFiles, user1.VirtualFolders[0].QuotaFiles) 3153 assert.Equal(t, u.VirtualFolders[0].QuotaSize, user1.VirtualFolders[0].QuotaSize) 3154 } 3155 // now the virtual folder contains all the required paths 3156 user1, _, err = httpdtest.UpdateUser(user1, http.StatusOK, "") 3157 assert.NoError(t, err) 3158 if assert.Len(t, user1.VirtualFolders, 1) { 3159 assert.Equal(t, mappedPath, user1.VirtualFolders[0].MappedPath) 3160 assert.Equal(t, u.VirtualFolders[0].VirtualPath, user1.VirtualFolders[0].VirtualPath) 3161 assert.Equal(t, u.VirtualFolders[0].QuotaFiles, user1.VirtualFolders[0].QuotaFiles) 3162 assert.Equal(t, u.VirtualFolders[0].QuotaSize, user1.VirtualFolders[0].QuotaSize) 3163 } 3164 3165 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3166 assert.NoError(t, err) 3167 _, err = httpdtest.RemoveUser(user1, http.StatusOK) 3168 assert.NoError(t, err) 3169 3170 _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: name}, http.StatusOK) 3171 assert.NoError(t, err) 3172} 3173 3174func TestEmbeddedFoldersUpdate(t *testing.T) { 3175 u := getTestUser() 3176 mappedPath := filepath.Join(os.TempDir(), "mapped_path") 3177 name := filepath.Base(mappedPath) 3178 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 3179 BaseVirtualFolder: vfs.BaseVirtualFolder{ 3180 Name: name, 3181 MappedPath: mappedPath, 3182 UsedQuotaFiles: 1000, 3183 UsedQuotaSize: 8192, 3184 LastQuotaUpdate: 123, 3185 }, 3186 VirtualPath: "/vdir", 3187 QuotaSize: 4096, 3188 QuotaFiles: 1, 3189 }) 3190 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 3191 assert.NoError(t, err) 3192 folder, _, err := httpdtest.GetFolderByName(name, http.StatusOK) 3193 assert.NoError(t, err) 3194 assert.Equal(t, mappedPath, folder.MappedPath) 3195 assert.Equal(t, 0, folder.UsedQuotaFiles) 3196 assert.Equal(t, int64(0), folder.UsedQuotaSize) 3197 assert.Equal(t, int64(0), folder.LastQuotaUpdate) 3198 assert.Empty(t, folder.Description) 3199 assert.Equal(t, sdk.LocalFilesystemProvider, folder.FsConfig.Provider) 3200 assert.Len(t, folder.Users, 1) 3201 assert.Contains(t, folder.Users, user.Username) 3202 // update a field on the folder 3203 description := "updatedDesc" 3204 folder.MappedPath = mappedPath + "_update" 3205 folder.Description = description 3206 folder, _, err = httpdtest.UpdateFolder(folder, http.StatusOK) 3207 assert.NoError(t, err) 3208 assert.Equal(t, mappedPath+"_update", folder.MappedPath) 3209 assert.Equal(t, 0, folder.UsedQuotaFiles) 3210 assert.Equal(t, int64(0), folder.UsedQuotaSize) 3211 assert.Equal(t, int64(0), folder.LastQuotaUpdate) 3212 assert.Equal(t, description, folder.Description) 3213 assert.Equal(t, sdk.LocalFilesystemProvider, folder.FsConfig.Provider) 3214 // check that the user gets the changes 3215 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 3216 assert.NoError(t, err) 3217 userFolder := user.VirtualFolders[0].BaseVirtualFolder 3218 assert.Equal(t, mappedPath+"_update", folder.MappedPath) 3219 assert.Equal(t, 0, userFolder.UsedQuotaFiles) 3220 assert.Equal(t, int64(0), userFolder.UsedQuotaSize) 3221 assert.Equal(t, int64(0), userFolder.LastQuotaUpdate) 3222 assert.Equal(t, description, userFolder.Description) 3223 assert.Equal(t, sdk.LocalFilesystemProvider, userFolder.FsConfig.Provider) 3224 // now update the folder embedding it inside the user 3225 user.VirtualFolders = []vfs.VirtualFolder{ 3226 { 3227 BaseVirtualFolder: vfs.BaseVirtualFolder{ 3228 Name: name, 3229 MappedPath: "", 3230 UsedQuotaFiles: 1000, 3231 UsedQuotaSize: 8192, 3232 LastQuotaUpdate: 123, 3233 FsConfig: vfs.Filesystem{ 3234 Provider: sdk.S3FilesystemProvider, 3235 S3Config: vfs.S3FsConfig{ 3236 S3FsConfig: sdk.S3FsConfig{ 3237 Bucket: "test", 3238 Region: "us-east-1", 3239 AccessKey: "akey", 3240 AccessSecret: kms.NewPlainSecret("asecret"), 3241 Endpoint: "http://127.0.1.1:9090", 3242 }, 3243 }, 3244 }, 3245 }, 3246 VirtualPath: "/vdir1", 3247 QuotaSize: 4096, 3248 QuotaFiles: 1, 3249 }, 3250 } 3251 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 3252 assert.NoError(t, err) 3253 userFolder = user.VirtualFolders[0].BaseVirtualFolder 3254 assert.Equal(t, 0, userFolder.UsedQuotaFiles) 3255 assert.Equal(t, int64(0), userFolder.UsedQuotaSize) 3256 assert.Equal(t, int64(0), userFolder.LastQuotaUpdate) 3257 assert.Empty(t, userFolder.Description) 3258 assert.Equal(t, sdk.S3FilesystemProvider, userFolder.FsConfig.Provider) 3259 assert.Equal(t, "test", userFolder.FsConfig.S3Config.Bucket) 3260 assert.Equal(t, "us-east-1", userFolder.FsConfig.S3Config.Region) 3261 assert.Equal(t, "http://127.0.1.1:9090", userFolder.FsConfig.S3Config.Endpoint) 3262 assert.Equal(t, kms.SecretStatusSecretBox, userFolder.FsConfig.S3Config.AccessSecret.GetStatus()) 3263 assert.NotEmpty(t, userFolder.FsConfig.S3Config.AccessSecret.GetPayload()) 3264 assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetKey()) 3265 assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 3266 // confirm the changes 3267 folder, _, err = httpdtest.GetFolderByName(name, http.StatusOK) 3268 assert.NoError(t, err) 3269 assert.Equal(t, 0, folder.UsedQuotaFiles) 3270 assert.Equal(t, int64(0), folder.UsedQuotaSize) 3271 assert.Equal(t, int64(0), folder.LastQuotaUpdate) 3272 assert.Empty(t, folder.Description) 3273 assert.Equal(t, sdk.S3FilesystemProvider, folder.FsConfig.Provider) 3274 assert.Equal(t, "test", folder.FsConfig.S3Config.Bucket) 3275 assert.Equal(t, "us-east-1", folder.FsConfig.S3Config.Region) 3276 assert.Equal(t, "http://127.0.1.1:9090", folder.FsConfig.S3Config.Endpoint) 3277 assert.Equal(t, kms.SecretStatusSecretBox, folder.FsConfig.S3Config.AccessSecret.GetStatus()) 3278 assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload()) 3279 assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetKey()) 3280 assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 3281 // now update folder usage limits and check that a folder update will not change them 3282 folder.UsedQuotaFiles = 100 3283 folder.UsedQuotaSize = 32768 3284 _, err = httpdtest.UpdateFolderQuotaUsage(folder, "reset", http.StatusOK) 3285 assert.NoError(t, err) 3286 folder, _, err = httpdtest.GetFolderByName(name, http.StatusOK) 3287 assert.NoError(t, err) 3288 assert.Equal(t, 100, folder.UsedQuotaFiles) 3289 assert.Equal(t, int64(32768), folder.UsedQuotaSize) 3290 assert.Greater(t, folder.LastQuotaUpdate, int64(0)) 3291 assert.Equal(t, sdk.S3FilesystemProvider, folder.FsConfig.Provider) 3292 assert.Equal(t, "test", folder.FsConfig.S3Config.Bucket) 3293 assert.Equal(t, "us-east-1", folder.FsConfig.S3Config.Region) 3294 assert.Equal(t, "http://127.0.1.1:9090", folder.FsConfig.S3Config.Endpoint) 3295 assert.Equal(t, kms.SecretStatusSecretBox, folder.FsConfig.S3Config.AccessSecret.GetStatus()) 3296 assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload()) 3297 assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetKey()) 3298 assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 3299 3300 user.VirtualFolders[0].FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("updated secret") 3301 user, resp, err := httpdtest.UpdateUser(user, http.StatusOK, "") 3302 assert.NoError(t, err, string(resp)) 3303 userFolder = user.VirtualFolders[0].BaseVirtualFolder 3304 assert.Equal(t, 100, userFolder.UsedQuotaFiles) 3305 assert.Equal(t, int64(32768), userFolder.UsedQuotaSize) 3306 assert.Greater(t, userFolder.LastQuotaUpdate, int64(0)) 3307 assert.Empty(t, userFolder.Description) 3308 assert.Equal(t, sdk.S3FilesystemProvider, userFolder.FsConfig.Provider) 3309 assert.Equal(t, "test", userFolder.FsConfig.S3Config.Bucket) 3310 assert.Equal(t, "us-east-1", userFolder.FsConfig.S3Config.Region) 3311 assert.Equal(t, "http://127.0.1.1:9090", userFolder.FsConfig.S3Config.Endpoint) 3312 assert.Equal(t, kms.SecretStatusSecretBox, userFolder.FsConfig.S3Config.AccessSecret.GetStatus()) 3313 assert.NotEmpty(t, userFolder.FsConfig.S3Config.AccessSecret.GetPayload()) 3314 assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetKey()) 3315 assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 3316 3317 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3318 assert.NoError(t, err) 3319 _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: name}, http.StatusOK) 3320 assert.NoError(t, err) 3321} 3322 3323func TestUpdateFolderQuotaUsage(t *testing.T) { 3324 f := vfs.BaseVirtualFolder{ 3325 Name: "vdir", 3326 MappedPath: filepath.Join(os.TempDir(), "folder"), 3327 } 3328 usedQuotaFiles := 1 3329 usedQuotaSize := int64(65535) 3330 f.UsedQuotaFiles = usedQuotaFiles 3331 f.UsedQuotaSize = usedQuotaSize 3332 folder, _, err := httpdtest.AddFolder(f, http.StatusCreated) 3333 if assert.NoError(t, err) { 3334 assert.Equal(t, usedQuotaFiles, folder.UsedQuotaFiles) 3335 assert.Equal(t, usedQuotaSize, folder.UsedQuotaSize) 3336 } 3337 _, err = httpdtest.UpdateFolderQuotaUsage(folder, "invalid mode", http.StatusBadRequest) 3338 assert.NoError(t, err) 3339 _, err = httpdtest.UpdateFolderQuotaUsage(f, "reset", http.StatusOK) 3340 assert.NoError(t, err) 3341 folder, _, err = httpdtest.GetFolderByName(f.Name, http.StatusOK) 3342 assert.NoError(t, err) 3343 assert.Equal(t, usedQuotaFiles, folder.UsedQuotaFiles) 3344 assert.Equal(t, usedQuotaSize, folder.UsedQuotaSize) 3345 _, err = httpdtest.UpdateFolderQuotaUsage(f, "add", http.StatusOK) 3346 assert.NoError(t, err) 3347 folder, _, err = httpdtest.GetFolderByName(f.Name, http.StatusOK) 3348 assert.NoError(t, err) 3349 assert.Equal(t, 2*usedQuotaFiles, folder.UsedQuotaFiles) 3350 assert.Equal(t, 2*usedQuotaSize, folder.UsedQuotaSize) 3351 f.UsedQuotaSize = -1 3352 _, err = httpdtest.UpdateFolderQuotaUsage(f, "", http.StatusBadRequest) 3353 assert.NoError(t, err) 3354 f.UsedQuotaSize = usedQuotaSize 3355 f.Name = f.Name + "1" 3356 _, err = httpdtest.UpdateFolderQuotaUsage(f, "", http.StatusNotFound) 3357 assert.NoError(t, err) 3358 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 3359 assert.NoError(t, err) 3360} 3361 3362func TestGetVersion(t *testing.T) { 3363 _, _, err := httpdtest.GetVersion(http.StatusOK) 3364 assert.NoError(t, err) 3365 _, _, err = httpdtest.GetVersion(http.StatusInternalServerError) 3366 assert.Error(t, err, "get version request must succeed, we requested to check a wrong status code") 3367} 3368 3369func TestGetStatus(t *testing.T) { 3370 _, _, err := httpdtest.GetStatus(http.StatusOK) 3371 assert.NoError(t, err) 3372 _, _, err = httpdtest.GetStatus(http.StatusBadRequest) 3373 assert.Error(t, err, "get provider status request must succeed, we requested to check a wrong status code") 3374} 3375 3376func TestGetConnections(t *testing.T) { 3377 _, _, err := httpdtest.GetConnections(http.StatusOK) 3378 assert.NoError(t, err) 3379 _, _, err = httpdtest.GetConnections(http.StatusInternalServerError) 3380 assert.Error(t, err, "get sftp connections request must succeed, we requested to check a wrong status code") 3381} 3382 3383func TestCloseActiveConnection(t *testing.T) { 3384 _, err := httpdtest.CloseConnection("non_existent_id", http.StatusNotFound) 3385 assert.NoError(t, err) 3386 user := getTestUser() 3387 c := common.NewBaseConnection("connID", common.ProtocolSFTP, "", "", user) 3388 fakeConn := &fakeConnection{ 3389 BaseConnection: c, 3390 } 3391 common.Connections.Add(fakeConn) 3392 _, err = httpdtest.CloseConnection(c.GetID(), http.StatusOK) 3393 assert.NoError(t, err) 3394 assert.Len(t, common.Connections.GetStats(), 0) 3395} 3396 3397func TestCloseConnectionAfterUserUpdateDelete(t *testing.T) { 3398 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 3399 assert.NoError(t, err) 3400 c := common.NewBaseConnection("connID", common.ProtocolFTP, "", "", user) 3401 fakeConn := &fakeConnection{ 3402 BaseConnection: c, 3403 } 3404 common.Connections.Add(fakeConn) 3405 c1 := common.NewBaseConnection("connID1", common.ProtocolSFTP, "", "", user) 3406 fakeConn1 := &fakeConnection{ 3407 BaseConnection: c1, 3408 } 3409 common.Connections.Add(fakeConn1) 3410 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "0") 3411 assert.NoError(t, err) 3412 assert.Len(t, common.Connections.GetStats(), 2) 3413 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "1") 3414 assert.NoError(t, err) 3415 assert.Len(t, common.Connections.GetStats(), 0) 3416 3417 common.Connections.Add(fakeConn) 3418 common.Connections.Add(fakeConn1) 3419 assert.Len(t, common.Connections.GetStats(), 2) 3420 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3421 assert.NoError(t, err) 3422 assert.Len(t, common.Connections.GetStats(), 0) 3423} 3424 3425func TestSkipNaturalKeysValidation(t *testing.T) { 3426 smtpCfg := smtp.Config{ 3427 Host: "127.0.0.1", 3428 Port: 3525, 3429 TemplatesPath: "templates", 3430 } 3431 err := smtpCfg.Initialize("..") 3432 require.NoError(t, err) 3433 err = dataprovider.Close() 3434 assert.NoError(t, err) 3435 err = config.LoadConfig(configDir, "") 3436 assert.NoError(t, err) 3437 providerConf := config.GetProviderConf() 3438 providerConf.SkipNaturalKeysValidation = true 3439 err = dataprovider.Initialize(providerConf, configDir, true) 3440 assert.NoError(t, err) 3441 3442 u := getTestUser() 3443 u.Username = "user@user.me" 3444 u.Email = u.Username 3445 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 3446 assert.NoError(t, err) 3447 user.AdditionalInfo = "info" 3448 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 3449 assert.NoError(t, err) 3450 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 3451 assert.NoError(t, err) 3452 3453 a := getTestAdmin() 3454 a.Username = "admin@example.com" 3455 admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated) 3456 assert.NoError(t, err) 3457 admin.Email = admin.Username 3458 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 3459 assert.NoError(t, err) 3460 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 3461 assert.NoError(t, err) 3462 3463 f := vfs.BaseVirtualFolder{ 3464 Name: "文件夹", 3465 MappedPath: filepath.Clean(os.TempDir()), 3466 } 3467 folder, resp, err := httpdtest.AddFolder(f, http.StatusCreated) 3468 assert.NoError(t, err, string(resp)) 3469 folder.Description = folder.Name 3470 folder, resp, err = httpdtest.UpdateFolder(folder, http.StatusOK) 3471 assert.NoError(t, err, string(resp)) 3472 folder, resp, err = httpdtest.GetFolderByName(folder.Name, http.StatusOK) 3473 assert.NoError(t, err, string(resp)) 3474 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 3475 assert.NoError(t, err) 3476 3477 err = dataprovider.Close() 3478 assert.NoError(t, err) 3479 err = config.LoadConfig(configDir, "") 3480 assert.NoError(t, err) 3481 providerConf = config.GetProviderConf() 3482 providerConf.CredentialsPath = credentialsPath 3483 err = os.RemoveAll(credentialsPath) 3484 assert.NoError(t, err) 3485 err = dataprovider.Initialize(providerConf, configDir, true) 3486 assert.NoError(t, err) 3487 if config.GetProviderConf().Driver == dataprovider.MemoryDataProviderName { 3488 return 3489 } 3490 3491 csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath) 3492 assert.NoError(t, err) 3493 token, err := getJWTWebClientTokenFromTestServer(user.Username, defaultPassword) 3494 assert.NoError(t, err) 3495 form := make(url.Values) 3496 form.Set(csrfFormToken, csrfToken) 3497 req, err := http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 3498 assert.NoError(t, err) 3499 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3500 setJWTCookieForReq(req, token) 3501 rr := executeRequest(req) 3502 checkResponseCode(t, http.StatusOK, rr) 3503 assert.Contains(t, rr.Body.String(), "the following characters are allowed") 3504 // test user reset password 3505 form = make(url.Values) 3506 form.Set("username", user.Username) 3507 form.Set(csrfFormToken, csrfToken) 3508 lastResetCode = "" 3509 req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 3510 assert.NoError(t, err) 3511 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3512 rr = executeRequest(req) 3513 assert.Equal(t, http.StatusFound, rr.Code) 3514 assert.GreaterOrEqual(t, len(lastResetCode), 20) 3515 form = make(url.Values) 3516 form.Set(csrfFormToken, csrfToken) 3517 form.Set("code", lastResetCode) 3518 form.Set("password", defaultPassword) 3519 req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 3520 assert.NoError(t, err) 3521 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3522 rr = executeRequest(req) 3523 assert.Equal(t, http.StatusOK, rr.Code) 3524 assert.Contains(t, rr.Body.String(), "Unable to set the new password") 3525 3526 adminAPIToken, err := getJWTAPITokenFromTestServer(admin.Username, defaultTokenAuthPass) 3527 assert.NoError(t, err) 3528 userAPIToken, err := getJWTAPIUserTokenFromTestServer(user.Username, defaultPassword) 3529 assert.NoError(t, err) 3530 req, err = http.NewRequest(http.MethodPut, userPath+"/"+user.Username+"/2fa/disable", nil) 3531 assert.NoError(t, err) 3532 setBearerForReq(req, adminAPIToken) 3533 rr = executeRequest(req) 3534 checkResponseCode(t, http.StatusBadRequest, rr) 3535 assert.Contains(t, rr.Body.String(), "the following characters are allowed") 3536 3537 req, err = http.NewRequest(http.MethodPost, user2FARecoveryCodesPath, nil) 3538 assert.NoError(t, err) 3539 setBearerForReq(req, userAPIToken) 3540 rr = executeRequest(req) 3541 checkResponseCode(t, http.StatusBadRequest, rr) 3542 assert.Contains(t, rr.Body.String(), "the following characters are allowed") 3543 3544 apiKeyAuthReq := make(map[string]bool) 3545 apiKeyAuthReq["allow_api_key_auth"] = true 3546 asJSON, err := json.Marshal(apiKeyAuthReq) 3547 assert.NoError(t, err) 3548 req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON)) 3549 assert.NoError(t, err) 3550 setBearerForReq(req, userAPIToken) 3551 rr = executeRequest(req) 3552 checkResponseCode(t, http.StatusBadRequest, rr) 3553 assert.Contains(t, rr.Body.String(), "the following characters are allowed") 3554 3555 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3556 assert.NoError(t, err) 3557 err = os.RemoveAll(user.GetHomeDir()) 3558 assert.NoError(t, err) 3559 3560 token, err = getJWTWebTokenFromTestServer(admin.Username, defaultTokenAuthPass) 3561 assert.NoError(t, err) 3562 csrfToken, err = getCSRFToken(httpBaseURL + webLoginPath) 3563 assert.NoError(t, err) 3564 form = make(url.Values) 3565 form.Set(csrfFormToken, csrfToken) 3566 req, _ = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 3567 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3568 setJWTCookieForReq(req, token) 3569 rr = executeRequest(req) 3570 checkResponseCode(t, http.StatusOK, rr) 3571 assert.Contains(t, rr.Body.String(), "the following characters are allowed") 3572 3573 apiKeyAuthReq = make(map[string]bool) 3574 apiKeyAuthReq["allow_api_key_auth"] = true 3575 asJSON, err = json.Marshal(apiKeyAuthReq) 3576 assert.NoError(t, err) 3577 req, err = http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer(asJSON)) 3578 assert.NoError(t, err) 3579 setBearerForReq(req, adminAPIToken) 3580 rr = executeRequest(req) 3581 checkResponseCode(t, http.StatusBadRequest, rr) 3582 assert.Contains(t, rr.Body.String(), "the following characters are allowed") 3583 3584 req, err = http.NewRequest(http.MethodPut, adminPath+"/"+admin.Username+"/2fa/disable", nil) 3585 assert.NoError(t, err) 3586 setBearerForReq(req, adminAPIToken) 3587 rr = executeRequest(req) 3588 checkResponseCode(t, http.StatusBadRequest, rr) 3589 assert.Contains(t, rr.Body.String(), "the following characters are allowed") 3590 3591 req, err = http.NewRequest(http.MethodPost, admin2FARecoveryCodesPath, nil) 3592 assert.NoError(t, err) 3593 setBearerForReq(req, adminAPIToken) 3594 rr = executeRequest(req) 3595 checkResponseCode(t, http.StatusBadRequest, rr) 3596 assert.Contains(t, rr.Body.String(), "the following characters are allowed") 3597 // test admin reset password 3598 form = make(url.Values) 3599 form.Set("username", admin.Username) 3600 form.Set(csrfFormToken, csrfToken) 3601 lastResetCode = "" 3602 req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 3603 assert.NoError(t, err) 3604 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3605 rr = executeRequest(req) 3606 assert.Equal(t, http.StatusFound, rr.Code) 3607 assert.GreaterOrEqual(t, len(lastResetCode), 20) 3608 form = make(url.Values) 3609 form.Set(csrfFormToken, csrfToken) 3610 form.Set("code", lastResetCode) 3611 form.Set("password", defaultPassword) 3612 req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 3613 assert.NoError(t, err) 3614 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3615 rr = executeRequest(req) 3616 assert.Equal(t, http.StatusOK, rr.Code) 3617 assert.Contains(t, rr.Body.String(), "Unable to set the new password") 3618 3619 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 3620 assert.NoError(t, err) 3621 3622 smtpCfg = smtp.Config{} 3623 err = smtpCfg.Initialize("..") 3624 require.NoError(t, err) 3625} 3626 3627func TestSaveErrors(t *testing.T) { 3628 err := dataprovider.Close() 3629 assert.NoError(t, err) 3630 err = config.LoadConfig(configDir, "") 3631 assert.NoError(t, err) 3632 providerConf := config.GetProviderConf() 3633 providerConf.SkipNaturalKeysValidation = true 3634 err = dataprovider.Initialize(providerConf, configDir, true) 3635 assert.NoError(t, err) 3636 3637 recCode := "recovery code" 3638 recoveryCodes := []sdk.RecoveryCode{ 3639 { 3640 Secret: kms.NewPlainSecret(recCode), 3641 Used: false, 3642 }, 3643 } 3644 3645 u := getTestUser() 3646 u.Username = "user@example.com" 3647 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 3648 assert.NoError(t, err) 3649 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 3650 assert.NoError(t, err) 3651 configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) 3652 assert.NoError(t, err) 3653 user.Password = u.Password 3654 user.Filters.TOTPConfig = sdk.TOTPConfig{ 3655 Enabled: true, 3656 ConfigName: configName, 3657 Secret: kms.NewPlainSecret(secret), 3658 Protocols: []string{common.ProtocolSSH, common.ProtocolHTTP}, 3659 } 3660 user.Filters.RecoveryCodes = recoveryCodes 3661 err = dataprovider.UpdateUser(&user, "", "") 3662 assert.NoError(t, err) 3663 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 3664 assert.NoError(t, err) 3665 assert.True(t, user.Filters.TOTPConfig.Enabled) 3666 assert.Len(t, user.Filters.RecoveryCodes, 1) 3667 3668 a := getTestAdmin() 3669 a.Username = "admin@example.com" 3670 admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated) 3671 assert.NoError(t, err) 3672 admin.Email = admin.Username 3673 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 3674 assert.NoError(t, err) 3675 admin.Password = a.Password 3676 admin.Filters.TOTPConfig = dataprovider.TOTPConfig{ 3677 Enabled: true, 3678 ConfigName: configName, 3679 Secret: kms.NewPlainSecret(secret), 3680 } 3681 admin.Filters.RecoveryCodes = recoveryCodes 3682 err = dataprovider.UpdateAdmin(&admin, "", "") 3683 assert.NoError(t, err) 3684 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 3685 assert.NoError(t, err) 3686 assert.True(t, admin.Filters.TOTPConfig.Enabled) 3687 assert.Len(t, admin.Filters.RecoveryCodes, 1) 3688 3689 err = dataprovider.Close() 3690 assert.NoError(t, err) 3691 err = config.LoadConfig(configDir, "") 3692 assert.NoError(t, err) 3693 providerConf = config.GetProviderConf() 3694 providerConf.CredentialsPath = credentialsPath 3695 err = os.RemoveAll(credentialsPath) 3696 assert.NoError(t, err) 3697 err = dataprovider.Initialize(providerConf, configDir, true) 3698 assert.NoError(t, err) 3699 if config.GetProviderConf().Driver == dataprovider.MemoryDataProviderName { 3700 return 3701 } 3702 3703 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 3704 assert.NoError(t, err) 3705 form := getLoginForm(a.Username, a.Password, csrfToken) 3706 req, err := http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 3707 assert.NoError(t, err) 3708 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3709 rr := executeRequest(req) 3710 assert.Equal(t, http.StatusFound, rr.Code) 3711 assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location")) 3712 cookie, err := getCookieFromResponse(rr) 3713 assert.NoError(t, err) 3714 3715 form = make(url.Values) 3716 form.Set("recovery_code", recCode) 3717 form.Set(csrfFormToken, csrfToken) 3718 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 3719 assert.NoError(t, err) 3720 setJWTCookieForReq(req, cookie) 3721 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3722 rr = executeRequest(req) 3723 assert.Equal(t, http.StatusInternalServerError, rr.Code) 3724 assert.Contains(t, rr.Body.String(), "unable to set the recovery code as used") 3725 3726 csrfToken, err = getCSRFToken(httpBaseURL + webClientLoginPath) 3727 assert.NoError(t, err) 3728 form = getLoginForm(u.Username, u.Password, csrfToken) 3729 req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 3730 assert.NoError(t, err) 3731 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3732 rr = executeRequest(req) 3733 assert.Equal(t, http.StatusFound, rr.Code) 3734 assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location")) 3735 cookie, err = getCookieFromResponse(rr) 3736 assert.NoError(t, err) 3737 3738 form = make(url.Values) 3739 form.Set("recovery_code", recCode) 3740 form.Set(csrfFormToken, csrfToken) 3741 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 3742 assert.NoError(t, err) 3743 setJWTCookieForReq(req, cookie) 3744 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3745 rr = executeRequest(req) 3746 assert.Equal(t, http.StatusInternalServerError, rr.Code) 3747 assert.Contains(t, rr.Body.String(), "unable to set the recovery code as used") 3748 3749 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3750 assert.NoError(t, err) 3751 err = os.RemoveAll(user.GetHomeDir()) 3752 assert.NoError(t, err) 3753 3754 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 3755 assert.NoError(t, err) 3756} 3757 3758func TestUserBaseDir(t *testing.T) { 3759 err := dataprovider.Close() 3760 assert.NoError(t, err) 3761 err = config.LoadConfig(configDir, "") 3762 assert.NoError(t, err) 3763 providerConf := config.GetProviderConf() 3764 providerConf.UsersBaseDir = homeBasePath 3765 err = dataprovider.Initialize(providerConf, configDir, true) 3766 assert.NoError(t, err) 3767 u := getTestUser() 3768 u.HomeDir = "" 3769 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 3770 if assert.Error(t, err) { 3771 assert.EqualError(t, err, "home dir mismatch") 3772 } 3773 assert.Equal(t, filepath.Join(providerConf.UsersBaseDir, u.Username), user.HomeDir) 3774 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3775 assert.NoError(t, err) 3776 err = dataprovider.Close() 3777 assert.NoError(t, err) 3778 err = config.LoadConfig(configDir, "") 3779 assert.NoError(t, err) 3780 providerConf = config.GetProviderConf() 3781 providerConf.CredentialsPath = credentialsPath 3782 err = os.RemoveAll(credentialsPath) 3783 assert.NoError(t, err) 3784 err = dataprovider.Initialize(providerConf, configDir, true) 3785 assert.NoError(t, err) 3786} 3787 3788func TestQuotaTrackingDisabled(t *testing.T) { 3789 err := dataprovider.Close() 3790 assert.NoError(t, err) 3791 err = config.LoadConfig(configDir, "") 3792 assert.NoError(t, err) 3793 providerConf := config.GetProviderConf() 3794 providerConf.TrackQuota = 0 3795 err = dataprovider.Initialize(providerConf, configDir, true) 3796 assert.NoError(t, err) 3797 // user quota scan must fail 3798 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 3799 assert.NoError(t, err) 3800 _, err = httpdtest.StartQuotaScan(user, http.StatusForbidden) 3801 assert.NoError(t, err) 3802 _, err = httpdtest.UpdateQuotaUsage(user, "", http.StatusForbidden) 3803 assert.NoError(t, err) 3804 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3805 assert.NoError(t, err) 3806 // folder quota scan must fail 3807 folder := vfs.BaseVirtualFolder{ 3808 Name: "folder_quota_test", 3809 MappedPath: filepath.Clean(os.TempDir()), 3810 } 3811 folder, resp, err := httpdtest.AddFolder(folder, http.StatusCreated) 3812 assert.NoError(t, err, string(resp)) 3813 _, err = httpdtest.StartFolderQuotaScan(folder, http.StatusForbidden) 3814 assert.NoError(t, err) 3815 _, err = httpdtest.UpdateFolderQuotaUsage(folder, "", http.StatusForbidden) 3816 assert.NoError(t, err) 3817 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 3818 assert.NoError(t, err) 3819 3820 err = dataprovider.Close() 3821 assert.NoError(t, err) 3822 err = config.LoadConfig(configDir, "") 3823 assert.NoError(t, err) 3824 providerConf = config.GetProviderConf() 3825 providerConf.CredentialsPath = credentialsPath 3826 err = os.RemoveAll(credentialsPath) 3827 assert.NoError(t, err) 3828 err = dataprovider.Initialize(providerConf, configDir, true) 3829 assert.NoError(t, err) 3830} 3831 3832func TestProviderErrors(t *testing.T) { 3833 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 3834 assert.NoError(t, err) 3835 userAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 3836 assert.NoError(t, err) 3837 userWebToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 3838 assert.NoError(t, err) 3839 _, err = httpdtest.RemoveUser(user, http.StatusOK) 3840 assert.NoError(t, err) 3841 token, _, err := httpdtest.GetToken(defaultTokenAuthUser, defaultTokenAuthPass) 3842 assert.NoError(t, err) 3843 testServerToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 3844 assert.NoError(t, err) 3845 httpdtest.SetJWTToken(token) 3846 err = dataprovider.Close() 3847 assert.NoError(t, err) 3848 _, _, err = httpdtest.GetUserByUsername("na", http.StatusInternalServerError) 3849 assert.NoError(t, err) 3850 _, _, err = httpdtest.GetUsers(1, 0, http.StatusInternalServerError) 3851 assert.NoError(t, err) 3852 _, _, err = httpdtest.GetAdmins(1, 0, http.StatusInternalServerError) 3853 assert.NoError(t, err) 3854 _, _, err = httpdtest.GetAPIKeys(1, 0, http.StatusInternalServerError) 3855 assert.NoError(t, err) 3856 req, err := http.NewRequest(http.MethodGet, userSharesPath, nil) 3857 assert.NoError(t, err) 3858 setBearerForReq(req, userAPIToken) 3859 rr := executeRequest(req) 3860 checkResponseCode(t, http.StatusInternalServerError, rr) 3861 3862 // password reset errors 3863 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 3864 assert.NoError(t, err) 3865 form := make(url.Values) 3866 form.Set("username", "username") 3867 form.Set(csrfFormToken, csrfToken) 3868 req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 3869 assert.NoError(t, err) 3870 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 3871 rr = executeRequest(req) 3872 assert.Equal(t, http.StatusOK, rr.Code) 3873 assert.Contains(t, rr.Body.String(), "Error retrieving your account, please try again later") 3874 3875 req, err = http.NewRequest(http.MethodGet, webClientSharesPath, nil) 3876 assert.NoError(t, err) 3877 setJWTCookieForReq(req, userWebToken) 3878 rr = executeRequest(req) 3879 checkResponseCode(t, http.StatusInternalServerError, rr) 3880 3881 req, err = http.NewRequest(http.MethodGet, webClientSharePath+"/shareID", nil) 3882 assert.NoError(t, err) 3883 setJWTCookieForReq(req, userWebToken) 3884 rr = executeRequest(req) 3885 checkResponseCode(t, http.StatusInternalServerError, rr) 3886 3887 req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/shareID", nil) 3888 assert.NoError(t, err) 3889 setJWTCookieForReq(req, userWebToken) 3890 rr = executeRequest(req) 3891 checkResponseCode(t, http.StatusInternalServerError, rr) 3892 3893 _, _, err = httpdtest.UpdateUser(dataprovider.User{BaseUser: sdk.BaseUser{Username: "auser"}}, http.StatusInternalServerError, "") 3894 assert.NoError(t, err) 3895 _, err = httpdtest.RemoveUser(dataprovider.User{BaseUser: sdk.BaseUser{Username: "auser"}}, http.StatusInternalServerError) 3896 assert.NoError(t, err) 3897 _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: "aname"}, http.StatusInternalServerError) 3898 assert.NoError(t, err) 3899 status, _, err := httpdtest.GetStatus(http.StatusOK) 3900 if assert.NoError(t, err) { 3901 assert.False(t, status.DataProvider.IsActive) 3902 } 3903 _, _, err = httpdtest.Dumpdata("backup.json", "", "", http.StatusInternalServerError) 3904 assert.NoError(t, err) 3905 _, _, err = httpdtest.GetFolders(0, 0, http.StatusInternalServerError) 3906 assert.NoError(t, err) 3907 user = getTestUser() 3908 user.ID = 1 3909 backupData := dataprovider.BackupData{} 3910 backupData.Users = append(backupData.Users, user) 3911 backupContent, err := json.Marshal(backupData) 3912 assert.NoError(t, err) 3913 backupFilePath := filepath.Join(backupsPath, "backup.json") 3914 err = os.WriteFile(backupFilePath, backupContent, os.ModePerm) 3915 assert.NoError(t, err) 3916 _, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError) 3917 assert.NoError(t, err) 3918 backupData.Folders = append(backupData.Folders, vfs.BaseVirtualFolder{Name: "testFolder", MappedPath: filepath.Clean(os.TempDir())}) 3919 backupContent, err = json.Marshal(backupData) 3920 assert.NoError(t, err) 3921 err = os.WriteFile(backupFilePath, backupContent, os.ModePerm) 3922 assert.NoError(t, err) 3923 _, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError) 3924 assert.NoError(t, err) 3925 backupData.Users = nil 3926 backupData.Folders = nil 3927 backupData.Admins = append(backupData.Admins, getTestAdmin()) 3928 backupContent, err = json.Marshal(backupData) 3929 assert.NoError(t, err) 3930 err = os.WriteFile(backupFilePath, backupContent, os.ModePerm) 3931 assert.NoError(t, err) 3932 _, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError) 3933 assert.NoError(t, err) 3934 backupData.Users = nil 3935 backupData.Folders = nil 3936 backupData.Admins = nil 3937 backupData.APIKeys = append(backupData.APIKeys, dataprovider.APIKey{ 3938 Name: "name", 3939 KeyID: util.GenerateUniqueID(), 3940 Key: fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()), 3941 Scope: dataprovider.APIKeyScopeUser, 3942 }) 3943 backupContent, err = json.Marshal(backupData) 3944 assert.NoError(t, err) 3945 err = os.WriteFile(backupFilePath, backupContent, os.ModePerm) 3946 assert.NoError(t, err) 3947 _, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError) 3948 assert.NoError(t, err) 3949 backupData.APIKeys = nil 3950 backupData.Shares = append(backupData.Shares, dataprovider.Share{ 3951 Name: util.GenerateUniqueID(), 3952 ShareID: util.GenerateUniqueID(), 3953 Scope: dataprovider.ShareScopeRead, 3954 Paths: []string{"/"}, 3955 Username: defaultUsername, 3956 }) 3957 backupContent, err = json.Marshal(backupData) 3958 assert.NoError(t, err) 3959 err = os.WriteFile(backupFilePath, backupContent, os.ModePerm) 3960 assert.NoError(t, err) 3961 _, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError) 3962 assert.NoError(t, err) 3963 err = os.Remove(backupFilePath) 3964 assert.NoError(t, err) 3965 req, err = http.NewRequest(http.MethodGet, webUserPath, nil) 3966 assert.NoError(t, err) 3967 setJWTCookieForReq(req, testServerToken) 3968 rr = executeRequest(req) 3969 checkResponseCode(t, http.StatusInternalServerError, rr) 3970 req, err = http.NewRequest(http.MethodGet, webUserPath+"?clone-from=user", nil) 3971 assert.NoError(t, err) 3972 setJWTCookieForReq(req, testServerToken) 3973 rr = executeRequest(req) 3974 checkResponseCode(t, http.StatusInternalServerError, rr) 3975 req, err = http.NewRequest(http.MethodGet, webTemplateUser+"?from=auser", nil) 3976 assert.NoError(t, err) 3977 setJWTCookieForReq(req, testServerToken) 3978 rr = executeRequest(req) 3979 checkResponseCode(t, http.StatusInternalServerError, rr) 3980 req, err = http.NewRequest(http.MethodGet, webTemplateFolder+"?from=afolder", nil) 3981 assert.NoError(t, err) 3982 setJWTCookieForReq(req, testServerToken) 3983 rr = executeRequest(req) 3984 checkResponseCode(t, http.StatusInternalServerError, rr) 3985 err = config.LoadConfig(configDir, "") 3986 assert.NoError(t, err) 3987 providerConf := config.GetProviderConf() 3988 providerConf.CredentialsPath = credentialsPath 3989 err = os.RemoveAll(credentialsPath) 3990 assert.NoError(t, err) 3991 err = dataprovider.Initialize(providerConf, configDir, true) 3992 assert.NoError(t, err) 3993 httpdtest.SetJWTToken("") 3994} 3995 3996func TestFolders(t *testing.T) { 3997 folder := vfs.BaseVirtualFolder{ 3998 Name: "name", 3999 MappedPath: "relative path", 4000 Users: []string{"1", "2", "3"}, 4001 FsConfig: vfs.Filesystem{ 4002 Provider: sdk.CryptedFilesystemProvider, 4003 CryptConfig: vfs.CryptFsConfig{ 4004 CryptFsConfig: sdk.CryptFsConfig{ 4005 Passphrase: kms.NewPlainSecret("asecret"), 4006 }, 4007 }, 4008 }, 4009 } 4010 _, _, err := httpdtest.AddFolder(folder, http.StatusBadRequest) 4011 assert.NoError(t, err) 4012 folder.MappedPath = filepath.Clean(os.TempDir()) 4013 folder1, resp, err := httpdtest.AddFolder(folder, http.StatusCreated) 4014 assert.NoError(t, err, string(resp)) 4015 assert.Equal(t, folder.Name, folder1.Name) 4016 assert.Equal(t, folder.MappedPath, folder1.MappedPath) 4017 assert.Equal(t, 0, folder1.UsedQuotaFiles) 4018 assert.Equal(t, int64(0), folder1.UsedQuotaSize) 4019 assert.Equal(t, int64(0), folder1.LastQuotaUpdate) 4020 assert.Equal(t, kms.SecretStatusSecretBox, folder1.FsConfig.CryptConfig.Passphrase.GetStatus()) 4021 assert.NotEmpty(t, folder1.FsConfig.CryptConfig.Passphrase.GetPayload()) 4022 assert.Empty(t, folder1.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 4023 assert.Empty(t, folder1.FsConfig.CryptConfig.Passphrase.GetKey()) 4024 assert.Len(t, folder1.Users, 0) 4025 // adding a duplicate folder must fail 4026 _, _, err = httpdtest.AddFolder(folder, http.StatusCreated) 4027 assert.Error(t, err) 4028 folder.MappedPath = filepath.Join(os.TempDir(), "vfolder") 4029 folder.Name = filepath.Base(folder.MappedPath) 4030 folder.UsedQuotaFiles = 1 4031 folder.UsedQuotaSize = 345 4032 folder.LastQuotaUpdate = 10 4033 folder2, _, err := httpdtest.AddFolder(folder, http.StatusCreated) 4034 assert.NoError(t, err, string(resp)) 4035 assert.Equal(t, 1, folder2.UsedQuotaFiles) 4036 assert.Equal(t, int64(345), folder2.UsedQuotaSize) 4037 assert.Equal(t, int64(10), folder2.LastQuotaUpdate) 4038 assert.Len(t, folder2.Users, 0) 4039 folders, _, err := httpdtest.GetFolders(0, 0, http.StatusOK) 4040 assert.NoError(t, err) 4041 numResults := len(folders) 4042 assert.GreaterOrEqual(t, numResults, 2) 4043 found := false 4044 for _, f := range folders { 4045 if f.Name == folder1.Name { 4046 found = true 4047 assert.Equal(t, folder1.MappedPath, f.MappedPath) 4048 assert.Equal(t, kms.SecretStatusSecretBox, f.FsConfig.CryptConfig.Passphrase.GetStatus()) 4049 assert.NotEmpty(t, f.FsConfig.CryptConfig.Passphrase.GetPayload()) 4050 assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 4051 assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetKey()) 4052 assert.Len(t, f.Users, 0) 4053 } 4054 } 4055 assert.True(t, found) 4056 folders, _, err = httpdtest.GetFolders(0, 1, http.StatusOK) 4057 assert.NoError(t, err) 4058 assert.Len(t, folders, numResults-1) 4059 folders, _, err = httpdtest.GetFolders(1, 0, http.StatusOK) 4060 assert.NoError(t, err) 4061 assert.Len(t, folders, 1) 4062 f, _, err := httpdtest.GetFolderByName(folder1.Name, http.StatusOK) 4063 assert.NoError(t, err) 4064 assert.Equal(t, folder1.Name, f.Name) 4065 assert.Equal(t, folder1.MappedPath, f.MappedPath) 4066 assert.Equal(t, kms.SecretStatusSecretBox, f.FsConfig.CryptConfig.Passphrase.GetStatus()) 4067 assert.NotEmpty(t, f.FsConfig.CryptConfig.Passphrase.GetPayload()) 4068 assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 4069 assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetKey()) 4070 assert.Len(t, f.Users, 0) 4071 f, _, err = httpdtest.GetFolderByName(folder2.Name, http.StatusOK) 4072 assert.NoError(t, err) 4073 assert.Equal(t, folder2.Name, f.Name) 4074 assert.Equal(t, folder2.MappedPath, f.MappedPath) 4075 _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{ 4076 Name: "invalid", 4077 }, http.StatusNotFound) 4078 assert.NoError(t, err) 4079 _, _, err = httpdtest.UpdateFolder(vfs.BaseVirtualFolder{Name: "notfound"}, http.StatusNotFound) 4080 assert.NoError(t, err) 4081 folder1.MappedPath = "a/relative/path" 4082 _, _, err = httpdtest.UpdateFolder(folder1, http.StatusBadRequest) 4083 assert.NoError(t, err) 4084 folder1.MappedPath = filepath.Join(os.TempDir(), "updated") 4085 folder1.Description = "updated folder description" 4086 f, resp, err = httpdtest.UpdateFolder(folder1, http.StatusOK) 4087 assert.NoError(t, err, string(resp)) 4088 assert.Equal(t, folder1.MappedPath, f.MappedPath) 4089 assert.Equal(t, folder1.Description, f.Description) 4090 4091 _, err = httpdtest.RemoveFolder(folder1, http.StatusOK) 4092 assert.NoError(t, err) 4093 _, err = httpdtest.RemoveFolder(folder2, http.StatusOK) 4094 assert.NoError(t, err) 4095} 4096 4097func TestDumpdata(t *testing.T) { 4098 err := dataprovider.Close() 4099 assert.NoError(t, err) 4100 err = config.LoadConfig(configDir, "") 4101 assert.NoError(t, err) 4102 providerConf := config.GetProviderConf() 4103 err = dataprovider.Initialize(providerConf, configDir, true) 4104 assert.NoError(t, err) 4105 _, rawResp, err := httpdtest.Dumpdata("", "", "", http.StatusBadRequest) 4106 assert.NoError(t, err, string(rawResp)) 4107 _, _, err = httpdtest.Dumpdata(filepath.Join(backupsPath, "backup.json"), "", "", http.StatusBadRequest) 4108 assert.NoError(t, err) 4109 _, rawResp, err = httpdtest.Dumpdata("../backup.json", "", "", http.StatusBadRequest) 4110 assert.NoError(t, err, string(rawResp)) 4111 _, rawResp, err = httpdtest.Dumpdata("backup.json", "", "0", http.StatusOK) 4112 assert.NoError(t, err, string(rawResp)) 4113 response, _, err := httpdtest.Dumpdata("", "1", "0", http.StatusOK) 4114 assert.NoError(t, err) 4115 _, ok := response["admins"] 4116 assert.True(t, ok) 4117 _, ok = response["users"] 4118 assert.True(t, ok) 4119 _, ok = response["folders"] 4120 assert.True(t, ok) 4121 _, ok = response["api_keys"] 4122 assert.True(t, ok) 4123 _, ok = response["shares"] 4124 assert.True(t, ok) 4125 _, ok = response["version"] 4126 assert.True(t, ok) 4127 _, rawResp, err = httpdtest.Dumpdata("backup.json", "", "1", http.StatusOK) 4128 assert.NoError(t, err, string(rawResp)) 4129 err = os.Remove(filepath.Join(backupsPath, "backup.json")) 4130 assert.NoError(t, err) 4131 if runtime.GOOS != osWindows { 4132 err = os.Chmod(backupsPath, 0001) 4133 assert.NoError(t, err) 4134 _, _, err = httpdtest.Dumpdata("bck.json", "", "", http.StatusForbidden) 4135 assert.NoError(t, err) 4136 // subdir cannot be created 4137 _, _, err = httpdtest.Dumpdata(filepath.Join("subdir", "bck.json"), "", "", http.StatusForbidden) 4138 assert.NoError(t, err) 4139 err = os.Chmod(backupsPath, 0755) 4140 assert.NoError(t, err) 4141 } 4142 err = dataprovider.Close() 4143 assert.NoError(t, err) 4144 err = config.LoadConfig(configDir, "") 4145 assert.NoError(t, err) 4146 providerConf = config.GetProviderConf() 4147 providerConf.CredentialsPath = credentialsPath 4148 err = os.RemoveAll(credentialsPath) 4149 assert.NoError(t, err) 4150 err = dataprovider.Initialize(providerConf, configDir, true) 4151 assert.NoError(t, err) 4152} 4153 4154func TestDefenderAPI(t *testing.T) { 4155 oldConfig := config.GetCommonConfig() 4156 4157 cfg := config.GetCommonConfig() 4158 cfg.DefenderConfig.Enabled = true 4159 cfg.DefenderConfig.Threshold = 3 4160 cfg.DefenderConfig.ScoreLimitExceeded = 2 4161 4162 err := common.Initialize(cfg) 4163 require.NoError(t, err) 4164 4165 ip := "::1" 4166 4167 response, _, err := httpdtest.GetBanTime(ip, http.StatusOK) 4168 require.NoError(t, err) 4169 banTime, ok := response["date_time"] 4170 require.True(t, ok) 4171 assert.Nil(t, banTime) 4172 4173 hosts, _, err := httpdtest.GetDefenderHosts(http.StatusOK) 4174 require.NoError(t, err) 4175 assert.Len(t, hosts, 0) 4176 4177 response, _, err = httpdtest.GetScore(ip, http.StatusOK) 4178 require.NoError(t, err) 4179 score, ok := response["score"] 4180 require.True(t, ok) 4181 assert.Equal(t, float64(0), score) 4182 4183 err = httpdtest.UnbanIP(ip, http.StatusNotFound) 4184 require.NoError(t, err) 4185 4186 _, err = httpdtest.RemoveDefenderHostByIP(ip, http.StatusNotFound) 4187 require.NoError(t, err) 4188 4189 common.AddDefenderEvent(ip, common.HostEventNoLoginTried) 4190 response, _, err = httpdtest.GetScore(ip, http.StatusOK) 4191 require.NoError(t, err) 4192 score, ok = response["score"] 4193 require.True(t, ok) 4194 assert.Equal(t, float64(2), score) 4195 4196 hosts, _, err = httpdtest.GetDefenderHosts(http.StatusOK) 4197 require.NoError(t, err) 4198 if assert.Len(t, hosts, 1) { 4199 host := hosts[0] 4200 assert.Empty(t, host.GetBanTime()) 4201 assert.Equal(t, 2, host.Score) 4202 assert.Equal(t, ip, host.IP) 4203 } 4204 host, _, err := httpdtest.GetDefenderHostByIP(ip, http.StatusOK) 4205 assert.NoError(t, err) 4206 assert.Empty(t, host.GetBanTime()) 4207 assert.Equal(t, 2, host.Score) 4208 4209 common.AddDefenderEvent(ip, common.HostEventNoLoginTried) 4210 response, _, err = httpdtest.GetBanTime(ip, http.StatusOK) 4211 require.NoError(t, err) 4212 banTime, ok = response["date_time"] 4213 require.True(t, ok) 4214 assert.NotNil(t, banTime) 4215 hosts, _, err = httpdtest.GetDefenderHosts(http.StatusOK) 4216 require.NoError(t, err) 4217 if assert.Len(t, hosts, 1) { 4218 host := hosts[0] 4219 assert.NotEmpty(t, host.GetBanTime()) 4220 assert.Equal(t, 0, host.Score) 4221 assert.Equal(t, ip, host.IP) 4222 } 4223 host, _, err = httpdtest.GetDefenderHostByIP(ip, http.StatusOK) 4224 assert.NoError(t, err) 4225 assert.NotEmpty(t, host.GetBanTime()) 4226 assert.Equal(t, 0, host.Score) 4227 4228 err = httpdtest.UnbanIP(ip, http.StatusOK) 4229 require.NoError(t, err) 4230 4231 err = httpdtest.UnbanIP(ip, http.StatusNotFound) 4232 require.NoError(t, err) 4233 4234 host, _, err = httpdtest.GetDefenderHostByIP(ip, http.StatusNotFound) 4235 assert.NoError(t, err) 4236 4237 common.AddDefenderEvent(ip, common.HostEventNoLoginTried) 4238 common.AddDefenderEvent(ip, common.HostEventNoLoginTried) 4239 hosts, _, err = httpdtest.GetDefenderHosts(http.StatusOK) 4240 require.NoError(t, err) 4241 assert.Len(t, hosts, 1) 4242 4243 _, err = httpdtest.RemoveDefenderHostByIP(ip, http.StatusOK) 4244 assert.NoError(t, err) 4245 4246 host, _, err = httpdtest.GetDefenderHostByIP(ip, http.StatusNotFound) 4247 assert.NoError(t, err) 4248 _, err = httpdtest.RemoveDefenderHostByIP(ip, http.StatusNotFound) 4249 assert.NoError(t, err) 4250 4251 host, _, err = httpdtest.GetDefenderHostByIP("invalid_ip", http.StatusBadRequest) 4252 assert.NoError(t, err) 4253 _, err = httpdtest.RemoveDefenderHostByIP("invalid_ip", http.StatusBadRequest) 4254 assert.NoError(t, err) 4255 4256 err = common.Initialize(oldConfig) 4257 require.NoError(t, err) 4258} 4259 4260func TestDefenderAPIErrors(t *testing.T) { 4261 _, _, err := httpdtest.GetBanTime("", http.StatusBadRequest) 4262 require.NoError(t, err) 4263 4264 _, _, err = httpdtest.GetBanTime("invalid", http.StatusBadRequest) 4265 require.NoError(t, err) 4266 4267 _, _, err = httpdtest.GetScore("", http.StatusBadRequest) 4268 require.NoError(t, err) 4269 4270 err = httpdtest.UnbanIP("", http.StatusBadRequest) 4271 require.NoError(t, err) 4272} 4273 4274func TestRestoreShares(t *testing.T) { 4275 // shares should be restored preserving the UsedTokens, CreatedAt, LastUseAt, UpdatedAt, 4276 // and ExpiresAt, so an expired share can be restored while we cannot create an already 4277 // expired share 4278 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 4279 assert.NoError(t, err) 4280 share := dataprovider.Share{ 4281 ShareID: shortuuid.New(), 4282 Name: "share name", 4283 Description: "share description", 4284 Scope: dataprovider.ShareScopeRead, 4285 Paths: []string{"/"}, 4286 Username: user.Username, 4287 CreatedAt: util.GetTimeAsMsSinceEpoch(time.Now().Add(-144 * time.Hour)), 4288 UpdatedAt: util.GetTimeAsMsSinceEpoch(time.Now().Add(-96 * time.Hour)), 4289 LastUseAt: util.GetTimeAsMsSinceEpoch(time.Now().Add(-64 * time.Hour)), 4290 ExpiresAt: util.GetTimeAsMsSinceEpoch(time.Now().Add(-48 * time.Hour)), 4291 MaxTokens: 10, 4292 UsedTokens: 8, 4293 AllowFrom: []string{"127.0.0.0/8"}, 4294 } 4295 backupData := dataprovider.BackupData{} 4296 backupData.Shares = append(backupData.Shares, share) 4297 backupContent, err := json.Marshal(backupData) 4298 assert.NoError(t, err) 4299 _, _, err = httpdtest.LoaddataFromPostBody(backupContent, "0", "0", http.StatusOK) 4300 assert.NoError(t, err) 4301 shareGet, err := dataprovider.ShareExists(share.ShareID, user.Username) 4302 assert.NoError(t, err) 4303 assert.Equal(t, share, shareGet) 4304 4305 share.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-142 * time.Hour)) 4306 share.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-92 * time.Hour)) 4307 share.LastUseAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-62 * time.Hour)) 4308 share.UsedTokens = 6 4309 backupData.Shares = []dataprovider.Share{share} 4310 backupContent, err = json.Marshal(backupData) 4311 assert.NoError(t, err) 4312 _, _, err = httpdtest.LoaddataFromPostBody(backupContent, "0", "0", http.StatusOK) 4313 assert.NoError(t, err) 4314 shareGet, err = dataprovider.ShareExists(share.ShareID, user.Username) 4315 assert.NoError(t, err) 4316 assert.Equal(t, share, shareGet) 4317 4318 _, err = httpdtest.RemoveUser(user, http.StatusOK) 4319 assert.NoError(t, err) 4320} 4321 4322func TestLoaddataFromPostBody(t *testing.T) { 4323 mappedPath := filepath.Join(os.TempDir(), "restored_folder") 4324 folderName := filepath.Base(mappedPath) 4325 user := getTestUser() 4326 user.ID = 1 4327 user.Username = "test_user_restored" 4328 admin := getTestAdmin() 4329 admin.ID = 1 4330 admin.Username = "test_admin_restored" 4331 backupData := dataprovider.BackupData{} 4332 backupData.Users = append(backupData.Users, user) 4333 backupData.Admins = append(backupData.Admins, admin) 4334 backupData.Folders = []vfs.BaseVirtualFolder{ 4335 { 4336 Name: folderName, 4337 MappedPath: mappedPath, 4338 UsedQuotaSize: 123, 4339 UsedQuotaFiles: 456, 4340 LastQuotaUpdate: 789, 4341 Users: []string{"user"}, 4342 }, 4343 { 4344 Name: folderName, 4345 MappedPath: mappedPath + "1", 4346 }, 4347 } 4348 backupData.APIKeys = append(backupData.APIKeys, dataprovider.APIKey{}) 4349 backupData.Shares = append(backupData.Shares, dataprovider.Share{}) 4350 backupContent, err := json.Marshal(backupData) 4351 assert.NoError(t, err) 4352 _, _, err = httpdtest.LoaddataFromPostBody(nil, "0", "0", http.StatusBadRequest) 4353 assert.NoError(t, err) 4354 _, _, err = httpdtest.LoaddataFromPostBody(backupContent, "a", "0", http.StatusBadRequest) 4355 assert.NoError(t, err) 4356 _, _, err = httpdtest.LoaddataFromPostBody([]byte("invalid content"), "0", "0", http.StatusBadRequest) 4357 assert.NoError(t, err) 4358 _, _, err = httpdtest.LoaddataFromPostBody(backupContent, "0", "0", http.StatusInternalServerError) 4359 assert.NoError(t, err) 4360 4361 keyID := util.GenerateUniqueID() 4362 backupData.APIKeys = []dataprovider.APIKey{ 4363 { 4364 Name: "test key", 4365 Scope: dataprovider.APIKeyScopeAdmin, 4366 KeyID: keyID, 4367 Key: fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()), 4368 }, 4369 } 4370 backupData.Shares = []dataprovider.Share{ 4371 { 4372 ShareID: keyID, 4373 Name: keyID, 4374 Scope: dataprovider.ShareScopeWrite, 4375 Paths: []string{"/"}, 4376 Username: user.Username, 4377 }, 4378 } 4379 backupContent, err = json.Marshal(backupData) 4380 assert.NoError(t, err) 4381 _, _, err = httpdtest.LoaddataFromPostBody(backupContent, "0", "0", http.StatusOK) 4382 assert.NoError(t, err) 4383 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 4384 assert.NoError(t, err) 4385 _, err = dataprovider.ShareExists(keyID, user.Username) 4386 assert.NoError(t, err) 4387 _, err = httpdtest.RemoveUser(user, http.StatusOK) 4388 assert.NoError(t, err) 4389 4390 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 4391 assert.NoError(t, err) 4392 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 4393 assert.NoError(t, err) 4394 apiKey, _, err := httpdtest.GetAPIKeyByID(keyID, http.StatusOK) 4395 assert.NoError(t, err) 4396 _, err = httpdtest.RemoveAPIKey(apiKey, http.StatusOK) 4397 assert.NoError(t, err) 4398 4399 folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK) 4400 assert.NoError(t, err) 4401 assert.Equal(t, mappedPath+"1", folder.MappedPath) 4402 assert.Equal(t, int64(123), folder.UsedQuotaSize) 4403 assert.Equal(t, 456, folder.UsedQuotaFiles) 4404 assert.Equal(t, int64(789), folder.LastQuotaUpdate) 4405 assert.Len(t, folder.Users, 0) 4406 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 4407 assert.NoError(t, err) 4408} 4409 4410func TestLoaddata(t *testing.T) { 4411 mappedPath := filepath.Join(os.TempDir(), "restored_folder") 4412 folderName := filepath.Base(mappedPath) 4413 foldeDesc := "restored folder desc" 4414 user := getTestUser() 4415 user.ID = 1 4416 user.Username = "test_user_restore" 4417 admin := getTestAdmin() 4418 admin.ID = 1 4419 admin.Username = "test_admin_restore" 4420 apiKey := dataprovider.APIKey{ 4421 Name: util.GenerateUniqueID(), 4422 Scope: dataprovider.APIKeyScopeAdmin, 4423 KeyID: util.GenerateUniqueID(), 4424 Key: fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()), 4425 } 4426 share := dataprovider.Share{ 4427 ShareID: util.GenerateUniqueID(), 4428 Name: util.GenerateUniqueID(), 4429 Scope: dataprovider.ShareScopeRead, 4430 Paths: []string{"/"}, 4431 Username: user.Username, 4432 } 4433 backupData := dataprovider.BackupData{} 4434 backupData.Users = append(backupData.Users, user) 4435 backupData.Admins = append(backupData.Admins, admin) 4436 backupData.Folders = []vfs.BaseVirtualFolder{ 4437 { 4438 Name: folderName, 4439 MappedPath: mappedPath + "1", 4440 UsedQuotaSize: 123, 4441 UsedQuotaFiles: 456, 4442 LastQuotaUpdate: 789, 4443 Users: []string{"user"}, 4444 }, 4445 { 4446 MappedPath: mappedPath, 4447 Name: folderName, 4448 Description: foldeDesc, 4449 }, 4450 } 4451 backupData.APIKeys = append(backupData.APIKeys, apiKey) 4452 backupData.Shares = append(backupData.Shares, share) 4453 backupContent, err := json.Marshal(backupData) 4454 assert.NoError(t, err) 4455 backupFilePath := filepath.Join(backupsPath, "backup.json") 4456 err = os.WriteFile(backupFilePath, backupContent, os.ModePerm) 4457 assert.NoError(t, err) 4458 _, _, err = httpdtest.Loaddata(backupFilePath, "a", "", http.StatusBadRequest) 4459 assert.NoError(t, err) 4460 _, _, err = httpdtest.Loaddata(backupFilePath, "", "a", http.StatusBadRequest) 4461 assert.NoError(t, err) 4462 _, _, err = httpdtest.Loaddata("backup.json", "1", "", http.StatusBadRequest) 4463 assert.NoError(t, err) 4464 _, _, err = httpdtest.Loaddata(backupFilePath+"a", "1", "", http.StatusBadRequest) 4465 assert.NoError(t, err) 4466 if runtime.GOOS != osWindows { 4467 err = os.Chmod(backupFilePath, 0111) 4468 assert.NoError(t, err) 4469 _, _, err = httpdtest.Loaddata(backupFilePath, "1", "", http.StatusForbidden) 4470 assert.NoError(t, err) 4471 err = os.Chmod(backupFilePath, 0644) 4472 assert.NoError(t, err) 4473 } 4474 // add user, folder, admin, API key, share from backup 4475 _, _, err = httpdtest.Loaddata(backupFilePath, "1", "", http.StatusOK) 4476 assert.NoError(t, err) 4477 // update from backup 4478 _, _, err = httpdtest.Loaddata(backupFilePath, "2", "", http.StatusOK) 4479 assert.NoError(t, err) 4480 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 4481 assert.NoError(t, err) 4482 _, err = dataprovider.ShareExists(share.ShareID, user.Username) 4483 assert.NoError(t, err) 4484 _, err = httpdtest.RemoveUser(user, http.StatusOK) 4485 assert.NoError(t, err) 4486 4487 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 4488 assert.NoError(t, err) 4489 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 4490 assert.NoError(t, err) 4491 4492 apiKey, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusOK) 4493 assert.NoError(t, err) 4494 _, err = httpdtest.RemoveAPIKey(apiKey, http.StatusOK) 4495 assert.NoError(t, err) 4496 4497 folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK) 4498 assert.NoError(t, err) 4499 assert.Equal(t, mappedPath, folder.MappedPath) 4500 assert.Equal(t, int64(123), folder.UsedQuotaSize) 4501 assert.Equal(t, 456, folder.UsedQuotaFiles) 4502 assert.Equal(t, int64(789), folder.LastQuotaUpdate) 4503 assert.Equal(t, foldeDesc, folder.Description) 4504 assert.Len(t, folder.Users, 0) 4505 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 4506 assert.NoError(t, err) 4507 err = os.Remove(backupFilePath) 4508 assert.NoError(t, err) 4509 err = createTestFile(backupFilePath, 10485761) 4510 assert.NoError(t, err) 4511 _, _, err = httpdtest.Loaddata(backupFilePath, "1", "0", http.StatusBadRequest) 4512 assert.NoError(t, err) 4513 err = os.Remove(backupFilePath) 4514 assert.NoError(t, err) 4515 err = createTestFile(backupFilePath, 65535) 4516 assert.NoError(t, err) 4517 _, _, err = httpdtest.Loaddata(backupFilePath, "1", "0", http.StatusBadRequest) 4518 assert.NoError(t, err) 4519 err = os.Remove(backupFilePath) 4520 assert.NoError(t, err) 4521} 4522 4523func TestLoaddataMode(t *testing.T) { 4524 mappedPath := filepath.Join(os.TempDir(), "restored_fold") 4525 folderName := filepath.Base(mappedPath) 4526 user := getTestUser() 4527 user.ID = 1 4528 user.Username = "test_user_restore" 4529 admin := getTestAdmin() 4530 admin.ID = 1 4531 admin.Username = "test_admin_restore" 4532 apiKey := dataprovider.APIKey{ 4533 Name: util.GenerateUniqueID(), 4534 Scope: dataprovider.APIKeyScopeAdmin, 4535 KeyID: util.GenerateUniqueID(), 4536 Key: fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()), 4537 Description: "desc", 4538 } 4539 share := dataprovider.Share{ 4540 ShareID: util.GenerateUniqueID(), 4541 Name: util.GenerateUniqueID(), 4542 Scope: dataprovider.ShareScopeRead, 4543 Paths: []string{"/"}, 4544 Username: user.Username, 4545 } 4546 backupData := dataprovider.BackupData{} 4547 backupData.Users = append(backupData.Users, user) 4548 backupData.Admins = append(backupData.Admins, admin) 4549 backupData.Folders = []vfs.BaseVirtualFolder{ 4550 { 4551 Name: folderName, 4552 MappedPath: mappedPath, 4553 UsedQuotaSize: 123, 4554 UsedQuotaFiles: 456, 4555 LastQuotaUpdate: 789, 4556 Users: []string{"user"}, 4557 }, 4558 { 4559 MappedPath: mappedPath + "1", 4560 Name: folderName, 4561 }, 4562 } 4563 backupData.APIKeys = append(backupData.APIKeys, apiKey) 4564 backupData.Shares = append(backupData.Shares, share) 4565 backupContent, _ := json.Marshal(backupData) 4566 backupFilePath := filepath.Join(backupsPath, "backup.json") 4567 err := os.WriteFile(backupFilePath, backupContent, os.ModePerm) 4568 assert.NoError(t, err) 4569 _, _, err = httpdtest.Loaddata(backupFilePath, "0", "0", http.StatusOK) 4570 assert.NoError(t, err) 4571 folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK) 4572 assert.NoError(t, err) 4573 assert.Equal(t, mappedPath+"1", folder.MappedPath) 4574 assert.Equal(t, int64(123), folder.UsedQuotaSize) 4575 assert.Equal(t, 456, folder.UsedQuotaFiles) 4576 assert.Equal(t, int64(789), folder.LastQuotaUpdate) 4577 assert.Len(t, folder.Users, 0) 4578 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 4579 assert.NoError(t, err) 4580 oldUploadBandwidth := user.UploadBandwidth 4581 user.UploadBandwidth = oldUploadBandwidth + 128 4582 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 4583 assert.NoError(t, err) 4584 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 4585 assert.NoError(t, err) 4586 oldInfo := admin.AdditionalInfo 4587 oldDesc := admin.Description 4588 admin.AdditionalInfo = "newInfo" 4589 admin.Description = "newDesc" 4590 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 4591 assert.NoError(t, err) 4592 apiKey, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusOK) 4593 assert.NoError(t, err) 4594 oldAPIKeyDesc := apiKey.Description 4595 apiKey.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now()) 4596 apiKey.Description = "new desc" 4597 apiKey, _, err = httpdtest.UpdateAPIKey(apiKey, http.StatusOK) 4598 assert.NoError(t, err) 4599 share.Description = "test desc" 4600 err = dataprovider.UpdateShare(&share, "", "") 4601 assert.NoError(t, err) 4602 4603 backupData.Folders = []vfs.BaseVirtualFolder{ 4604 { 4605 MappedPath: mappedPath, 4606 Name: folderName, 4607 }, 4608 } 4609 _, _, err = httpdtest.Loaddata(backupFilePath, "0", "1", http.StatusOK) 4610 assert.NoError(t, err) 4611 folder, _, err = httpdtest.GetFolderByName(folderName, http.StatusOK) 4612 assert.NoError(t, err) 4613 assert.Equal(t, mappedPath+"1", folder.MappedPath) 4614 assert.Equal(t, int64(123), folder.UsedQuotaSize) 4615 assert.Equal(t, 456, folder.UsedQuotaFiles) 4616 assert.Equal(t, int64(789), folder.LastQuotaUpdate) 4617 assert.Len(t, folder.Users, 0) 4618 4619 c := common.NewBaseConnection("connID", common.ProtocolFTP, "", "", user) 4620 fakeConn := &fakeConnection{ 4621 BaseConnection: c, 4622 } 4623 common.Connections.Add(fakeConn) 4624 assert.Len(t, common.Connections.GetStats(), 1) 4625 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 4626 assert.NoError(t, err) 4627 assert.NotEqual(t, oldUploadBandwidth, user.UploadBandwidth) 4628 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 4629 assert.NoError(t, err) 4630 assert.NotEqual(t, oldInfo, admin.AdditionalInfo) 4631 assert.NotEqual(t, oldDesc, admin.Description) 4632 4633 apiKey, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusOK) 4634 assert.NoError(t, err) 4635 assert.NotEqual(t, int64(0), apiKey.ExpiresAt) 4636 assert.NotEqual(t, oldAPIKeyDesc, apiKey.Description) 4637 4638 share, err = dataprovider.ShareExists(share.ShareID, user.Username) 4639 assert.NoError(t, err) 4640 assert.NotEmpty(t, share.Description) 4641 4642 _, _, err = httpdtest.Loaddata(backupFilePath, "0", "2", http.StatusOK) 4643 assert.NoError(t, err) 4644 // mode 2 will update the user and close the previous connection 4645 assert.Len(t, common.Connections.GetStats(), 0) 4646 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 4647 assert.NoError(t, err) 4648 assert.Equal(t, oldUploadBandwidth, user.UploadBandwidth) 4649 _, err = httpdtest.RemoveUser(user, http.StatusOK) 4650 assert.NoError(t, err) 4651 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 4652 assert.NoError(t, err) 4653 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 4654 assert.NoError(t, err) 4655 err = os.Remove(backupFilePath) 4656 assert.NoError(t, err) 4657} 4658 4659func TestRateLimiter(t *testing.T) { 4660 oldConfig := config.GetCommonConfig() 4661 4662 cfg := config.GetCommonConfig() 4663 cfg.RateLimitersConfig = []common.RateLimiterConfig{ 4664 { 4665 Average: 1, 4666 Period: 1000, 4667 Burst: 1, 4668 Type: 1, 4669 Protocols: []string{common.ProtocolHTTP}, 4670 }, 4671 } 4672 4673 err := common.Initialize(cfg) 4674 assert.NoError(t, err) 4675 4676 client := &http.Client{ 4677 Timeout: 5 * time.Second, 4678 } 4679 resp, err := client.Get(httpBaseURL + healthzPath) 4680 assert.NoError(t, err) 4681 assert.Equal(t, http.StatusOK, resp.StatusCode) 4682 err = resp.Body.Close() 4683 assert.NoError(t, err) 4684 4685 resp, err = client.Get(httpBaseURL + healthzPath) 4686 assert.NoError(t, err) 4687 assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode) 4688 assert.Equal(t, "1", resp.Header.Get("Retry-After")) 4689 assert.NotEmpty(t, resp.Header.Get("X-Retry-In")) 4690 err = resp.Body.Close() 4691 assert.NoError(t, err) 4692 4693 resp, err = client.Get(httpBaseURL + webLoginPath) 4694 assert.NoError(t, err) 4695 assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode) 4696 assert.Equal(t, "1", resp.Header.Get("Retry-After")) 4697 assert.NotEmpty(t, resp.Header.Get("X-Retry-In")) 4698 err = resp.Body.Close() 4699 assert.NoError(t, err) 4700 4701 resp, err = client.Get(httpBaseURL + webClientLoginPath) 4702 assert.NoError(t, err) 4703 assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode) 4704 assert.Equal(t, "1", resp.Header.Get("Retry-After")) 4705 assert.NotEmpty(t, resp.Header.Get("X-Retry-In")) 4706 err = resp.Body.Close() 4707 assert.NoError(t, err) 4708 4709 err = common.Initialize(oldConfig) 4710 assert.NoError(t, err) 4711} 4712 4713func TestHTTPSConnection(t *testing.T) { 4714 client := &http.Client{ 4715 Timeout: 5 * time.Second, 4716 } 4717 resp, err := client.Get("https://localhost:8443" + healthzPath) 4718 if assert.Error(t, err) { 4719 if !strings.Contains(err.Error(), "certificate is not valid") && 4720 !strings.Contains(err.Error(), "certificate signed by unknown authority") { 4721 assert.Fail(t, err.Error()) 4722 } 4723 } else { 4724 resp.Body.Close() 4725 } 4726} 4727 4728// test using mock http server 4729 4730func TestBasicUserHandlingMock(t *testing.T) { 4731 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4732 assert.NoError(t, err) 4733 user := getTestUser() 4734 userAsJSON := getUserAsJSON(t, user) 4735 req, err := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 4736 assert.NoError(t, err) 4737 setBearerForReq(req, token) 4738 rr := executeRequest(req) 4739 checkResponseCode(t, http.StatusCreated, rr) 4740 err = render.DecodeJSON(rr.Body, &user) 4741 assert.NoError(t, err) 4742 req, err = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 4743 assert.NoError(t, err) 4744 setBearerForReq(req, token) 4745 rr = executeRequest(req) 4746 checkResponseCode(t, http.StatusInternalServerError, rr) 4747 user.MaxSessions = 10 4748 user.UploadBandwidth = 128 4749 user.Permissions["/"] = []string{dataprovider.PermAny, dataprovider.PermDelete, dataprovider.PermDownload} 4750 userAsJSON = getUserAsJSON(t, user) 4751 req, _ = http.NewRequest(http.MethodPut, userPath+"/"+user.Username, bytes.NewBuffer(userAsJSON)) 4752 setBearerForReq(req, token) 4753 rr = executeRequest(req) 4754 checkResponseCode(t, http.StatusOK, rr) 4755 4756 req, _ = http.NewRequest(http.MethodGet, userPath+"/"+user.Username, nil) 4757 setBearerForReq(req, token) 4758 rr = executeRequest(req) 4759 checkResponseCode(t, http.StatusOK, rr) 4760 4761 var updatedUser dataprovider.User 4762 err = render.DecodeJSON(rr.Body, &updatedUser) 4763 assert.NoError(t, err) 4764 assert.Equal(t, user.MaxSessions, updatedUser.MaxSessions) 4765 assert.Equal(t, user.UploadBandwidth, updatedUser.UploadBandwidth) 4766 assert.Equal(t, 1, len(updatedUser.Permissions["/"])) 4767 assert.True(t, util.IsStringInSlice(dataprovider.PermAny, updatedUser.Permissions["/"])) 4768 req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+user.Username, nil) 4769 setBearerForReq(req, token) 4770 rr = executeRequest(req) 4771 checkResponseCode(t, http.StatusOK, rr) 4772} 4773 4774func TestAddUserNoUsernameMock(t *testing.T) { 4775 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4776 assert.NoError(t, err) 4777 user := getTestUser() 4778 user.Username = "" 4779 userAsJSON := getUserAsJSON(t, user) 4780 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 4781 setBearerForReq(req, token) 4782 rr := executeRequest(req) 4783 checkResponseCode(t, http.StatusBadRequest, rr) 4784} 4785 4786func TestAddUserInvalidHomeDirMock(t *testing.T) { 4787 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4788 assert.NoError(t, err) 4789 user := getTestUser() 4790 user.HomeDir = "relative_path" 4791 userAsJSON := getUserAsJSON(t, user) 4792 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 4793 setBearerForReq(req, token) 4794 rr := executeRequest(req) 4795 checkResponseCode(t, http.StatusBadRequest, rr) 4796} 4797 4798func TestAddUserInvalidPermsMock(t *testing.T) { 4799 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4800 assert.NoError(t, err) 4801 user := getTestUser() 4802 user.Permissions["/"] = []string{} 4803 userAsJSON := getUserAsJSON(t, user) 4804 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 4805 setBearerForReq(req, token) 4806 rr := executeRequest(req) 4807 checkResponseCode(t, http.StatusBadRequest, rr) 4808} 4809 4810func TestAddFolderInvalidJsonMock(t *testing.T) { 4811 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4812 assert.NoError(t, err) 4813 req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer([]byte("invalid json"))) 4814 setBearerForReq(req, token) 4815 rr := executeRequest(req) 4816 checkResponseCode(t, http.StatusBadRequest, rr) 4817} 4818 4819func TestUpdateFolderInvalidJsonMock(t *testing.T) { 4820 folder := vfs.BaseVirtualFolder{ 4821 Name: "name", 4822 MappedPath: filepath.Clean(os.TempDir()), 4823 } 4824 folder, resp, err := httpdtest.AddFolder(folder, http.StatusCreated) 4825 assert.NoError(t, err, string(resp)) 4826 4827 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4828 assert.NoError(t, err) 4829 req, _ := http.NewRequest(http.MethodPut, path.Join(folderPath, folder.Name), bytes.NewBuffer([]byte("not a json"))) 4830 setBearerForReq(req, token) 4831 rr := executeRequest(req) 4832 checkResponseCode(t, http.StatusBadRequest, rr) 4833 4834 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 4835 assert.NoError(t, err) 4836} 4837 4838func TestUnbanInvalidJsonMock(t *testing.T) { 4839 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4840 assert.NoError(t, err) 4841 req, _ := http.NewRequest(http.MethodPost, defenderUnban, bytes.NewBuffer([]byte("invalid json"))) 4842 setBearerForReq(req, token) 4843 rr := executeRequest(req) 4844 checkResponseCode(t, http.StatusBadRequest, rr) 4845} 4846 4847func TestAddUserInvalidJsonMock(t *testing.T) { 4848 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4849 assert.NoError(t, err) 4850 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer([]byte("invalid json"))) 4851 setBearerForReq(req, token) 4852 rr := executeRequest(req) 4853 checkResponseCode(t, http.StatusBadRequest, rr) 4854} 4855 4856func TestAddAdminInvalidJsonMock(t *testing.T) { 4857 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4858 assert.NoError(t, err) 4859 req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer([]byte("..."))) 4860 setBearerForReq(req, token) 4861 rr := executeRequest(req) 4862 checkResponseCode(t, http.StatusBadRequest, rr) 4863} 4864 4865func TestAddAdminNoPasswordMock(t *testing.T) { 4866 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4867 assert.NoError(t, err) 4868 admin := getTestAdmin() 4869 admin.Password = "" 4870 asJSON, err := json.Marshal(admin) 4871 assert.NoError(t, err) 4872 req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON)) 4873 setBearerForReq(req, token) 4874 rr := executeRequest(req) 4875 checkResponseCode(t, http.StatusBadRequest, rr) 4876 assert.Contains(t, rr.Body.String(), "please set a password") 4877} 4878 4879func TestAdminTwoFactorLogin(t *testing.T) { 4880 admin := getTestAdmin() 4881 admin.Username = altAdminUsername 4882 admin.Password = altAdminPassword 4883 admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) 4884 assert.NoError(t, err) 4885 // enable two factor authentication 4886 configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], admin.Username) 4887 assert.NoError(t, err) 4888 altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword) 4889 assert.NoError(t, err) 4890 adminTOTPConfig := dataprovider.TOTPConfig{ 4891 Enabled: true, 4892 ConfigName: configName, 4893 Secret: kms.NewPlainSecret(secret), 4894 } 4895 asJSON, err := json.Marshal(adminTOTPConfig) 4896 assert.NoError(t, err) 4897 req, err := http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON)) 4898 assert.NoError(t, err) 4899 setBearerForReq(req, altToken) 4900 rr := executeRequest(req) 4901 checkResponseCode(t, http.StatusOK, rr) 4902 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 4903 assert.NoError(t, err) 4904 assert.True(t, admin.Filters.TOTPConfig.Enabled) 4905 4906 req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil) 4907 assert.NoError(t, err) 4908 setBearerForReq(req, altToken) 4909 rr = executeRequest(req) 4910 checkResponseCode(t, http.StatusOK, rr) 4911 var recCodes []recoveryCode 4912 err = json.Unmarshal(rr.Body.Bytes(), &recCodes) 4913 assert.NoError(t, err) 4914 assert.Len(t, recCodes, 12) 4915 4916 admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK) 4917 assert.NoError(t, err) 4918 assert.Len(t, admin.Filters.RecoveryCodes, 12) 4919 for _, c := range admin.Filters.RecoveryCodes { 4920 assert.Empty(t, c.Secret.GetAdditionalData()) 4921 assert.Empty(t, c.Secret.GetKey()) 4922 assert.Equal(t, kms.SecretStatusSecretBox, c.Secret.GetStatus()) 4923 assert.NotEmpty(t, c.Secret.GetPayload()) 4924 } 4925 4926 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 4927 assert.NoError(t, err) 4928 req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorPath, nil) 4929 assert.NoError(t, err) 4930 setJWTCookieForReq(req, webToken) 4931 rr = executeRequest(req) 4932 checkResponseCode(t, http.StatusNotFound, rr) 4933 4934 req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorRecoveryPath, nil) 4935 assert.NoError(t, err) 4936 setJWTCookieForReq(req, webToken) 4937 rr = executeRequest(req) 4938 checkResponseCode(t, http.StatusNotFound, rr) 4939 4940 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, nil) 4941 assert.NoError(t, err) 4942 setJWTCookieForReq(req, webToken) 4943 rr = executeRequest(req) 4944 checkResponseCode(t, http.StatusNotFound, rr) 4945 4946 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, nil) 4947 assert.NoError(t, err) 4948 setJWTCookieForReq(req, webToken) 4949 rr = executeRequest(req) 4950 checkResponseCode(t, http.StatusNotFound, rr) 4951 4952 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 4953 assert.NoError(t, err) 4954 form := getLoginForm(altAdminUsername, altAdminPassword, csrfToken) 4955 req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 4956 assert.NoError(t, err) 4957 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 4958 rr = executeRequest(req) 4959 assert.Equal(t, http.StatusFound, rr.Code) 4960 assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location")) 4961 cookie, err := getCookieFromResponse(rr) 4962 assert.NoError(t, err) 4963 4964 // without a cookie 4965 req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorRecoveryPath, nil) 4966 assert.NoError(t, err) 4967 rr = executeRequest(req) 4968 checkResponseCode(t, http.StatusNotFound, rr) 4969 4970 req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorPath, nil) 4971 assert.NoError(t, err) 4972 setJWTCookieForReq(req, cookie) 4973 rr = executeRequest(req) 4974 checkResponseCode(t, http.StatusOK, rr) 4975 4976 req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorRecoveryPath, nil) 4977 assert.NoError(t, err) 4978 setJWTCookieForReq(req, cookie) 4979 rr = executeRequest(req) 4980 checkResponseCode(t, http.StatusOK, rr) 4981 4982 // any other page will be redirected to the two factor auth page 4983 req, err = http.NewRequest(http.MethodGet, webUsersPath, nil) 4984 assert.NoError(t, err) 4985 setJWTCookieForReq(req, cookie) 4986 rr = executeRequest(req) 4987 checkResponseCode(t, http.StatusFound, rr) 4988 assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location")) 4989 // a partial token cannot be used for user pages 4990 req, err = http.NewRequest(http.MethodGet, webClientFilesPath, nil) 4991 assert.NoError(t, err) 4992 setJWTCookieForReq(req, cookie) 4993 rr = executeRequest(req) 4994 checkResponseCode(t, http.StatusFound, rr) 4995 assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) 4996 4997 passcode, err := generateTOTPPasscode(secret) 4998 assert.NoError(t, err) 4999 form = make(url.Values) 5000 form.Set("passcode", passcode) 5001 // no csrf 5002 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5003 assert.NoError(t, err) 5004 setJWTCookieForReq(req, cookie) 5005 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5006 rr = executeRequest(req) 5007 assert.Equal(t, http.StatusOK, rr.Code) 5008 assert.Contains(t, rr.Body.String(), "unable to verify form token") 5009 5010 form.Set(csrfFormToken, csrfToken) 5011 form.Set("passcode", "invalid_passcode") 5012 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5013 assert.NoError(t, err) 5014 setJWTCookieForReq(req, cookie) 5015 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5016 rr = executeRequest(req) 5017 assert.Equal(t, http.StatusOK, rr.Code) 5018 assert.Contains(t, rr.Body.String(), "Invalid authentication code") 5019 5020 form.Set("passcode", "") 5021 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5022 assert.NoError(t, err) 5023 setJWTCookieForReq(req, cookie) 5024 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5025 rr = executeRequest(req) 5026 assert.Equal(t, http.StatusOK, rr.Code) 5027 assert.Contains(t, rr.Body.String(), "Invalid credentials") 5028 5029 form.Set("passcode", passcode) 5030 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5031 assert.NoError(t, err) 5032 setJWTCookieForReq(req, cookie) 5033 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5034 rr = executeRequest(req) 5035 assert.Equal(t, http.StatusFound, rr.Code) 5036 assert.Equal(t, webUsersPath, rr.Header().Get("Location")) 5037 // the same cookie cannot be reused 5038 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5039 assert.NoError(t, err) 5040 setJWTCookieForReq(req, cookie) 5041 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5042 rr = executeRequest(req) 5043 assert.Equal(t, http.StatusNotFound, rr.Code) 5044 // get a new cookie and login using a recovery code 5045 form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken) 5046 req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 5047 assert.NoError(t, err) 5048 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5049 rr = executeRequest(req) 5050 assert.Equal(t, http.StatusFound, rr.Code) 5051 assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location")) 5052 cookie, err = getCookieFromResponse(rr) 5053 assert.NoError(t, err) 5054 5055 form = make(url.Values) 5056 recoveryCode := recCodes[0].Code 5057 form.Set("recovery_code", recoveryCode) 5058 // no csrf 5059 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5060 assert.NoError(t, err) 5061 setJWTCookieForReq(req, cookie) 5062 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5063 rr = executeRequest(req) 5064 assert.Equal(t, http.StatusOK, rr.Code) 5065 assert.Contains(t, rr.Body.String(), "unable to verify form token") 5066 5067 form.Set(csrfFormToken, csrfToken) 5068 form.Set("recovery_code", "") 5069 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5070 assert.NoError(t, err) 5071 setJWTCookieForReq(req, cookie) 5072 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5073 rr = executeRequest(req) 5074 assert.Equal(t, http.StatusOK, rr.Code) 5075 assert.Contains(t, rr.Body.String(), "Invalid credentials") 5076 5077 form.Set("recovery_code", recoveryCode) 5078 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5079 assert.NoError(t, err) 5080 setJWTCookieForReq(req, cookie) 5081 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5082 rr = executeRequest(req) 5083 assert.Equal(t, http.StatusFound, rr.Code) 5084 assert.Equal(t, webUsersPath, rr.Header().Get("Location")) 5085 authenticatedCookie, err := getCookieFromResponse(rr) 5086 assert.NoError(t, err) 5087 //render MFA page 5088 req, err = http.NewRequest(http.MethodGet, webAdminMFAPath, nil) 5089 assert.NoError(t, err) 5090 setJWTCookieForReq(req, authenticatedCookie) 5091 rr = executeRequest(req) 5092 checkResponseCode(t, http.StatusOK, rr) 5093 // check that the recovery code was marked as used 5094 req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil) 5095 assert.NoError(t, err) 5096 setBearerForReq(req, altToken) 5097 rr = executeRequest(req) 5098 checkResponseCode(t, http.StatusOK, rr) 5099 recCodes = nil 5100 err = json.Unmarshal(rr.Body.Bytes(), &recCodes) 5101 assert.NoError(t, err) 5102 assert.Len(t, recCodes, 12) 5103 found := false 5104 for _, rc := range recCodes { 5105 if rc.Code == recoveryCode { 5106 found = true 5107 assert.True(t, rc.Used) 5108 } else { 5109 assert.False(t, rc.Used) 5110 } 5111 } 5112 assert.True(t, found) 5113 // the same recovery code cannot be reused 5114 form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken) 5115 req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 5116 assert.NoError(t, err) 5117 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5118 rr = executeRequest(req) 5119 assert.Equal(t, http.StatusFound, rr.Code) 5120 assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location")) 5121 cookie, err = getCookieFromResponse(rr) 5122 assert.NoError(t, err) 5123 form = make(url.Values) 5124 form.Set("recovery_code", recoveryCode) 5125 form.Set(csrfFormToken, csrfToken) 5126 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5127 assert.NoError(t, err) 5128 setJWTCookieForReq(req, cookie) 5129 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5130 rr = executeRequest(req) 5131 assert.Equal(t, http.StatusOK, rr.Code) 5132 assert.Contains(t, rr.Body.String(), "This recovery code was already used") 5133 5134 form.Set("recovery_code", "invalid_recovery_code") 5135 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5136 assert.NoError(t, err) 5137 setJWTCookieForReq(req, cookie) 5138 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5139 rr = executeRequest(req) 5140 assert.Equal(t, http.StatusOK, rr.Code) 5141 assert.Contains(t, rr.Body.String(), "Invalid recovery code") 5142 5143 form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken) 5144 req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 5145 assert.NoError(t, err) 5146 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5147 rr = executeRequest(req) 5148 assert.Equal(t, http.StatusFound, rr.Code) 5149 assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location")) 5150 cookie, err = getCookieFromResponse(rr) 5151 assert.NoError(t, err) 5152 5153 // disable TOTP 5154 req, err = http.NewRequest(http.MethodPut, adminPath+"/"+altAdminUsername+"/2fa/disable", nil) 5155 assert.NoError(t, err) 5156 setBearerForReq(req, altToken) 5157 rr = executeRequest(req) 5158 checkResponseCode(t, http.StatusOK, rr) 5159 5160 form = make(url.Values) 5161 form.Set("recovery_code", recoveryCode) 5162 form.Set(csrfFormToken, csrfToken) 5163 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5164 assert.NoError(t, err) 5165 setJWTCookieForReq(req, cookie) 5166 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5167 rr = executeRequest(req) 5168 assert.Equal(t, http.StatusOK, rr.Code) 5169 assert.Contains(t, rr.Body.String(), "Two factory authentication is not enabled") 5170 5171 form.Set("passcode", passcode) 5172 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5173 assert.NoError(t, err) 5174 setJWTCookieForReq(req, cookie) 5175 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5176 rr = executeRequest(req) 5177 assert.Equal(t, http.StatusOK, rr.Code) 5178 assert.Contains(t, rr.Body.String(), "Two factory authentication is not enabled") 5179 5180 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 5181 assert.NoError(t, err) 5182 5183 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5184 assert.NoError(t, err) 5185 setJWTCookieForReq(req, cookie) 5186 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5187 rr = executeRequest(req) 5188 assert.Equal(t, http.StatusOK, rr.Code) 5189 assert.Contains(t, rr.Body.String(), "Invalid credentials") 5190 5191 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5192 assert.NoError(t, err) 5193 setJWTCookieForReq(req, cookie) 5194 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5195 rr = executeRequest(req) 5196 assert.Equal(t, http.StatusOK, rr.Code) 5197 assert.Contains(t, rr.Body.String(), "Invalid credentials") 5198 5199 req, err = http.NewRequest(http.MethodGet, webAdminMFAPath, nil) 5200 assert.NoError(t, err) 5201 setJWTCookieForReq(req, authenticatedCookie) 5202 rr = executeRequest(req) 5203 checkResponseCode(t, http.StatusInternalServerError, rr) 5204} 5205 5206func TestAdminTOTP(t *testing.T) { 5207 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 5208 assert.NoError(t, err) 5209 admin := getTestAdmin() 5210 admin.Username = altAdminUsername 5211 admin.Password = altAdminPassword 5212 // TOTPConfig will be ignored on add 5213 admin.Filters.TOTPConfig = dataprovider.TOTPConfig{ 5214 Enabled: true, 5215 ConfigName: "config", 5216 Secret: kms.NewEmptySecret(), 5217 } 5218 asJSON, err := json.Marshal(admin) 5219 assert.NoError(t, err) 5220 req, err := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON)) 5221 assert.NoError(t, err) 5222 setBearerForReq(req, token) 5223 rr := executeRequest(req) 5224 checkResponseCode(t, http.StatusCreated, rr) 5225 5226 admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK) 5227 assert.NoError(t, err) 5228 assert.False(t, admin.Filters.TOTPConfig.Enabled) 5229 assert.Len(t, admin.Filters.RecoveryCodes, 0) 5230 5231 altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword) 5232 assert.NoError(t, err) 5233 5234 req, err = http.NewRequest(http.MethodGet, adminTOTPConfigsPath, nil) 5235 assert.NoError(t, err) 5236 setBearerForReq(req, altToken) 5237 rr = executeRequest(req) 5238 checkResponseCode(t, http.StatusOK, rr) 5239 var configs []mfa.TOTPConfig 5240 err = json.Unmarshal(rr.Body.Bytes(), &configs) 5241 assert.NoError(t, err, rr.Body.String()) 5242 assert.Len(t, configs, len(mfa.GetAvailableTOTPConfigs())) 5243 totpConfig := configs[0] 5244 totpReq := generateTOTPRequest{ 5245 ConfigName: totpConfig.Name, 5246 } 5247 asJSON, err = json.Marshal(totpReq) 5248 assert.NoError(t, err) 5249 req, err = http.NewRequest(http.MethodPost, adminTOTPGeneratePath, bytes.NewBuffer(asJSON)) 5250 assert.NoError(t, err) 5251 setBearerForReq(req, altToken) 5252 rr = executeRequest(req) 5253 checkResponseCode(t, http.StatusOK, rr) 5254 var totpGenResp generateTOTPResponse 5255 err = json.Unmarshal(rr.Body.Bytes(), &totpGenResp) 5256 assert.NoError(t, err) 5257 assert.NotEmpty(t, totpGenResp.Secret) 5258 assert.NotEmpty(t, totpGenResp.QRCode) 5259 5260 passcode, err := generateTOTPPasscode(totpGenResp.Secret) 5261 assert.NoError(t, err) 5262 validateReq := validateTOTPRequest{ 5263 ConfigName: totpGenResp.ConfigName, 5264 Passcode: passcode, 5265 Secret: totpGenResp.Secret, 5266 } 5267 asJSON, err = json.Marshal(validateReq) 5268 assert.NoError(t, err) 5269 req, err = http.NewRequest(http.MethodPost, adminTOTPValidatePath, bytes.NewBuffer(asJSON)) 5270 assert.NoError(t, err) 5271 setBearerForReq(req, altToken) 5272 rr = executeRequest(req) 5273 checkResponseCode(t, http.StatusOK, rr) 5274 // the same passcode cannot be reused 5275 req, err = http.NewRequest(http.MethodPost, adminTOTPValidatePath, bytes.NewBuffer(asJSON)) 5276 assert.NoError(t, err) 5277 setBearerForReq(req, altToken) 5278 rr = executeRequest(req) 5279 checkResponseCode(t, http.StatusBadRequest, rr) 5280 assert.Contains(t, rr.Body.String(), "this passcode was already used") 5281 5282 adminTOTPConfig := dataprovider.TOTPConfig{ 5283 Enabled: true, 5284 ConfigName: totpGenResp.ConfigName, 5285 Secret: kms.NewPlainSecret(totpGenResp.Secret), 5286 } 5287 asJSON, err = json.Marshal(adminTOTPConfig) 5288 assert.NoError(t, err) 5289 req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON)) 5290 assert.NoError(t, err) 5291 setBearerForReq(req, altToken) 5292 rr = executeRequest(req) 5293 checkResponseCode(t, http.StatusOK, rr) 5294 admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK) 5295 assert.NoError(t, err) 5296 assert.True(t, admin.Filters.TOTPConfig.Enabled) 5297 assert.Equal(t, totpGenResp.ConfigName, admin.Filters.TOTPConfig.ConfigName) 5298 assert.Empty(t, admin.Filters.TOTPConfig.Secret.GetKey()) 5299 assert.Empty(t, admin.Filters.TOTPConfig.Secret.GetAdditionalData()) 5300 assert.NotEmpty(t, admin.Filters.TOTPConfig.Secret.GetPayload()) 5301 assert.Equal(t, kms.SecretStatusSecretBox, admin.Filters.TOTPConfig.Secret.GetStatus()) 5302 admin.Filters.TOTPConfig = dataprovider.TOTPConfig{ 5303 Enabled: false, 5304 ConfigName: util.GenerateUniqueID(), 5305 Secret: kms.NewEmptySecret(), 5306 } 5307 admin.Filters.RecoveryCodes = []sdk.RecoveryCode{ 5308 { 5309 Secret: kms.NewEmptySecret(), 5310 }, 5311 } 5312 admin, resp, err := httpdtest.UpdateAdmin(admin, http.StatusOK) 5313 assert.NoError(t, err, string(resp)) 5314 assert.True(t, admin.Filters.TOTPConfig.Enabled) 5315 assert.Len(t, admin.Filters.RecoveryCodes, 12) 5316 // if we use token we should get no recovery codes 5317 req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil) 5318 assert.NoError(t, err) 5319 setBearerForReq(req, token) 5320 rr = executeRequest(req) 5321 checkResponseCode(t, http.StatusOK, rr) 5322 var recCodes []recoveryCode 5323 err = json.Unmarshal(rr.Body.Bytes(), &recCodes) 5324 assert.NoError(t, err) 5325 assert.Len(t, recCodes, 0) 5326 // now the same but with altToken 5327 req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil) 5328 assert.NoError(t, err) 5329 setBearerForReq(req, altToken) 5330 rr = executeRequest(req) 5331 checkResponseCode(t, http.StatusOK, rr) 5332 recCodes = nil 5333 err = json.Unmarshal(rr.Body.Bytes(), &recCodes) 5334 assert.NoError(t, err) 5335 assert.Len(t, recCodes, 12) 5336 // regenerate recovery codes 5337 req, err = http.NewRequest(http.MethodPost, admin2FARecoveryCodesPath, nil) 5338 assert.NoError(t, err) 5339 setBearerForReq(req, altToken) 5340 rr = executeRequest(req) 5341 checkResponseCode(t, http.StatusOK, rr) 5342 // check that recovery codes are different 5343 req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil) 5344 assert.NoError(t, err) 5345 setBearerForReq(req, altToken) 5346 rr = executeRequest(req) 5347 checkResponseCode(t, http.StatusOK, rr) 5348 var newRecCodes []recoveryCode 5349 err = json.Unmarshal(rr.Body.Bytes(), &newRecCodes) 5350 assert.NoError(t, err) 5351 assert.Len(t, newRecCodes, 12) 5352 assert.NotEqual(t, recCodes, newRecCodes) 5353 // disable 2FA, the update admin API should not work 5354 admin.Filters.TOTPConfig.Enabled = false 5355 admin.Filters.RecoveryCodes = nil 5356 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 5357 assert.NoError(t, err) 5358 assert.Equal(t, altAdminUsername, admin.Username) 5359 assert.True(t, admin.Filters.TOTPConfig.Enabled) 5360 assert.Len(t, admin.Filters.RecoveryCodes, 12) 5361 // use the dedicated API 5362 req, err = http.NewRequest(http.MethodPut, adminPath+"/"+altAdminUsername+"/2fa/disable", nil) 5363 assert.NoError(t, err) 5364 setBearerForReq(req, token) 5365 rr = executeRequest(req) 5366 checkResponseCode(t, http.StatusOK, rr) 5367 admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK) 5368 assert.NoError(t, err) 5369 assert.False(t, admin.Filters.TOTPConfig.Enabled) 5370 assert.Len(t, admin.Filters.RecoveryCodes, 0) 5371 5372 req, _ = http.NewRequest(http.MethodDelete, path.Join(adminPath, altAdminUsername), nil) 5373 setBearerForReq(req, token) 5374 rr = executeRequest(req) 5375 checkResponseCode(t, http.StatusOK, rr) 5376 5377 req, err = http.NewRequest(http.MethodPut, adminPath+"/"+altAdminUsername+"/2fa/disable", nil) 5378 assert.NoError(t, err) 5379 setBearerForReq(req, token) 5380 rr = executeRequest(req) 5381 checkResponseCode(t, http.StatusNotFound, rr) 5382 5383 req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil) 5384 assert.NoError(t, err) 5385 setBearerForReq(req, altToken) 5386 rr = executeRequest(req) 5387 checkResponseCode(t, http.StatusNotFound, rr) 5388 5389 req, err = http.NewRequest(http.MethodPost, admin2FARecoveryCodesPath, nil) 5390 assert.NoError(t, err) 5391 setBearerForReq(req, altToken) 5392 rr = executeRequest(req) 5393 checkResponseCode(t, http.StatusNotFound, rr) 5394 5395 req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON)) 5396 assert.NoError(t, err) 5397 setBearerForReq(req, altToken) 5398 rr = executeRequest(req) 5399 checkResponseCode(t, http.StatusNotFound, rr) 5400} 5401 5402func TestChangeAdminPwdInvalidJsonMock(t *testing.T) { 5403 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 5404 assert.NoError(t, err) 5405 req, _ := http.NewRequest(http.MethodPut, adminPwdPath, bytes.NewBuffer([]byte("{"))) 5406 setBearerForReq(req, token) 5407 rr := executeRequest(req) 5408 checkResponseCode(t, http.StatusBadRequest, rr) 5409} 5410 5411func TestMFAPermission(t *testing.T) { 5412 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 5413 assert.NoError(t, err) 5414 5415 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 5416 assert.NoError(t, err) 5417 5418 req, err := http.NewRequest(http.MethodGet, webClientMFAPath, nil) 5419 assert.NoError(t, err) 5420 req.RequestURI = webClientMFAPath 5421 setJWTCookieForReq(req, webToken) 5422 rr := executeRequest(req) 5423 checkResponseCode(t, http.StatusOK, rr) 5424 5425 user.Filters.WebClient = []string{sdk.WebClientMFADisabled} 5426 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 5427 assert.NoError(t, err) 5428 5429 webToken, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 5430 assert.NoError(t, err) 5431 5432 req, err = http.NewRequest(http.MethodGet, webClientMFAPath, nil) 5433 assert.NoError(t, err) 5434 req.RequestURI = webClientMFAPath 5435 setJWTCookieForReq(req, webToken) 5436 rr = executeRequest(req) 5437 checkResponseCode(t, http.StatusForbidden, rr) 5438 5439 _, err = httpdtest.RemoveUser(user, http.StatusOK) 5440 assert.NoError(t, err) 5441 err = os.RemoveAll(user.GetHomeDir()) 5442 assert.NoError(t, err) 5443} 5444 5445func TestWebUserTwoFactorLogin(t *testing.T) { 5446 u := getTestUser() 5447 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 5448 assert.NoError(t, err) 5449 // enable two factor authentication 5450 configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) 5451 assert.NoError(t, err) 5452 token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 5453 assert.NoError(t, err) 5454 adminToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 5455 assert.NoError(t, err) 5456 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 5457 assert.NoError(t, err) 5458 5459 userTOTPConfig := sdk.TOTPConfig{ 5460 Enabled: true, 5461 ConfigName: configName, 5462 Secret: kms.NewPlainSecret(secret), 5463 Protocols: []string{common.ProtocolHTTP}, 5464 } 5465 asJSON, err := json.Marshal(userTOTPConfig) 5466 assert.NoError(t, err) 5467 req, err := http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 5468 assert.NoError(t, err) 5469 setBearerForReq(req, token) 5470 rr := executeRequest(req) 5471 checkResponseCode(t, http.StatusOK, rr) 5472 5473 req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil) 5474 assert.NoError(t, err) 5475 setBearerForReq(req, token) 5476 rr = executeRequest(req) 5477 checkResponseCode(t, http.StatusOK, rr) 5478 var recCodes []recoveryCode 5479 err = json.Unmarshal(rr.Body.Bytes(), &recCodes) 5480 assert.NoError(t, err) 5481 assert.Len(t, recCodes, 12) 5482 5483 user, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusOK) 5484 assert.NoError(t, err) 5485 assert.Len(t, user.Filters.RecoveryCodes, 12) 5486 for _, c := range user.Filters.RecoveryCodes { 5487 assert.Empty(t, c.Secret.GetAdditionalData()) 5488 assert.Empty(t, c.Secret.GetKey()) 5489 assert.Equal(t, kms.SecretStatusSecretBox, c.Secret.GetStatus()) 5490 assert.NotEmpty(t, c.Secret.GetPayload()) 5491 } 5492 5493 req, err = http.NewRequest(http.MethodGet, webClientTwoFactorPath, nil) 5494 assert.NoError(t, err) 5495 setJWTCookieForReq(req, webToken) 5496 rr = executeRequest(req) 5497 checkResponseCode(t, http.StatusNotFound, rr) 5498 5499 req, err = http.NewRequest(http.MethodGet, webClientTwoFactorRecoveryPath, nil) 5500 assert.NoError(t, err) 5501 setJWTCookieForReq(req, webToken) 5502 rr = executeRequest(req) 5503 checkResponseCode(t, http.StatusNotFound, rr) 5504 5505 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, nil) 5506 assert.NoError(t, err) 5507 setJWTCookieForReq(req, webToken) 5508 rr = executeRequest(req) 5509 checkResponseCode(t, http.StatusNotFound, rr) 5510 5511 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, nil) 5512 assert.NoError(t, err) 5513 setJWTCookieForReq(req, webToken) 5514 rr = executeRequest(req) 5515 checkResponseCode(t, http.StatusNotFound, rr) 5516 5517 csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath) 5518 assert.NoError(t, err) 5519 form := getLoginForm(defaultUsername, defaultPassword, csrfToken) 5520 req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 5521 assert.NoError(t, err) 5522 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5523 rr = executeRequest(req) 5524 assert.Equal(t, http.StatusFound, rr.Code) 5525 assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location")) 5526 cookie, err := getCookieFromResponse(rr) 5527 assert.NoError(t, err) 5528 5529 req, err = http.NewRequest(http.MethodGet, webClientTwoFactorPath, nil) 5530 assert.NoError(t, err) 5531 setJWTCookieForReq(req, cookie) 5532 rr = executeRequest(req) 5533 checkResponseCode(t, http.StatusOK, rr) 5534 5535 // without a cookie 5536 req, err = http.NewRequest(http.MethodGet, webClientTwoFactorPath, nil) 5537 assert.NoError(t, err) 5538 rr = executeRequest(req) 5539 checkResponseCode(t, http.StatusNotFound, rr) 5540 5541 req, err = http.NewRequest(http.MethodGet, webClientTwoFactorRecoveryPath, nil) 5542 assert.NoError(t, err) 5543 setJWTCookieForReq(req, cookie) 5544 rr = executeRequest(req) 5545 checkResponseCode(t, http.StatusOK, rr) 5546 // any other page will be redirected to the two factor auth page 5547 req, err = http.NewRequest(http.MethodGet, webClientFilesPath, nil) 5548 assert.NoError(t, err) 5549 setJWTCookieForReq(req, cookie) 5550 rr = executeRequest(req) 5551 checkResponseCode(t, http.StatusFound, rr) 5552 assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location")) 5553 // a partial token cannot be used for admin pages 5554 req, err = http.NewRequest(http.MethodGet, webUsersPath, nil) 5555 assert.NoError(t, err) 5556 setJWTCookieForReq(req, cookie) 5557 rr = executeRequest(req) 5558 checkResponseCode(t, http.StatusFound, rr) 5559 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 5560 5561 passcode, err := generateTOTPPasscode(secret) 5562 assert.NoError(t, err) 5563 form = make(url.Values) 5564 form.Set("passcode", passcode) 5565 5566 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5567 assert.NoError(t, err) 5568 setJWTCookieForReq(req, cookie) 5569 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5570 rr = executeRequest(req) 5571 assert.Equal(t, http.StatusOK, rr.Code) 5572 assert.Contains(t, rr.Body.String(), "unable to verify form token") 5573 5574 form.Set(csrfFormToken, csrfToken) 5575 form.Set("passcode", "invalid_user_passcode") 5576 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5577 assert.NoError(t, err) 5578 setJWTCookieForReq(req, cookie) 5579 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5580 rr = executeRequest(req) 5581 assert.Equal(t, http.StatusOK, rr.Code) 5582 assert.Contains(t, rr.Body.String(), "Invalid authentication code") 5583 5584 form.Set("passcode", "") 5585 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5586 assert.NoError(t, err) 5587 setJWTCookieForReq(req, cookie) 5588 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5589 rr = executeRequest(req) 5590 assert.Equal(t, http.StatusOK, rr.Code) 5591 assert.Contains(t, rr.Body.String(), "Invalid credentials") 5592 5593 form.Set("passcode", passcode) 5594 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5595 assert.NoError(t, err) 5596 setJWTCookieForReq(req, cookie) 5597 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5598 rr = executeRequest(req) 5599 assert.Equal(t, http.StatusFound, rr.Code) 5600 assert.Equal(t, webClientFilesPath, rr.Header().Get("Location")) 5601 // the same cookie cannot be reused 5602 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5603 assert.NoError(t, err) 5604 setJWTCookieForReq(req, cookie) 5605 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5606 rr = executeRequest(req) 5607 assert.Equal(t, http.StatusNotFound, rr.Code) 5608 // get a new cookie and login using a recovery code 5609 form = getLoginForm(defaultUsername, defaultPassword, csrfToken) 5610 req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 5611 assert.NoError(t, err) 5612 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5613 rr = executeRequest(req) 5614 assert.Equal(t, http.StatusFound, rr.Code) 5615 assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location")) 5616 cookie, err = getCookieFromResponse(rr) 5617 assert.NoError(t, err) 5618 5619 form = make(url.Values) 5620 recoveryCode := recCodes[0].Code 5621 form.Set("recovery_code", recoveryCode) 5622 // no csrf 5623 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5624 assert.NoError(t, err) 5625 setJWTCookieForReq(req, cookie) 5626 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5627 rr = executeRequest(req) 5628 assert.Equal(t, http.StatusOK, rr.Code) 5629 assert.Contains(t, rr.Body.String(), "unable to verify form token") 5630 5631 form.Set(csrfFormToken, csrfToken) 5632 form.Set("recovery_code", "") 5633 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5634 assert.NoError(t, err) 5635 setJWTCookieForReq(req, cookie) 5636 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5637 rr = executeRequest(req) 5638 assert.Equal(t, http.StatusOK, rr.Code) 5639 assert.Contains(t, rr.Body.String(), "Invalid credentials") 5640 5641 form.Set("recovery_code", recoveryCode) 5642 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5643 assert.NoError(t, err) 5644 setJWTCookieForReq(req, cookie) 5645 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5646 rr = executeRequest(req) 5647 assert.Equal(t, http.StatusFound, rr.Code) 5648 assert.Equal(t, webClientFilesPath, rr.Header().Get("Location")) 5649 authenticatedCookie, err := getCookieFromResponse(rr) 5650 assert.NoError(t, err) 5651 //render MFA page 5652 req, err = http.NewRequest(http.MethodGet, webClientMFAPath, nil) 5653 assert.NoError(t, err) 5654 setJWTCookieForReq(req, authenticatedCookie) 5655 rr = executeRequest(req) 5656 checkResponseCode(t, http.StatusOK, rr) 5657 5658 // check that the recovery code was marked as used 5659 req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil) 5660 assert.NoError(t, err) 5661 setBearerForReq(req, token) 5662 rr = executeRequest(req) 5663 checkResponseCode(t, http.StatusOK, rr) 5664 recCodes = nil 5665 err = json.Unmarshal(rr.Body.Bytes(), &recCodes) 5666 assert.NoError(t, err) 5667 assert.Len(t, recCodes, 12) 5668 found := false 5669 for _, rc := range recCodes { 5670 if rc.Code == recoveryCode { 5671 found = true 5672 assert.True(t, rc.Used) 5673 } else { 5674 assert.False(t, rc.Used) 5675 } 5676 } 5677 assert.True(t, found) 5678 // the same recovery code cannot be reused 5679 form = getLoginForm(defaultUsername, defaultPassword, csrfToken) 5680 req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 5681 assert.NoError(t, err) 5682 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5683 rr = executeRequest(req) 5684 assert.Equal(t, http.StatusFound, rr.Code) 5685 assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location")) 5686 cookie, err = getCookieFromResponse(rr) 5687 assert.NoError(t, err) 5688 form = make(url.Values) 5689 form.Set("recovery_code", recoveryCode) 5690 form.Set(csrfFormToken, csrfToken) 5691 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5692 assert.NoError(t, err) 5693 setJWTCookieForReq(req, cookie) 5694 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5695 rr = executeRequest(req) 5696 assert.Equal(t, http.StatusOK, rr.Code) 5697 assert.Contains(t, rr.Body.String(), "This recovery code was already used") 5698 5699 form.Set("recovery_code", "invalid_user_recovery_code") 5700 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5701 assert.NoError(t, err) 5702 setJWTCookieForReq(req, cookie) 5703 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5704 rr = executeRequest(req) 5705 assert.Equal(t, http.StatusOK, rr.Code) 5706 assert.Contains(t, rr.Body.String(), "Invalid recovery code") 5707 5708 form = getLoginForm(defaultUsername, defaultPassword, csrfToken) 5709 req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 5710 assert.NoError(t, err) 5711 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5712 rr = executeRequest(req) 5713 assert.Equal(t, http.StatusFound, rr.Code) 5714 assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location")) 5715 cookie, err = getCookieFromResponse(rr) 5716 assert.NoError(t, err) 5717 5718 // disable TOTP 5719 req, err = http.NewRequest(http.MethodPut, userPath+"/"+user.Username+"/2fa/disable", nil) 5720 assert.NoError(t, err) 5721 setBearerForReq(req, adminToken) 5722 rr = executeRequest(req) 5723 checkResponseCode(t, http.StatusOK, rr) 5724 5725 form = make(url.Values) 5726 form.Set("recovery_code", recoveryCode) 5727 form.Set("passcode", passcode) 5728 form.Set(csrfFormToken, csrfToken) 5729 5730 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5731 assert.NoError(t, err) 5732 setJWTCookieForReq(req, cookie) 5733 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5734 rr = executeRequest(req) 5735 assert.Equal(t, http.StatusOK, rr.Code) 5736 assert.Contains(t, rr.Body.String(), "Two factory authentication is not enabled") 5737 5738 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5739 assert.NoError(t, err) 5740 setJWTCookieForReq(req, cookie) 5741 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5742 rr = executeRequest(req) 5743 assert.Equal(t, http.StatusOK, rr.Code) 5744 assert.Contains(t, rr.Body.String(), "Two factory authentication is not enabled") 5745 5746 _, err = httpdtest.RemoveUser(user, http.StatusOK) 5747 assert.NoError(t, err) 5748 err = os.RemoveAll(user.GetHomeDir()) 5749 assert.NoError(t, err) 5750 5751 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 5752 assert.NoError(t, err) 5753 setJWTCookieForReq(req, cookie) 5754 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5755 rr = executeRequest(req) 5756 assert.Equal(t, http.StatusOK, rr.Code) 5757 assert.Contains(t, rr.Body.String(), "Invalid credentials") 5758 5759 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 5760 assert.NoError(t, err) 5761 setJWTCookieForReq(req, cookie) 5762 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 5763 rr = executeRequest(req) 5764 assert.Equal(t, http.StatusOK, rr.Code) 5765 assert.Contains(t, rr.Body.String(), "Invalid credentials") 5766 5767 req, err = http.NewRequest(http.MethodGet, webClientMFAPath, nil) 5768 assert.NoError(t, err) 5769 setJWTCookieForReq(req, authenticatedCookie) 5770 rr = executeRequest(req) 5771 checkResponseCode(t, http.StatusInternalServerError, rr) 5772} 5773 5774func TestSearchEvents(t *testing.T) { 5775 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 5776 assert.NoError(t, err) 5777 5778 req, err := http.NewRequest(http.MethodGet, fsEventsPath+"?limit=10&order=ASC", nil) 5779 assert.NoError(t, err) 5780 setBearerForReq(req, token) 5781 rr := executeRequest(req) 5782 checkResponseCode(t, http.StatusOK, rr) 5783 5784 // the test eventsearcher plugin returns error if start_timestamp < 0 5785 req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?start_timestamp=-1&end_timestamp=123456&statuses=1,2", nil) 5786 assert.NoError(t, err) 5787 setBearerForReq(req, token) 5788 rr = executeRequest(req) 5789 checkResponseCode(t, http.StatusInternalServerError, rr) 5790 5791 req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?limit=a", nil) 5792 assert.NoError(t, err) 5793 setBearerForReq(req, token) 5794 rr = executeRequest(req) 5795 checkResponseCode(t, http.StatusBadRequest, rr) 5796 5797 req, err = http.NewRequest(http.MethodGet, providerEventsPath, nil) 5798 assert.NoError(t, err) 5799 setBearerForReq(req, token) 5800 rr = executeRequest(req) 5801 checkResponseCode(t, http.StatusOK, rr) 5802 5803 // the test eventsearcher plugin returns error if start_timestamp < 0 5804 req, err = http.NewRequest(http.MethodGet, providerEventsPath+"?start_timestamp=-1", nil) 5805 assert.NoError(t, err) 5806 setBearerForReq(req, token) 5807 rr = executeRequest(req) 5808 checkResponseCode(t, http.StatusInternalServerError, rr) 5809 5810 req, err = http.NewRequest(http.MethodGet, providerEventsPath+"?limit=2000", nil) 5811 assert.NoError(t, err) 5812 setBearerForReq(req, token) 5813 rr = executeRequest(req) 5814 checkResponseCode(t, http.StatusBadRequest, rr) 5815 5816 req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?start_timestamp=a", nil) 5817 assert.NoError(t, err) 5818 setBearerForReq(req, token) 5819 rr = executeRequest(req) 5820 checkResponseCode(t, http.StatusBadRequest, rr) 5821 5822 req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?end_timestamp=a", nil) 5823 assert.NoError(t, err) 5824 setBearerForReq(req, token) 5825 rr = executeRequest(req) 5826 checkResponseCode(t, http.StatusBadRequest, rr) 5827 5828 req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?order=ASSC", nil) 5829 assert.NoError(t, err) 5830 setBearerForReq(req, token) 5831 rr = executeRequest(req) 5832 checkResponseCode(t, http.StatusBadRequest, rr) 5833 5834 req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?statuses=a,b", nil) 5835 assert.NoError(t, err) 5836 setBearerForReq(req, token) 5837 rr = executeRequest(req) 5838 checkResponseCode(t, http.StatusBadRequest, rr) 5839} 5840 5841func TestMFAErrors(t *testing.T) { 5842 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 5843 assert.NoError(t, err) 5844 assert.False(t, user.Filters.TOTPConfig.Enabled) 5845 userToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 5846 assert.NoError(t, err) 5847 adminToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 5848 assert.NoError(t, err) 5849 5850 // invalid config name 5851 totpReq := generateTOTPRequest{ 5852 ConfigName: "invalid config name", 5853 } 5854 asJSON, err := json.Marshal(totpReq) 5855 assert.NoError(t, err) 5856 req, err := http.NewRequest(http.MethodPost, userTOTPGeneratePath, bytes.NewBuffer(asJSON)) 5857 assert.NoError(t, err) 5858 setBearerForReq(req, userToken) 5859 rr := executeRequest(req) 5860 checkResponseCode(t, http.StatusBadRequest, rr) 5861 // invalid JSON 5862 invalidJSON := []byte("not a JSON") 5863 req, err = http.NewRequest(http.MethodPost, userTOTPGeneratePath, bytes.NewBuffer(invalidJSON)) 5864 assert.NoError(t, err) 5865 setBearerForReq(req, userToken) 5866 rr = executeRequest(req) 5867 checkResponseCode(t, http.StatusBadRequest, rr) 5868 5869 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(invalidJSON)) 5870 assert.NoError(t, err) 5871 setBearerForReq(req, userToken) 5872 rr = executeRequest(req) 5873 checkResponseCode(t, http.StatusBadRequest, rr) 5874 5875 req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(invalidJSON)) 5876 assert.NoError(t, err) 5877 setBearerForReq(req, adminToken) 5878 rr = executeRequest(req) 5879 checkResponseCode(t, http.StatusBadRequest, rr) 5880 5881 req, err = http.NewRequest(http.MethodPost, adminTOTPValidatePath, bytes.NewBuffer(invalidJSON)) 5882 assert.NoError(t, err) 5883 setBearerForReq(req, adminToken) 5884 rr = executeRequest(req) 5885 checkResponseCode(t, http.StatusBadRequest, rr) 5886 // invalid TOTP config name 5887 userTOTPConfig := sdk.TOTPConfig{ 5888 Enabled: true, 5889 ConfigName: "missing name", 5890 Secret: kms.NewPlainSecret(xid.New().String()), 5891 Protocols: []string{common.ProtocolSSH}, 5892 } 5893 asJSON, err = json.Marshal(userTOTPConfig) 5894 assert.NoError(t, err) 5895 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 5896 assert.NoError(t, err) 5897 setBearerForReq(req, userToken) 5898 rr = executeRequest(req) 5899 checkResponseCode(t, http.StatusBadRequest, rr) 5900 assert.Contains(t, rr.Body.String(), "totp: config name") 5901 // invalid TOTP secret 5902 userTOTPConfig = sdk.TOTPConfig{ 5903 Enabled: true, 5904 ConfigName: mfa.GetAvailableTOTPConfigNames()[0], 5905 Secret: nil, 5906 Protocols: []string{common.ProtocolSSH}, 5907 } 5908 asJSON, err = json.Marshal(userTOTPConfig) 5909 assert.NoError(t, err) 5910 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 5911 assert.NoError(t, err) 5912 setBearerForReq(req, userToken) 5913 rr = executeRequest(req) 5914 checkResponseCode(t, http.StatusBadRequest, rr) 5915 assert.Contains(t, rr.Body.String(), "totp: secret is mandatory") 5916 // no protocol 5917 userTOTPConfig = sdk.TOTPConfig{ 5918 Enabled: true, 5919 ConfigName: mfa.GetAvailableTOTPConfigNames()[0], 5920 Secret: kms.NewPlainSecret(xid.New().String()), 5921 Protocols: nil, 5922 } 5923 asJSON, err = json.Marshal(userTOTPConfig) 5924 assert.NoError(t, err) 5925 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 5926 assert.NoError(t, err) 5927 setBearerForReq(req, userToken) 5928 rr = executeRequest(req) 5929 checkResponseCode(t, http.StatusBadRequest, rr) 5930 assert.Contains(t, rr.Body.String(), "totp: specify at least one protocol") 5931 // invalid protocol 5932 userTOTPConfig = sdk.TOTPConfig{ 5933 Enabled: true, 5934 ConfigName: mfa.GetAvailableTOTPConfigNames()[0], 5935 Secret: kms.NewPlainSecret(xid.New().String()), 5936 Protocols: []string{common.ProtocolWebDAV}, 5937 } 5938 asJSON, err = json.Marshal(userTOTPConfig) 5939 assert.NoError(t, err) 5940 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 5941 assert.NoError(t, err) 5942 setBearerForReq(req, userToken) 5943 rr = executeRequest(req) 5944 checkResponseCode(t, http.StatusBadRequest, rr) 5945 assert.Contains(t, rr.Body.String(), "totp: invalid protocol") 5946 5947 adminTOTPConfig := dataprovider.TOTPConfig{ 5948 Enabled: true, 5949 ConfigName: "", 5950 Secret: kms.NewPlainSecret("secret"), 5951 } 5952 asJSON, err = json.Marshal(adminTOTPConfig) 5953 assert.NoError(t, err) 5954 req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON)) 5955 assert.NoError(t, err) 5956 setBearerForReq(req, adminToken) 5957 rr = executeRequest(req) 5958 checkResponseCode(t, http.StatusBadRequest, rr) 5959 assert.Contains(t, rr.Body.String(), "totp: config name is mandatory") 5960 5961 adminTOTPConfig = dataprovider.TOTPConfig{ 5962 Enabled: true, 5963 ConfigName: mfa.GetAvailableTOTPConfigNames()[0], 5964 Secret: nil, 5965 } 5966 asJSON, err = json.Marshal(adminTOTPConfig) 5967 assert.NoError(t, err) 5968 req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON)) 5969 assert.NoError(t, err) 5970 setBearerForReq(req, adminToken) 5971 rr = executeRequest(req) 5972 checkResponseCode(t, http.StatusBadRequest, rr) 5973 assert.Contains(t, rr.Body.String(), "totp: secret is mandatory") 5974 5975 // invalid TOTP secret status 5976 userTOTPConfig = sdk.TOTPConfig{ 5977 Enabled: true, 5978 ConfigName: mfa.GetAvailableTOTPConfigNames()[0], 5979 Secret: kms.NewSecret(kms.SecretStatusRedacted, "", "", ""), 5980 Protocols: []string{common.ProtocolSSH}, 5981 } 5982 asJSON, err = json.Marshal(userTOTPConfig) 5983 assert.NoError(t, err) 5984 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 5985 assert.NoError(t, err) 5986 setBearerForReq(req, userToken) 5987 rr = executeRequest(req) 5988 checkResponseCode(t, http.StatusBadRequest, rr) 5989 // previous secret will be preserved and we have no secret saved 5990 assert.Contains(t, rr.Body.String(), "totp: secret is mandatory") 5991 5992 req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON)) 5993 assert.NoError(t, err) 5994 setBearerForReq(req, adminToken) 5995 rr = executeRequest(req) 5996 checkResponseCode(t, http.StatusBadRequest, rr) 5997 assert.Contains(t, rr.Body.String(), "totp: secret is mandatory") 5998 5999 _, err = httpdtest.RemoveUser(user, http.StatusOK) 6000 assert.NoError(t, err) 6001 err = os.RemoveAll(user.GetHomeDir()) 6002 assert.NoError(t, err) 6003} 6004 6005func TestMFAInvalidSecret(t *testing.T) { 6006 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 6007 assert.NoError(t, err) 6008 6009 userToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 6010 assert.NoError(t, err) 6011 6012 user.Password = defaultPassword 6013 user.Filters.TOTPConfig = sdk.TOTPConfig{ 6014 Enabled: true, 6015 ConfigName: mfa.GetAvailableTOTPConfigNames()[0], 6016 Secret: kms.NewSecret(kms.SecretStatusSecretBox, "payload", "key", user.Username), 6017 Protocols: []string{common.ProtocolSSH, common.ProtocolHTTP}, 6018 } 6019 user.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, sdk.RecoveryCode{ 6020 Used: false, 6021 Secret: kms.NewSecret(kms.SecretStatusSecretBox, "payload", "key", user.Username), 6022 }) 6023 err = dataprovider.UpdateUser(&user, "", "") 6024 assert.NoError(t, err) 6025 6026 req, err := http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil) 6027 assert.NoError(t, err) 6028 setBearerForReq(req, userToken) 6029 rr := executeRequest(req) 6030 checkResponseCode(t, http.StatusInternalServerError, rr) 6031 assert.Contains(t, rr.Body.String(), "Unable to decrypt recovery codes") 6032 6033 csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath) 6034 assert.NoError(t, err) 6035 form := getLoginForm(defaultUsername, defaultPassword, csrfToken) 6036 req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 6037 assert.NoError(t, err) 6038 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 6039 rr = executeRequest(req) 6040 assert.Equal(t, http.StatusFound, rr.Code) 6041 assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location")) 6042 cookie, err := getCookieFromResponse(rr) 6043 assert.NoError(t, err) 6044 form = make(url.Values) 6045 form.Set(csrfFormToken, csrfToken) 6046 form.Set("passcode", "123456") 6047 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 6048 assert.NoError(t, err) 6049 setJWTCookieForReq(req, cookie) 6050 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 6051 rr = executeRequest(req) 6052 assert.Equal(t, http.StatusInternalServerError, rr.Code) 6053 6054 form = make(url.Values) 6055 form.Set(csrfFormToken, csrfToken) 6056 form.Set("recovery_code", "RC-123456") 6057 req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 6058 assert.NoError(t, err) 6059 setJWTCookieForReq(req, cookie) 6060 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 6061 rr = executeRequest(req) 6062 assert.Equal(t, http.StatusInternalServerError, rr.Code) 6063 6064 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil) 6065 assert.NoError(t, err) 6066 req.Header.Set("X-SFTPGO-OTP", "authcode") 6067 req.SetBasicAuth(defaultUsername, defaultPassword) 6068 resp, err := httpclient.GetHTTPClient().Do(req) 6069 assert.NoError(t, err) 6070 assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) 6071 err = resp.Body.Close() 6072 assert.NoError(t, err) 6073 6074 _, err = httpdtest.RemoveUser(user, http.StatusOK) 6075 assert.NoError(t, err) 6076 err = os.RemoveAll(user.GetHomeDir()) 6077 assert.NoError(t, err) 6078 6079 admin := getTestAdmin() 6080 admin.Username = altAdminUsername 6081 admin.Password = altAdminPassword 6082 admin, _, err = httpdtest.AddAdmin(admin, http.StatusCreated) 6083 assert.NoError(t, err) 6084 6085 admin.Password = altAdminPassword 6086 admin.Filters.TOTPConfig = dataprovider.TOTPConfig{ 6087 Enabled: true, 6088 ConfigName: mfa.GetAvailableTOTPConfigNames()[0], 6089 Secret: kms.NewSecret(kms.SecretStatusSecretBox, "payload", "key", user.Username), 6090 } 6091 admin.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, sdk.RecoveryCode{ 6092 Used: false, 6093 Secret: kms.NewSecret(kms.SecretStatusSecretBox, "payload", "key", user.Username), 6094 }) 6095 err = dataprovider.UpdateAdmin(&admin, "", "") 6096 assert.NoError(t, err) 6097 6098 csrfToken, err = getCSRFToken(httpBaseURL + webLoginPath) 6099 assert.NoError(t, err) 6100 form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken) 6101 req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 6102 assert.NoError(t, err) 6103 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 6104 rr = executeRequest(req) 6105 assert.Equal(t, http.StatusFound, rr.Code) 6106 assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location")) 6107 cookie, err = getCookieFromResponse(rr) 6108 assert.NoError(t, err) 6109 form = make(url.Values) 6110 form.Set(csrfFormToken, csrfToken) 6111 form.Set("passcode", "123456") 6112 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode()))) 6113 assert.NoError(t, err) 6114 setJWTCookieForReq(req, cookie) 6115 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 6116 rr = executeRequest(req) 6117 assert.Equal(t, http.StatusInternalServerError, rr.Code) 6118 6119 form = make(url.Values) 6120 form.Set(csrfFormToken, csrfToken) 6121 form.Set("recovery_code", "RC-123456") 6122 req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode()))) 6123 assert.NoError(t, err) 6124 setJWTCookieForReq(req, cookie) 6125 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 6126 rr = executeRequest(req) 6127 assert.Equal(t, http.StatusInternalServerError, rr.Code) 6128 6129 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil) 6130 assert.NoError(t, err) 6131 req.Header.Set("X-SFTPGO-OTP", "auth-code") 6132 req.SetBasicAuth(altAdminUsername, altAdminPassword) 6133 resp, err = httpclient.GetHTTPClient().Do(req) 6134 assert.NoError(t, err) 6135 assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) 6136 err = resp.Body.Close() 6137 assert.NoError(t, err) 6138 6139 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 6140 assert.NoError(t, err) 6141} 6142 6143func TestWebUserTOTP(t *testing.T) { 6144 u := getTestUser() 6145 // TOTPConfig will be ignored on add 6146 u.Filters.TOTPConfig = sdk.TOTPConfig{ 6147 Enabled: true, 6148 ConfigName: "", 6149 Secret: kms.NewEmptySecret(), 6150 Protocols: []string{common.ProtocolSSH}, 6151 } 6152 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 6153 assert.NoError(t, err) 6154 assert.False(t, user.Filters.TOTPConfig.Enabled) 6155 token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 6156 assert.NoError(t, err) 6157 6158 req, err := http.NewRequest(http.MethodGet, userTOTPConfigsPath, nil) 6159 assert.NoError(t, err) 6160 setBearerForReq(req, token) 6161 rr := executeRequest(req) 6162 checkResponseCode(t, http.StatusOK, rr) 6163 var configs []mfa.TOTPConfig 6164 err = json.Unmarshal(rr.Body.Bytes(), &configs) 6165 assert.NoError(t, err, rr.Body.String()) 6166 assert.Len(t, configs, len(mfa.GetAvailableTOTPConfigs())) 6167 totpConfig := configs[0] 6168 totpReq := generateTOTPRequest{ 6169 ConfigName: totpConfig.Name, 6170 } 6171 asJSON, err := json.Marshal(totpReq) 6172 assert.NoError(t, err) 6173 req, err = http.NewRequest(http.MethodPost, userTOTPGeneratePath, bytes.NewBuffer(asJSON)) 6174 assert.NoError(t, err) 6175 setBearerForReq(req, token) 6176 rr = executeRequest(req) 6177 checkResponseCode(t, http.StatusOK, rr) 6178 var totpGenResp generateTOTPResponse 6179 err = json.Unmarshal(rr.Body.Bytes(), &totpGenResp) 6180 assert.NoError(t, err) 6181 assert.NotEmpty(t, totpGenResp.Secret) 6182 assert.NotEmpty(t, totpGenResp.QRCode) 6183 6184 passcode, err := generateTOTPPasscode(totpGenResp.Secret) 6185 assert.NoError(t, err) 6186 validateReq := validateTOTPRequest{ 6187 ConfigName: totpGenResp.ConfigName, 6188 Passcode: passcode, 6189 Secret: totpGenResp.Secret, 6190 } 6191 asJSON, err = json.Marshal(validateReq) 6192 assert.NoError(t, err) 6193 req, err = http.NewRequest(http.MethodPost, userTOTPValidatePath, bytes.NewBuffer(asJSON)) 6194 assert.NoError(t, err) 6195 setBearerForReq(req, token) 6196 rr = executeRequest(req) 6197 checkResponseCode(t, http.StatusOK, rr) 6198 // the same passcode cannot be reused 6199 req, err = http.NewRequest(http.MethodPost, userTOTPValidatePath, bytes.NewBuffer(asJSON)) 6200 assert.NoError(t, err) 6201 setBearerForReq(req, token) 6202 rr = executeRequest(req) 6203 checkResponseCode(t, http.StatusBadRequest, rr) 6204 assert.Contains(t, rr.Body.String(), "this passcode was already used") 6205 6206 userTOTPConfig := sdk.TOTPConfig{ 6207 Enabled: true, 6208 ConfigName: totpGenResp.ConfigName, 6209 Secret: kms.NewPlainSecret(totpGenResp.Secret), 6210 Protocols: []string{common.ProtocolSSH}, 6211 } 6212 asJSON, err = json.Marshal(userTOTPConfig) 6213 assert.NoError(t, err) 6214 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 6215 assert.NoError(t, err) 6216 setBearerForReq(req, token) 6217 rr = executeRequest(req) 6218 checkResponseCode(t, http.StatusOK, rr) 6219 6220 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 6221 assert.NoError(t, err) 6222 totpCfg := user.Filters.TOTPConfig 6223 assert.True(t, totpCfg.Enabled) 6224 secretPayload := totpCfg.Secret.GetPayload() 6225 assert.Equal(t, totpGenResp.ConfigName, totpCfg.ConfigName) 6226 assert.Empty(t, totpCfg.Secret.GetKey()) 6227 assert.Empty(t, totpCfg.Secret.GetAdditionalData()) 6228 assert.NotEmpty(t, secretPayload) 6229 assert.Equal(t, kms.SecretStatusSecretBox, totpCfg.Secret.GetStatus()) 6230 assert.Len(t, totpCfg.Protocols, 1) 6231 assert.Contains(t, totpCfg.Protocols, common.ProtocolSSH) 6232 // update protocols only 6233 userTOTPConfig = sdk.TOTPConfig{ 6234 Protocols: []string{common.ProtocolSSH, common.ProtocolFTP}, 6235 Secret: kms.NewEmptySecret(), 6236 } 6237 asJSON, err = json.Marshal(userTOTPConfig) 6238 assert.NoError(t, err) 6239 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 6240 assert.NoError(t, err) 6241 setBearerForReq(req, token) 6242 rr = executeRequest(req) 6243 checkResponseCode(t, http.StatusOK, rr) 6244 6245 // update the user, TOTP should not be affected 6246 user.Filters.TOTPConfig = sdk.TOTPConfig{ 6247 Enabled: false, 6248 Secret: kms.NewEmptySecret(), 6249 } 6250 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 6251 assert.NoError(t, err) 6252 6253 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 6254 assert.NoError(t, err) 6255 assert.True(t, user.Filters.TOTPConfig.Enabled) 6256 assert.Equal(t, totpCfg.ConfigName, user.Filters.TOTPConfig.ConfigName) 6257 assert.Empty(t, user.Filters.TOTPConfig.Secret.GetKey()) 6258 assert.Empty(t, user.Filters.TOTPConfig.Secret.GetAdditionalData()) 6259 assert.Equal(t, secretPayload, user.Filters.TOTPConfig.Secret.GetPayload()) 6260 assert.Equal(t, kms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) 6261 assert.Len(t, user.Filters.TOTPConfig.Protocols, 2) 6262 assert.Contains(t, user.Filters.TOTPConfig.Protocols, common.ProtocolSSH) 6263 assert.Contains(t, user.Filters.TOTPConfig.Protocols, common.ProtocolFTP) 6264 6265 req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil) 6266 assert.NoError(t, err) 6267 setBearerForReq(req, token) 6268 rr = executeRequest(req) 6269 checkResponseCode(t, http.StatusOK, rr) 6270 var recCodes []recoveryCode 6271 err = json.Unmarshal(rr.Body.Bytes(), &recCodes) 6272 assert.NoError(t, err) 6273 assert.Len(t, recCodes, 12) 6274 // regenerate recovery codes 6275 req, err = http.NewRequest(http.MethodPost, user2FARecoveryCodesPath, nil) 6276 assert.NoError(t, err) 6277 setBearerForReq(req, token) 6278 rr = executeRequest(req) 6279 checkResponseCode(t, http.StatusOK, rr) 6280 // check that recovery codes are different 6281 req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil) 6282 assert.NoError(t, err) 6283 setBearerForReq(req, token) 6284 rr = executeRequest(req) 6285 checkResponseCode(t, http.StatusOK, rr) 6286 var newRecCodes []recoveryCode 6287 err = json.Unmarshal(rr.Body.Bytes(), &newRecCodes) 6288 assert.NoError(t, err) 6289 assert.Len(t, newRecCodes, 12) 6290 assert.NotEqual(t, recCodes, newRecCodes) 6291 // disable 2FA, the update user API should not work 6292 adminToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 6293 assert.NoError(t, err) 6294 user.Filters.TOTPConfig.Enabled = false 6295 user.Filters.RecoveryCodes = nil 6296 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 6297 assert.NoError(t, err) 6298 assert.Equal(t, defaultUsername, user.Username) 6299 assert.True(t, user.Filters.TOTPConfig.Enabled) 6300 assert.Len(t, user.Filters.RecoveryCodes, 12) 6301 // use the dedicated API 6302 req, err = http.NewRequest(http.MethodPut, userPath+"/"+defaultUsername+"/2fa/disable", nil) 6303 assert.NoError(t, err) 6304 setBearerForReq(req, adminToken) 6305 rr = executeRequest(req) 6306 checkResponseCode(t, http.StatusOK, rr) 6307 user, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusOK) 6308 assert.NoError(t, err) 6309 assert.False(t, user.Filters.TOTPConfig.Enabled) 6310 assert.Len(t, user.Filters.RecoveryCodes, 0) 6311 6312 _, err = httpdtest.RemoveUser(user, http.StatusOK) 6313 assert.NoError(t, err) 6314 err = os.RemoveAll(user.GetHomeDir()) 6315 assert.NoError(t, err) 6316 6317 req, err = http.NewRequest(http.MethodPut, userPath+"/"+defaultUsername+"/2fa/disable", nil) 6318 assert.NoError(t, err) 6319 setBearerForReq(req, adminToken) 6320 rr = executeRequest(req) 6321 checkResponseCode(t, http.StatusNotFound, rr) 6322 6323 req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil) 6324 assert.NoError(t, err) 6325 setBearerForReq(req, token) 6326 rr = executeRequest(req) 6327 checkResponseCode(t, http.StatusNotFound, rr) 6328 6329 req, err = http.NewRequest(http.MethodPost, user2FARecoveryCodesPath, nil) 6330 assert.NoError(t, err) 6331 setBearerForReq(req, token) 6332 rr = executeRequest(req) 6333 checkResponseCode(t, http.StatusNotFound, rr) 6334 6335 req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON)) 6336 assert.NoError(t, err) 6337 setBearerForReq(req, token) 6338 rr = executeRequest(req) 6339 checkResponseCode(t, http.StatusNotFound, rr) 6340} 6341 6342func TestWebAPIChangeUserProfileMock(t *testing.T) { 6343 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 6344 assert.NoError(t, err) 6345 assert.False(t, user.Filters.AllowAPIKeyAuth) 6346 token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 6347 assert.NoError(t, err) 6348 // invalid json 6349 req, err := http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer([]byte("{"))) 6350 assert.NoError(t, err) 6351 setBearerForReq(req, token) 6352 rr := executeRequest(req) 6353 checkResponseCode(t, http.StatusBadRequest, rr) 6354 6355 email := "userapi@example.com" 6356 description := "user API description" 6357 profileReq := make(map[string]interface{}) 6358 profileReq["allow_api_key_auth"] = true 6359 profileReq["email"] = email 6360 profileReq["description"] = description 6361 profileReq["public_keys"] = []string{testPubKey, testPubKey1} 6362 asJSON, err := json.Marshal(profileReq) 6363 assert.NoError(t, err) 6364 req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON)) 6365 assert.NoError(t, err) 6366 setBearerForReq(req, token) 6367 rr = executeRequest(req) 6368 checkResponseCode(t, http.StatusOK, rr) 6369 6370 profileReq = make(map[string]interface{}) 6371 req, err = http.NewRequest(http.MethodGet, userProfilePath, nil) 6372 assert.NoError(t, err) 6373 setBearerForReq(req, token) 6374 rr = executeRequest(req) 6375 checkResponseCode(t, http.StatusOK, rr) 6376 err = json.Unmarshal(rr.Body.Bytes(), &profileReq) 6377 assert.NoError(t, err) 6378 assert.Equal(t, email, profileReq["email"].(string)) 6379 assert.Equal(t, description, profileReq["description"].(string)) 6380 assert.True(t, profileReq["allow_api_key_auth"].(bool)) 6381 assert.Len(t, profileReq["public_keys"].([]interface{}), 2) 6382 // set an invalid email 6383 profileReq = make(map[string]interface{}) 6384 profileReq["email"] = "notavalidemail" 6385 asJSON, err = json.Marshal(profileReq) 6386 assert.NoError(t, err) 6387 req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON)) 6388 assert.NoError(t, err) 6389 setBearerForReq(req, token) 6390 rr = executeRequest(req) 6391 checkResponseCode(t, http.StatusBadRequest, rr) 6392 assert.Contains(t, rr.Body.String(), "Validation error: email") 6393 // set an invalid public key 6394 profileReq = make(map[string]interface{}) 6395 profileReq["public_keys"] = []string{"not a public key"} 6396 asJSON, err = json.Marshal(profileReq) 6397 assert.NoError(t, err) 6398 req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON)) 6399 assert.NoError(t, err) 6400 setBearerForReq(req, token) 6401 rr = executeRequest(req) 6402 checkResponseCode(t, http.StatusBadRequest, rr) 6403 assert.Contains(t, rr.Body.String(), "Validation error: could not parse key") 6404 6405 user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientPubKeyChangeDisabled} 6406 user.Email = email 6407 user.Description = description 6408 user.Filters.AllowAPIKeyAuth = true 6409 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 6410 assert.NoError(t, err) 6411 token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 6412 assert.NoError(t, err) 6413 6414 profileReq = make(map[string]interface{}) 6415 profileReq["allow_api_key_auth"] = false 6416 profileReq["email"] = email 6417 profileReq["description"] = description + "_mod" 6418 profileReq["public_keys"] = []string{testPubKey} 6419 asJSON, err = json.Marshal(profileReq) 6420 assert.NoError(t, err) 6421 req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON)) 6422 assert.NoError(t, err) 6423 setBearerForReq(req, token) 6424 rr = executeRequest(req) 6425 checkResponseCode(t, http.StatusOK, rr) 6426 assert.Contains(t, rr.Body.String(), "Profile updated") 6427 // check that api key auth and public keys were not changed 6428 profileReq = make(map[string]interface{}) 6429 req, err = http.NewRequest(http.MethodGet, userProfilePath, nil) 6430 assert.NoError(t, err) 6431 setBearerForReq(req, token) 6432 rr = executeRequest(req) 6433 checkResponseCode(t, http.StatusOK, rr) 6434 err = json.Unmarshal(rr.Body.Bytes(), &profileReq) 6435 assert.NoError(t, err) 6436 assert.Equal(t, email, profileReq["email"].(string)) 6437 assert.Equal(t, description+"_mod", profileReq["description"].(string)) 6438 assert.True(t, profileReq["allow_api_key_auth"].(bool)) 6439 assert.Len(t, profileReq["public_keys"].([]interface{}), 2) 6440 6441 user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientInfoChangeDisabled} 6442 user.Description = description + "_mod" 6443 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 6444 assert.NoError(t, err) 6445 token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 6446 assert.NoError(t, err) 6447 6448 profileReq = make(map[string]interface{}) 6449 profileReq["allow_api_key_auth"] = false 6450 profileReq["email"] = "newemail@apiuser.com" 6451 profileReq["description"] = description 6452 profileReq["public_keys"] = []string{testPubKey} 6453 asJSON, err = json.Marshal(profileReq) 6454 assert.NoError(t, err) 6455 req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON)) 6456 assert.NoError(t, err) 6457 setBearerForReq(req, token) 6458 rr = executeRequest(req) 6459 checkResponseCode(t, http.StatusOK, rr) 6460 profileReq = make(map[string]interface{}) 6461 req, err = http.NewRequest(http.MethodGet, userProfilePath, nil) 6462 assert.NoError(t, err) 6463 setBearerForReq(req, token) 6464 rr = executeRequest(req) 6465 checkResponseCode(t, http.StatusOK, rr) 6466 err = json.Unmarshal(rr.Body.Bytes(), &profileReq) 6467 assert.NoError(t, err) 6468 assert.Equal(t, email, profileReq["email"].(string)) 6469 assert.Equal(t, description+"_mod", profileReq["description"].(string)) 6470 assert.True(t, profileReq["allow_api_key_auth"].(bool)) 6471 assert.Len(t, profileReq["public_keys"].([]interface{}), 1) 6472 // finally disable all profile permissions 6473 user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientInfoChangeDisabled, 6474 sdk.WebClientPubKeyChangeDisabled} 6475 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 6476 assert.NoError(t, err) 6477 req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON)) 6478 assert.NoError(t, err) 6479 setBearerForReq(req, token) 6480 rr = executeRequest(req) 6481 checkResponseCode(t, http.StatusForbidden, rr) 6482 assert.Contains(t, rr.Body.String(), "You are not allowed to change anything") 6483 6484 _, err = httpdtest.RemoveUser(user, http.StatusOK) 6485 assert.NoError(t, err) 6486 err = os.RemoveAll(user.GetHomeDir()) 6487 assert.NoError(t, err) 6488 6489 req, err = http.NewRequest(http.MethodGet, userProfilePath, nil) 6490 assert.NoError(t, err) 6491 setBearerForReq(req, token) 6492 rr = executeRequest(req) 6493 checkResponseCode(t, http.StatusNotFound, rr) 6494 6495 req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON)) 6496 assert.NoError(t, err) 6497 setBearerForReq(req, token) 6498 rr = executeRequest(req) 6499 checkResponseCode(t, http.StatusNotFound, rr) 6500} 6501 6502func TestWebAPIChangeUserPwdMock(t *testing.T) { 6503 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 6504 assert.NoError(t, err) 6505 token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 6506 assert.NoError(t, err) 6507 // invalid json 6508 req, err := http.NewRequest(http.MethodPut, userPwdPath, bytes.NewBuffer([]byte("{"))) 6509 assert.NoError(t, err) 6510 setBearerForReq(req, token) 6511 rr := executeRequest(req) 6512 checkResponseCode(t, http.StatusBadRequest, rr) 6513 6514 pwd := make(map[string]string) 6515 pwd["current_password"] = defaultPassword 6516 pwd["new_password"] = defaultPassword 6517 asJSON, err := json.Marshal(pwd) 6518 assert.NoError(t, err) 6519 req, err = http.NewRequest(http.MethodPut, userPwdPath, bytes.NewBuffer(asJSON)) 6520 assert.NoError(t, err) 6521 setBearerForReq(req, token) 6522 rr = executeRequest(req) 6523 checkResponseCode(t, http.StatusBadRequest, rr) 6524 assert.Contains(t, rr.Body.String(), "the new password must be different from the current one") 6525 6526 pwd["new_password"] = altAdminPassword 6527 asJSON, err = json.Marshal(pwd) 6528 assert.NoError(t, err) 6529 req, err = http.NewRequest(http.MethodPut, userPwdPath, bytes.NewBuffer(asJSON)) 6530 assert.NoError(t, err) 6531 setBearerForReq(req, token) 6532 rr = executeRequest(req) 6533 checkResponseCode(t, http.StatusOK, rr) 6534 _, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 6535 assert.Error(t, err) 6536 token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, altAdminPassword) 6537 assert.NoError(t, err) 6538 assert.NotEmpty(t, token) 6539 6540 // remove the change password permission 6541 user.Filters.WebClient = []string{sdk.WebClientPasswordChangeDisabled} 6542 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 6543 assert.NoError(t, err) 6544 assert.Len(t, user.Filters.WebClient, 1) 6545 assert.Contains(t, user.Filters.WebClient, sdk.WebClientPasswordChangeDisabled) 6546 6547 token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, altAdminPassword) 6548 assert.NoError(t, err) 6549 assert.NotEmpty(t, token) 6550 6551 pwd["current_password"] = altAdminPassword 6552 pwd["new_password"] = defaultPassword 6553 asJSON, err = json.Marshal(pwd) 6554 assert.NoError(t, err) 6555 req, err = http.NewRequest(http.MethodPut, userPwdPath, bytes.NewBuffer(asJSON)) 6556 assert.NoError(t, err) 6557 setBearerForReq(req, token) 6558 rr = executeRequest(req) 6559 checkResponseCode(t, http.StatusForbidden, rr) 6560 6561 _, err = httpdtest.RemoveUser(user, http.StatusOK) 6562 assert.NoError(t, err) 6563 err = os.RemoveAll(user.GetHomeDir()) 6564 assert.NoError(t, err) 6565} 6566 6567func TestLoginInvalidPasswordMock(t *testing.T) { 6568 _, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass+"1") 6569 assert.Error(t, err) 6570 // now a login with no credentials 6571 req, _ := http.NewRequest(http.MethodGet, "/api/v2/token", nil) 6572 rr := executeRequest(req) 6573 assert.Equal(t, http.StatusUnauthorized, rr.Code) 6574} 6575 6576func TestWebAPIChangeAdminProfileMock(t *testing.T) { 6577 admin := getTestAdmin() 6578 admin.Username = altAdminUsername 6579 admin.Password = altAdminPassword 6580 admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) 6581 assert.NoError(t, err) 6582 assert.False(t, admin.Filters.AllowAPIKeyAuth) 6583 6584 token, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword) 6585 assert.NoError(t, err) 6586 // invalid json 6587 req, err := http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer([]byte("{"))) 6588 assert.NoError(t, err) 6589 setBearerForReq(req, token) 6590 rr := executeRequest(req) 6591 checkResponseCode(t, http.StatusBadRequest, rr) 6592 6593 email := "adminapi@example.com" 6594 description := "admin API description" 6595 profileReq := make(map[string]interface{}) 6596 profileReq["allow_api_key_auth"] = true 6597 profileReq["email"] = email 6598 profileReq["description"] = description 6599 asJSON, err := json.Marshal(profileReq) 6600 assert.NoError(t, err) 6601 req, err = http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer(asJSON)) 6602 assert.NoError(t, err) 6603 setBearerForReq(req, token) 6604 rr = executeRequest(req) 6605 checkResponseCode(t, http.StatusOK, rr) 6606 assert.Contains(t, rr.Body.String(), "Profile updated") 6607 6608 profileReq = make(map[string]interface{}) 6609 req, err = http.NewRequest(http.MethodGet, adminProfilePath, nil) 6610 assert.NoError(t, err) 6611 setBearerForReq(req, token) 6612 rr = executeRequest(req) 6613 checkResponseCode(t, http.StatusOK, rr) 6614 err = json.Unmarshal(rr.Body.Bytes(), &profileReq) 6615 assert.NoError(t, err) 6616 assert.Equal(t, email, profileReq["email"].(string)) 6617 assert.Equal(t, description, profileReq["description"].(string)) 6618 assert.True(t, profileReq["allow_api_key_auth"].(bool)) 6619 // set an invalid email 6620 profileReq["email"] = "admin_invalid_email" 6621 asJSON, err = json.Marshal(profileReq) 6622 assert.NoError(t, err) 6623 req, err = http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer(asJSON)) 6624 assert.NoError(t, err) 6625 setBearerForReq(req, token) 6626 rr = executeRequest(req) 6627 checkResponseCode(t, http.StatusBadRequest, rr) 6628 assert.Contains(t, rr.Body.String(), "Validation error: email") 6629 6630 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 6631 assert.NoError(t, err) 6632 6633 req, err = http.NewRequest(http.MethodGet, adminProfilePath, nil) 6634 assert.NoError(t, err) 6635 setBearerForReq(req, token) 6636 rr = executeRequest(req) 6637 checkResponseCode(t, http.StatusNotFound, rr) 6638 6639 req, err = http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer(asJSON)) 6640 assert.NoError(t, err) 6641 setBearerForReq(req, token) 6642 rr = executeRequest(req) 6643 checkResponseCode(t, http.StatusNotFound, rr) 6644} 6645 6646func TestChangeAdminPwdMock(t *testing.T) { 6647 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 6648 assert.NoError(t, err) 6649 admin := getTestAdmin() 6650 admin.Username = altAdminUsername 6651 admin.Password = altAdminPassword 6652 admin.Permissions = []string{dataprovider.PermAdminAddUsers, dataprovider.PermAdminDeleteUsers} 6653 asJSON, err := json.Marshal(admin) 6654 assert.NoError(t, err) 6655 req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON)) 6656 setBearerForReq(req, token) 6657 rr := executeRequest(req) 6658 checkResponseCode(t, http.StatusCreated, rr) 6659 6660 altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword) 6661 assert.NoError(t, err) 6662 user := getTestUser() 6663 userAsJSON := getUserAsJSON(t, user) 6664 req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 6665 setBearerForReq(req, altToken) 6666 rr = executeRequest(req) 6667 checkResponseCode(t, http.StatusCreated, rr) 6668 6669 req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON)) 6670 setBearerForReq(req, altToken) 6671 rr = executeRequest(req) 6672 checkResponseCode(t, http.StatusForbidden, rr) 6673 6674 pwd := make(map[string]string) 6675 pwd["current_password"] = altAdminPassword 6676 pwd["new_password"] = defaultTokenAuthPass 6677 asJSON, err = json.Marshal(pwd) 6678 assert.NoError(t, err) 6679 req, _ = http.NewRequest(http.MethodPut, adminPwdPath, bytes.NewBuffer(asJSON)) 6680 setBearerForReq(req, altToken) 6681 rr = executeRequest(req) 6682 checkResponseCode(t, http.StatusOK, rr) 6683 6684 _, err = getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword) 6685 assert.Error(t, err) 6686 6687 altToken, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass) 6688 assert.NoError(t, err) 6689 req, _ = http.NewRequest(http.MethodPut, adminPwdPath, bytes.NewBuffer(asJSON)) 6690 setBearerForReq(req, altToken) 6691 rr = executeRequest(req) 6692 checkResponseCode(t, http.StatusBadRequest, rr) // current password does not match 6693 6694 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 6695 setBearerForReq(req, altToken) 6696 rr = executeRequest(req) 6697 checkResponseCode(t, http.StatusOK, rr) 6698 6699 req, _ = http.NewRequest(http.MethodDelete, path.Join(adminPath, altAdminUsername), nil) 6700 setBearerForReq(req, token) 6701 rr = executeRequest(req) 6702 checkResponseCode(t, http.StatusOK, rr) 6703} 6704 6705func TestUpdateAdminMock(t *testing.T) { 6706 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 6707 assert.NoError(t, err) 6708 _, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass) 6709 assert.Error(t, err) 6710 admin := getTestAdmin() 6711 admin.Username = altAdminUsername 6712 admin.Permissions = []string{dataprovider.PermAdminManageAdmins} 6713 asJSON, err := json.Marshal(admin) 6714 assert.NoError(t, err) 6715 req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON)) 6716 setBearerForReq(req, token) 6717 rr := executeRequest(req) 6718 checkResponseCode(t, http.StatusCreated, rr) 6719 _, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass) 6720 assert.NoError(t, err) 6721 6722 req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, "abc"), bytes.NewBuffer(asJSON)) 6723 setBearerForReq(req, token) 6724 rr = executeRequest(req) 6725 checkResponseCode(t, http.StatusNotFound, rr) 6726 req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, altAdminUsername), bytes.NewBuffer([]byte("no json"))) 6727 setBearerForReq(req, token) 6728 rr = executeRequest(req) 6729 checkResponseCode(t, http.StatusBadRequest, rr) 6730 admin.Permissions = nil 6731 asJSON, err = json.Marshal(admin) 6732 assert.NoError(t, err) 6733 req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, altAdminUsername), bytes.NewBuffer(asJSON)) 6734 setBearerForReq(req, token) 6735 rr = executeRequest(req) 6736 checkResponseCode(t, http.StatusBadRequest, rr) 6737 admin = getTestAdmin() 6738 admin.Status = 0 6739 asJSON, err = json.Marshal(admin) 6740 assert.NoError(t, err) 6741 req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, defaultTokenAuthUser), bytes.NewBuffer(asJSON)) 6742 setBearerForReq(req, token) 6743 rr = executeRequest(req) 6744 checkResponseCode(t, http.StatusBadRequest, rr) 6745 admin.Status = 1 6746 admin.Permissions = []string{dataprovider.PermAdminAddUsers} 6747 asJSON, err = json.Marshal(admin) 6748 assert.NoError(t, err) 6749 req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, defaultTokenAuthUser), bytes.NewBuffer(asJSON)) 6750 setBearerForReq(req, token) 6751 rr = executeRequest(req) 6752 checkResponseCode(t, http.StatusBadRequest, rr) 6753 6754 altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass) 6755 assert.NoError(t, err) 6756 admin.Password = "" // it must remain unchanged 6757 admin.Permissions = []string{dataprovider.PermAdminManageAdmins, dataprovider.PermAdminCloseConnections} 6758 asJSON, err = json.Marshal(admin) 6759 assert.NoError(t, err) 6760 req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, altAdminUsername), bytes.NewBuffer(asJSON)) 6761 setBearerForReq(req, altToken) 6762 rr = executeRequest(req) 6763 checkResponseCode(t, http.StatusOK, rr) 6764 6765 _, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass) 6766 assert.NoError(t, err) 6767 6768 req, _ = http.NewRequest(http.MethodDelete, path.Join(adminPath, altAdminUsername), nil) 6769 setBearerForReq(req, token) 6770 rr = executeRequest(req) 6771 checkResponseCode(t, http.StatusOK, rr) 6772} 6773 6774func TestAdminLastLoginWithAPIKey(t *testing.T) { 6775 admin := getTestAdmin() 6776 admin.Username = altAdminUsername 6777 admin.Filters.AllowAPIKeyAuth = true 6778 admin, resp, err := httpdtest.AddAdmin(admin, http.StatusCreated) 6779 assert.NoError(t, err, string(resp)) 6780 assert.Equal(t, int64(0), admin.LastLogin) 6781 6782 apiKey := dataprovider.APIKey{ 6783 Name: "admin API key", 6784 Scope: dataprovider.APIKeyScopeAdmin, 6785 Admin: altAdminUsername, 6786 LastUseAt: 123, 6787 } 6788 6789 apiKey, resp, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated) 6790 assert.NoError(t, err, string(resp)) 6791 assert.Equal(t, int64(0), apiKey.LastUseAt) 6792 6793 req, err := http.NewRequest(http.MethodGet, versionPath, nil) 6794 assert.NoError(t, err) 6795 setAPIKeyForReq(req, apiKey.Key, admin.Username) 6796 rr := executeRequest(req) 6797 checkResponseCode(t, http.StatusOK, rr) 6798 6799 admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK) 6800 assert.NoError(t, err) 6801 assert.Greater(t, admin.LastLogin, int64(0)) 6802 6803 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 6804 assert.NoError(t, err) 6805} 6806 6807func TestUserLastLoginWithAPIKey(t *testing.T) { 6808 user := getTestUser() 6809 user.Filters.AllowAPIKeyAuth = true 6810 user, resp, err := httpdtest.AddUser(user, http.StatusCreated) 6811 assert.NoError(t, err, string(resp)) 6812 assert.Equal(t, int64(0), user.LastLogin) 6813 6814 apiKey := dataprovider.APIKey{ 6815 Name: "user API key", 6816 Scope: dataprovider.APIKeyScopeUser, 6817 User: user.Username, 6818 } 6819 6820 apiKey, resp, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated) 6821 assert.NoError(t, err, string(resp)) 6822 6823 req, err := http.NewRequest(http.MethodGet, userDirsPath, nil) 6824 assert.NoError(t, err) 6825 setAPIKeyForReq(req, apiKey.Key, "") 6826 rr := executeRequest(req) 6827 checkResponseCode(t, http.StatusOK, rr) 6828 6829 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 6830 assert.NoError(t, err) 6831 assert.Greater(t, user.LastLogin, int64(0)) 6832 6833 _, err = httpdtest.RemoveUser(user, http.StatusOK) 6834 assert.NoError(t, err) 6835 err = os.RemoveAll(user.GetHomeDir()) 6836 assert.NoError(t, err) 6837} 6838 6839func TestAdminHandlingWithAPIKeys(t *testing.T) { 6840 sysAdmin, _, err := httpdtest.GetAdminByUsername(defaultTokenAuthUser, http.StatusOK) 6841 assert.NoError(t, err) 6842 sysAdmin.Filters.AllowAPIKeyAuth = true 6843 sysAdmin, _, err = httpdtest.UpdateAdmin(sysAdmin, http.StatusOK) 6844 assert.NoError(t, err) 6845 6846 apiKey := dataprovider.APIKey{ 6847 Name: "test admin API key", 6848 Scope: dataprovider.APIKeyScopeAdmin, 6849 Admin: defaultTokenAuthUser, 6850 } 6851 6852 apiKey, resp, err := httpdtest.AddAPIKey(apiKey, http.StatusCreated) 6853 assert.NoError(t, err, string(resp)) 6854 6855 admin := getTestAdmin() 6856 admin.Username = altAdminUsername 6857 asJSON, err := json.Marshal(admin) 6858 assert.NoError(t, err) 6859 req, err := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON)) 6860 assert.NoError(t, err) 6861 setAPIKeyForReq(req, apiKey.Key, "") 6862 rr := executeRequest(req) 6863 checkResponseCode(t, http.StatusCreated, rr) 6864 _, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass) 6865 assert.NoError(t, err) 6866 6867 admin.Filters.AllowAPIKeyAuth = true 6868 asJSON, err = json.Marshal(admin) 6869 assert.NoError(t, err) 6870 req, err = http.NewRequest(http.MethodPut, path.Join(adminPath, altAdminUsername), bytes.NewBuffer(asJSON)) 6871 assert.NoError(t, err) 6872 setAPIKeyForReq(req, apiKey.Key, "") 6873 rr = executeRequest(req) 6874 checkResponseCode(t, http.StatusOK, rr) 6875 6876 req, err = http.NewRequest(http.MethodGet, path.Join(adminPath, altAdminUsername), nil) 6877 assert.NoError(t, err) 6878 setAPIKeyForReq(req, apiKey.Key, "") 6879 rr = executeRequest(req) 6880 checkResponseCode(t, http.StatusOK, rr) 6881 var adminGet dataprovider.Admin 6882 err = json.Unmarshal(rr.Body.Bytes(), &adminGet) 6883 assert.NoError(t, err) 6884 assert.True(t, adminGet.Filters.AllowAPIKeyAuth) 6885 6886 req, err = http.NewRequest(http.MethodPut, path.Join(adminPath, defaultTokenAuthUser), bytes.NewBuffer(asJSON)) 6887 assert.NoError(t, err) 6888 setAPIKeyForReq(req, apiKey.Key, "") 6889 rr = executeRequest(req) 6890 checkResponseCode(t, http.StatusBadRequest, rr) 6891 assert.Contains(t, rr.Body.String(), "updating the admin impersonated with an API key is not allowed") 6892 // changing the password for the impersonated admin is not allowed 6893 pwd := make(map[string]string) 6894 pwd["current_password"] = defaultTokenAuthPass 6895 pwd["new_password"] = altAdminPassword 6896 asJSON, err = json.Marshal(pwd) 6897 assert.NoError(t, err) 6898 req, _ = http.NewRequest(http.MethodPut, adminPwdPath, bytes.NewBuffer(asJSON)) 6899 setAPIKeyForReq(req, apiKey.Key, "") 6900 rr = executeRequest(req) 6901 checkResponseCode(t, http.StatusForbidden, rr) 6902 assert.Contains(t, rr.Body.String(), "API key authentication is not allowed") 6903 6904 req, err = http.NewRequest(http.MethodDelete, path.Join(adminPath, defaultTokenAuthUser), nil) 6905 assert.NoError(t, err) 6906 setAPIKeyForReq(req, apiKey.Key, "") 6907 rr = executeRequest(req) 6908 checkResponseCode(t, http.StatusBadRequest, rr) 6909 assert.Contains(t, rr.Body.String(), "you cannot delete yourself") 6910 6911 req, err = http.NewRequest(http.MethodDelete, path.Join(adminPath, altAdminUsername), nil) 6912 assert.NoError(t, err) 6913 setAPIKeyForReq(req, apiKey.Key, "") 6914 rr = executeRequest(req) 6915 checkResponseCode(t, http.StatusOK, rr) 6916 6917 _, err = httpdtest.RemoveAPIKey(apiKey, http.StatusOK) 6918 assert.NoError(t, err) 6919 6920 dbAdmin, err := dataprovider.AdminExists(defaultTokenAuthUser) 6921 assert.NoError(t, err) 6922 dbAdmin.Filters.AllowAPIKeyAuth = false 6923 err = dataprovider.UpdateAdmin(&dbAdmin, "", "") 6924 assert.NoError(t, err) 6925 sysAdmin, _, err = httpdtest.GetAdminByUsername(defaultTokenAuthUser, http.StatusOK) 6926 assert.NoError(t, err) 6927 assert.False(t, sysAdmin.Filters.AllowAPIKeyAuth) 6928} 6929 6930func TestUserHandlingWithAPIKey(t *testing.T) { 6931 admin := getTestAdmin() 6932 admin.Username = altAdminUsername 6933 admin.Filters.AllowAPIKeyAuth = true 6934 admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) 6935 assert.NoError(t, err) 6936 6937 apiKey := dataprovider.APIKey{ 6938 Name: "test admin API key", 6939 Scope: dataprovider.APIKeyScopeAdmin, 6940 Admin: admin.Username, 6941 } 6942 6943 apiKey, _, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated) 6944 assert.NoError(t, err) 6945 6946 user := getTestUser() 6947 userAsJSON := getUserAsJSON(t, user) 6948 req, err := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 6949 assert.NoError(t, err) 6950 setAPIKeyForReq(req, apiKey.Key, "") 6951 rr := executeRequest(req) 6952 checkResponseCode(t, http.StatusCreated, rr) 6953 6954 user.Filters.DisableFsChecks = true 6955 user.Description = "desc" 6956 userAsJSON = getUserAsJSON(t, user) 6957 req, err = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON)) 6958 assert.NoError(t, err) 6959 setAPIKeyForReq(req, apiKey.Key, "") 6960 rr = executeRequest(req) 6961 checkResponseCode(t, http.StatusOK, rr) 6962 6963 req, err = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 6964 assert.NoError(t, err) 6965 setAPIKeyForReq(req, apiKey.Key, "") 6966 rr = executeRequest(req) 6967 checkResponseCode(t, http.StatusOK, rr) 6968 var updatedUser dataprovider.User 6969 err = json.Unmarshal(rr.Body.Bytes(), &updatedUser) 6970 assert.NoError(t, err) 6971 assert.True(t, updatedUser.Filters.DisableFsChecks) 6972 assert.Equal(t, user.Description, updatedUser.Description) 6973 6974 req, err = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 6975 assert.NoError(t, err) 6976 setAPIKeyForReq(req, apiKey.Key, "") 6977 rr = executeRequest(req) 6978 checkResponseCode(t, http.StatusOK, rr) 6979 err = os.RemoveAll(user.GetHomeDir()) 6980 assert.NoError(t, err) 6981 6982 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 6983 assert.NoError(t, err) 6984 _, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusNotFound) 6985 assert.NoError(t, err) 6986} 6987 6988func TestUpdateUserMock(t *testing.T) { 6989 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 6990 assert.NoError(t, err) 6991 user := getTestUser() 6992 userAsJSON := getUserAsJSON(t, user) 6993 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 6994 setBearerForReq(req, token) 6995 rr := executeRequest(req) 6996 checkResponseCode(t, http.StatusCreated, rr) 6997 err = render.DecodeJSON(rr.Body, &user) 6998 assert.NoError(t, err) 6999 // permissions should not change if empty or nil 7000 permissions := user.Permissions 7001 user.Permissions = make(map[string][]string) 7002 userAsJSON = getUserAsJSON(t, user) 7003 req, _ = http.NewRequest(http.MethodPut, userPath+"/"+user.Username, bytes.NewBuffer(userAsJSON)) 7004 setBearerForReq(req, token) 7005 rr = executeRequest(req) 7006 checkResponseCode(t, http.StatusOK, rr) 7007 req, _ = http.NewRequest(http.MethodGet, userPath+"/"+user.Username, nil) 7008 setBearerForReq(req, token) 7009 rr = executeRequest(req) 7010 checkResponseCode(t, http.StatusOK, rr) 7011 var updatedUser dataprovider.User 7012 err = render.DecodeJSON(rr.Body, &updatedUser) 7013 assert.NoError(t, err) 7014 for dir, perms := range permissions { 7015 if actualPerms, ok := updatedUser.Permissions[dir]; ok { 7016 for _, v := range actualPerms { 7017 assert.True(t, util.IsStringInSlice(v, perms)) 7018 } 7019 } else { 7020 assert.Fail(t, "Permissions directories mismatch") 7021 } 7022 } 7023 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 7024 setBearerForReq(req, token) 7025 rr = executeRequest(req) 7026 checkResponseCode(t, http.StatusOK, rr) 7027} 7028 7029func TestUpdateUserQuotaUsageMock(t *testing.T) { 7030 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7031 assert.NoError(t, err) 7032 var user dataprovider.User 7033 u := getTestUser() 7034 usedQuotaFiles := 1 7035 usedQuotaSize := int64(65535) 7036 u.UsedQuotaFiles = usedQuotaFiles 7037 u.UsedQuotaSize = usedQuotaSize 7038 u.QuotaFiles = 100 7039 userAsJSON := getUserAsJSON(t, u) 7040 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 7041 setBearerForReq(req, token) 7042 rr := executeRequest(req) 7043 checkResponseCode(t, http.StatusCreated, rr) 7044 err = render.DecodeJSON(rr.Body, &user) 7045 assert.NoError(t, err) 7046 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage"), bytes.NewBuffer(userAsJSON)) 7047 setBearerForReq(req, token) 7048 rr = executeRequest(req) 7049 checkResponseCode(t, http.StatusOK, rr) 7050 req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaCompatPath, bytes.NewBuffer(userAsJSON)) 7051 setBearerForReq(req, token) 7052 rr = executeRequest(req) 7053 checkResponseCode(t, http.StatusOK, rr) 7054 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 7055 setBearerForReq(req, token) 7056 rr = executeRequest(req) 7057 checkResponseCode(t, http.StatusOK, rr) 7058 err = render.DecodeJSON(rr.Body, &user) 7059 assert.NoError(t, err) 7060 assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles) 7061 assert.Equal(t, usedQuotaSize, user.UsedQuotaSize) 7062 // now update only quota size 7063 u.UsedQuotaFiles = 0 7064 userAsJSON = getUserAsJSON(t, u) 7065 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage")+"?mode=add", bytes.NewBuffer(userAsJSON)) 7066 setBearerForReq(req, token) 7067 rr = executeRequest(req) 7068 checkResponseCode(t, http.StatusOK, rr) 7069 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 7070 setBearerForReq(req, token) 7071 rr = executeRequest(req) 7072 checkResponseCode(t, http.StatusOK, rr) 7073 err = render.DecodeJSON(rr.Body, &user) 7074 assert.NoError(t, err) 7075 assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles) 7076 assert.Equal(t, usedQuotaSize*2, user.UsedQuotaSize) 7077 // only quota files 7078 u.UsedQuotaFiles = usedQuotaFiles 7079 u.UsedQuotaSize = 0 7080 userAsJSON = getUserAsJSON(t, u) 7081 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage")+"?mode=add", bytes.NewBuffer(userAsJSON)) 7082 setBearerForReq(req, token) 7083 rr = executeRequest(req) 7084 checkResponseCode(t, http.StatusOK, rr) 7085 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 7086 setBearerForReq(req, token) 7087 rr = executeRequest(req) 7088 checkResponseCode(t, http.StatusOK, rr) 7089 err = render.DecodeJSON(rr.Body, &user) 7090 assert.NoError(t, err) 7091 assert.Equal(t, usedQuotaFiles*2, user.UsedQuotaFiles) 7092 assert.Equal(t, usedQuotaSize*2, user.UsedQuotaSize) 7093 req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaCompatPath, bytes.NewBuffer([]byte("string"))) 7094 setBearerForReq(req, token) 7095 rr = executeRequest(req) 7096 checkResponseCode(t, http.StatusBadRequest, rr) 7097 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage"), bytes.NewBuffer([]byte("string"))) 7098 setBearerForReq(req, token) 7099 rr = executeRequest(req) 7100 checkResponseCode(t, http.StatusBadRequest, rr) 7101 assert.True(t, common.QuotaScans.AddUserQuotaScan(user.Username)) 7102 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage"), bytes.NewBuffer(userAsJSON)) 7103 setBearerForReq(req, token) 7104 rr = executeRequest(req) 7105 checkResponseCode(t, http.StatusConflict, rr) 7106 assert.True(t, common.QuotaScans.RemoveUserQuotaScan(user.Username)) 7107 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 7108 setBearerForReq(req, token) 7109 rr = executeRequest(req) 7110 checkResponseCode(t, http.StatusOK, rr) 7111} 7112 7113func TestUserPermissionsMock(t *testing.T) { 7114 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7115 assert.NoError(t, err) 7116 user := getTestUser() 7117 user.Permissions = make(map[string][]string) 7118 user.Permissions["/somedir"] = []string{dataprovider.PermAny} 7119 userAsJSON := getUserAsJSON(t, user) 7120 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 7121 setBearerForReq(req, token) 7122 rr := executeRequest(req) 7123 checkResponseCode(t, http.StatusBadRequest, rr) 7124 user.Permissions = make(map[string][]string) 7125 user.Permissions["/"] = []string{dataprovider.PermAny} 7126 user.Permissions[".."] = []string{dataprovider.PermAny} 7127 userAsJSON = getUserAsJSON(t, user) 7128 req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 7129 setBearerForReq(req, token) 7130 rr = executeRequest(req) 7131 checkResponseCode(t, http.StatusBadRequest, rr) 7132 user.Permissions = make(map[string][]string) 7133 user.Permissions["/"] = []string{dataprovider.PermAny} 7134 userAsJSON = getUserAsJSON(t, user) 7135 req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 7136 setBearerForReq(req, token) 7137 rr = executeRequest(req) 7138 checkResponseCode(t, http.StatusCreated, rr) 7139 err = render.DecodeJSON(rr.Body, &user) 7140 assert.NoError(t, err) 7141 user.Permissions["/somedir"] = []string{"invalid"} 7142 userAsJSON = getUserAsJSON(t, user) 7143 req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON)) 7144 setBearerForReq(req, token) 7145 rr = executeRequest(req) 7146 checkResponseCode(t, http.StatusBadRequest, rr) 7147 delete(user.Permissions, "/somedir") 7148 user.Permissions["/somedir/.."] = []string{dataprovider.PermAny} 7149 userAsJSON = getUserAsJSON(t, user) 7150 req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON)) 7151 setBearerForReq(req, token) 7152 rr = executeRequest(req) 7153 checkResponseCode(t, http.StatusBadRequest, rr) 7154 delete(user.Permissions, "/somedir/..") 7155 user.Permissions["not_abs_path"] = []string{dataprovider.PermAny} 7156 userAsJSON = getUserAsJSON(t, user) 7157 req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON)) 7158 setBearerForReq(req, token) 7159 rr = executeRequest(req) 7160 checkResponseCode(t, http.StatusBadRequest, rr) 7161 delete(user.Permissions, "not_abs_path") 7162 user.Permissions["/somedir/../otherdir/"] = []string{dataprovider.PermListItems} 7163 userAsJSON = getUserAsJSON(t, user) 7164 req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON)) 7165 setBearerForReq(req, token) 7166 rr = executeRequest(req) 7167 checkResponseCode(t, http.StatusOK, rr) 7168 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 7169 setBearerForReq(req, token) 7170 rr = executeRequest(req) 7171 checkResponseCode(t, http.StatusOK, rr) 7172 var updatedUser dataprovider.User 7173 err = render.DecodeJSON(rr.Body, &updatedUser) 7174 assert.NoError(t, err) 7175 if val, ok := updatedUser.Permissions["/otherdir"]; ok { 7176 assert.True(t, util.IsStringInSlice(dataprovider.PermListItems, val)) 7177 assert.Equal(t, 1, len(val)) 7178 } else { 7179 assert.Fail(t, "expected dir not found in permissions") 7180 } 7181 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 7182 setBearerForReq(req, token) 7183 rr = executeRequest(req) 7184 checkResponseCode(t, http.StatusOK, rr) 7185} 7186 7187func TestUpdateUserInvalidJsonMock(t *testing.T) { 7188 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7189 assert.NoError(t, err) 7190 user := getTestUser() 7191 userAsJSON := getUserAsJSON(t, user) 7192 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 7193 setBearerForReq(req, token) 7194 rr := executeRequest(req) 7195 checkResponseCode(t, http.StatusCreated, rr) 7196 err = render.DecodeJSON(rr.Body, &user) 7197 assert.NoError(t, err) 7198 req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer([]byte("Invalid json"))) 7199 setBearerForReq(req, token) 7200 rr = executeRequest(req) 7201 checkResponseCode(t, http.StatusBadRequest, rr) 7202 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 7203 setBearerForReq(req, token) 7204 rr = executeRequest(req) 7205 checkResponseCode(t, http.StatusOK, rr) 7206} 7207 7208func TestUpdateUserInvalidParamsMock(t *testing.T) { 7209 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7210 assert.NoError(t, err) 7211 user := getTestUser() 7212 userAsJSON := getUserAsJSON(t, user) 7213 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 7214 setBearerForReq(req, token) 7215 rr := executeRequest(req) 7216 checkResponseCode(t, http.StatusCreated, rr) 7217 err = render.DecodeJSON(rr.Body, &user) 7218 assert.NoError(t, err) 7219 user.HomeDir = "" 7220 userAsJSON = getUserAsJSON(t, user) 7221 req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON)) 7222 setBearerForReq(req, token) 7223 rr = executeRequest(req) 7224 checkResponseCode(t, http.StatusBadRequest, rr) 7225 userID := user.ID 7226 user.ID = 0 7227 user.CreatedAt = 0 7228 userAsJSON = getUserAsJSON(t, user) 7229 req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON)) 7230 setBearerForReq(req, token) 7231 rr = executeRequest(req) 7232 checkResponseCode(t, http.StatusBadRequest, rr) 7233 user.ID = userID 7234 req, _ = http.NewRequest(http.MethodPut, userPath+"/0", bytes.NewBuffer(userAsJSON)) 7235 setBearerForReq(req, token) 7236 rr = executeRequest(req) 7237 checkResponseCode(t, http.StatusNotFound, rr) 7238 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 7239 setBearerForReq(req, token) 7240 rr = executeRequest(req) 7241 checkResponseCode(t, http.StatusOK, rr) 7242} 7243 7244func TestGetAdminsMock(t *testing.T) { 7245 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7246 assert.NoError(t, err) 7247 admin := getTestAdmin() 7248 admin.Username = altAdminUsername 7249 asJSON, err := json.Marshal(admin) 7250 assert.NoError(t, err) 7251 req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON)) 7252 setBearerForReq(req, token) 7253 rr := executeRequest(req) 7254 checkResponseCode(t, http.StatusCreated, rr) 7255 7256 req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=510&offset=0&order=ASC", nil) 7257 setBearerForReq(req, token) 7258 rr = executeRequest(req) 7259 checkResponseCode(t, http.StatusOK, rr) 7260 var admins []dataprovider.Admin 7261 err = render.DecodeJSON(rr.Body, &admins) 7262 assert.NoError(t, err) 7263 assert.GreaterOrEqual(t, len(admins), 1) 7264 firtAdmin := admins[0].Username 7265 req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=510&offset=0&order=DESC", nil) 7266 setBearerForReq(req, token) 7267 rr = executeRequest(req) 7268 checkResponseCode(t, http.StatusOK, rr) 7269 admins = nil 7270 err = render.DecodeJSON(rr.Body, &admins) 7271 assert.NoError(t, err) 7272 assert.GreaterOrEqual(t, len(admins), 1) 7273 assert.NotEqual(t, firtAdmin, admins[0].Username) 7274 7275 req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=510&offset=1&order=ASC", nil) 7276 setBearerForReq(req, token) 7277 rr = executeRequest(req) 7278 checkResponseCode(t, http.StatusOK, rr) 7279 admins = nil 7280 err = render.DecodeJSON(rr.Body, &admins) 7281 assert.NoError(t, err) 7282 assert.GreaterOrEqual(t, len(admins), 1) 7283 assert.NotEqual(t, firtAdmin, admins[0].Username) 7284 7285 req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=a&offset=0&order=ASC", nil) 7286 setBearerForReq(req, token) 7287 rr = executeRequest(req) 7288 checkResponseCode(t, http.StatusBadRequest, rr) 7289 req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=1&offset=a&order=ASC", nil) 7290 setBearerForReq(req, token) 7291 rr = executeRequest(req) 7292 checkResponseCode(t, http.StatusBadRequest, rr) 7293 req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=1&offset=0&order=ASCa", nil) 7294 setBearerForReq(req, token) 7295 rr = executeRequest(req) 7296 checkResponseCode(t, http.StatusBadRequest, rr) 7297 7298 req, _ = http.NewRequest(http.MethodDelete, path.Join(adminPath, admin.Username), nil) 7299 setBearerForReq(req, token) 7300 rr = executeRequest(req) 7301 checkResponseCode(t, http.StatusOK, rr) 7302} 7303 7304func TestGetUsersMock(t *testing.T) { 7305 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7306 assert.NoError(t, err) 7307 user := getTestUser() 7308 userAsJSON := getUserAsJSON(t, user) 7309 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 7310 setBearerForReq(req, token) 7311 rr := executeRequest(req) 7312 checkResponseCode(t, http.StatusCreated, rr) 7313 err = render.DecodeJSON(rr.Body, &user) 7314 assert.NoError(t, err) 7315 req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=510&offset=0&order=ASC", nil) 7316 setBearerForReq(req, token) 7317 rr = executeRequest(req) 7318 checkResponseCode(t, http.StatusOK, rr) 7319 var users []dataprovider.User 7320 err = render.DecodeJSON(rr.Body, &users) 7321 assert.NoError(t, err) 7322 assert.GreaterOrEqual(t, len(users), 1) 7323 req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=a&offset=0&order=ASC", nil) 7324 setBearerForReq(req, token) 7325 rr = executeRequest(req) 7326 checkResponseCode(t, http.StatusBadRequest, rr) 7327 req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=a&order=ASC", nil) 7328 setBearerForReq(req, token) 7329 rr = executeRequest(req) 7330 checkResponseCode(t, http.StatusBadRequest, rr) 7331 req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASCa", nil) 7332 setBearerForReq(req, token) 7333 rr = executeRequest(req) 7334 checkResponseCode(t, http.StatusBadRequest, rr) 7335 7336 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 7337 setBearerForReq(req, token) 7338 rr = executeRequest(req) 7339 checkResponseCode(t, http.StatusOK, rr) 7340} 7341 7342func TestDeleteUserInvalidParamsMock(t *testing.T) { 7343 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7344 assert.NoError(t, err) 7345 req, _ := http.NewRequest(http.MethodDelete, userPath+"/0", nil) 7346 setBearerForReq(req, token) 7347 rr := executeRequest(req) 7348 checkResponseCode(t, http.StatusNotFound, rr) 7349} 7350 7351func TestGetQuotaScansMock(t *testing.T) { 7352 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7353 assert.NoError(t, err) 7354 req, err := http.NewRequest(http.MethodGet, quotaScanPath, nil) 7355 assert.NoError(t, err) 7356 setBearerForReq(req, token) 7357 rr := executeRequest(req) 7358 checkResponseCode(t, http.StatusOK, rr) 7359} 7360 7361func TestStartQuotaScanMock(t *testing.T) { 7362 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7363 assert.NoError(t, err) 7364 user := getTestUser() 7365 userAsJSON := getUserAsJSON(t, user) 7366 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 7367 setBearerForReq(req, token) 7368 rr := executeRequest(req) 7369 checkResponseCode(t, http.StatusCreated, rr) 7370 err = render.DecodeJSON(rr.Body, &user) 7371 assert.NoError(t, err) 7372 _, err = os.Stat(user.HomeDir) 7373 if err == nil { 7374 err = os.Remove(user.HomeDir) 7375 assert.NoError(t, err) 7376 } 7377 // simulate a duplicate quota scan 7378 common.QuotaScans.AddUserQuotaScan(user.Username) 7379 req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil) 7380 setBearerForReq(req, token) 7381 rr = executeRequest(req) 7382 checkResponseCode(t, http.StatusConflict, rr) 7383 assert.True(t, common.QuotaScans.RemoveUserQuotaScan(user.Username)) 7384 7385 req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil) 7386 setBearerForReq(req, token) 7387 rr = executeRequest(req) 7388 checkResponseCode(t, http.StatusAccepted, rr) 7389 7390 waitForUsersQuotaScan(t, token) 7391 7392 _, err = os.Stat(user.HomeDir) 7393 if err != nil && os.IsNotExist(err) { 7394 err = os.MkdirAll(user.HomeDir, os.ModePerm) 7395 assert.NoError(t, err) 7396 } 7397 req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil) 7398 setBearerForReq(req, token) 7399 rr = executeRequest(req) 7400 checkResponseCode(t, http.StatusAccepted, rr) 7401 7402 waitForUsersQuotaScan(t, token) 7403 7404 req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil) 7405 setBearerForReq(req, token) 7406 rr = executeRequest(req) 7407 checkResponseCode(t, http.StatusAccepted, rr) 7408 7409 waitForUsersQuotaScan(t, token) 7410 7411 asJSON, err := json.Marshal(user) 7412 assert.NoError(t, err) 7413 req, _ = http.NewRequest(http.MethodPost, quotaScanCompatPath, bytes.NewBuffer(asJSON)) 7414 setBearerForReq(req, token) 7415 rr = executeRequest(req) 7416 checkResponseCode(t, http.StatusAccepted, rr) 7417 7418 waitForUsersQuotaScan(t, token) 7419 7420 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 7421 setBearerForReq(req, token) 7422 rr = executeRequest(req) 7423 checkResponseCode(t, http.StatusOK, rr) 7424 err = os.RemoveAll(user.GetHomeDir()) 7425 assert.NoError(t, err) 7426} 7427 7428func TestUpdateFolderQuotaUsageMock(t *testing.T) { 7429 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7430 assert.NoError(t, err) 7431 mappedPath := filepath.Join(os.TempDir(), "vfolder") 7432 folderName := filepath.Base(mappedPath) 7433 f := vfs.BaseVirtualFolder{ 7434 MappedPath: mappedPath, 7435 Name: folderName, 7436 } 7437 usedQuotaFiles := 1 7438 usedQuotaSize := int64(65535) 7439 f.UsedQuotaFiles = usedQuotaFiles 7440 f.UsedQuotaSize = usedQuotaSize 7441 var folder vfs.BaseVirtualFolder 7442 folderAsJSON, err := json.Marshal(f) 7443 assert.NoError(t, err) 7444 req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON)) 7445 setBearerForReq(req, token) 7446 rr := executeRequest(req) 7447 checkResponseCode(t, http.StatusCreated, rr) 7448 err = render.DecodeJSON(rr.Body, &folder) 7449 assert.NoError(t, err) 7450 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage"), bytes.NewBuffer(folderAsJSON)) 7451 setBearerForReq(req, token) 7452 rr = executeRequest(req) 7453 checkResponseCode(t, http.StatusOK, rr) 7454 req, _ = http.NewRequest(http.MethodPut, updateFolderUsedQuotaCompatPath, bytes.NewBuffer(folderAsJSON)) 7455 setBearerForReq(req, token) 7456 rr = executeRequest(req) 7457 checkResponseCode(t, http.StatusOK, rr) 7458 var folderGet vfs.BaseVirtualFolder 7459 req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil) 7460 setBearerForReq(req, token) 7461 rr = executeRequest(req) 7462 checkResponseCode(t, http.StatusOK, rr) 7463 err = render.DecodeJSON(rr.Body, &folderGet) 7464 assert.NoError(t, err) 7465 assert.Equal(t, usedQuotaFiles, folderGet.UsedQuotaFiles) 7466 assert.Equal(t, usedQuotaSize, folderGet.UsedQuotaSize) 7467 // now update only quota size 7468 f.UsedQuotaFiles = 0 7469 folderAsJSON, err = json.Marshal(f) 7470 assert.NoError(t, err) 7471 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage")+"?mode=add", 7472 bytes.NewBuffer(folderAsJSON)) 7473 setBearerForReq(req, token) 7474 rr = executeRequest(req) 7475 checkResponseCode(t, http.StatusOK, rr) 7476 folderGet = vfs.BaseVirtualFolder{} 7477 req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil) 7478 setBearerForReq(req, token) 7479 rr = executeRequest(req) 7480 checkResponseCode(t, http.StatusOK, rr) 7481 err = render.DecodeJSON(rr.Body, &folderGet) 7482 assert.NoError(t, err) 7483 assert.Equal(t, usedQuotaFiles, folderGet.UsedQuotaFiles) 7484 assert.Equal(t, usedQuotaSize*2, folderGet.UsedQuotaSize) 7485 // now update only quota files 7486 f.UsedQuotaSize = 0 7487 f.UsedQuotaFiles = 1 7488 folderAsJSON, err = json.Marshal(f) 7489 assert.NoError(t, err) 7490 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage")+"?mode=add", 7491 bytes.NewBuffer(folderAsJSON)) 7492 setBearerForReq(req, token) 7493 rr = executeRequest(req) 7494 checkResponseCode(t, http.StatusOK, rr) 7495 folderGet = vfs.BaseVirtualFolder{} 7496 req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil) 7497 setBearerForReq(req, token) 7498 rr = executeRequest(req) 7499 checkResponseCode(t, http.StatusOK, rr) 7500 err = render.DecodeJSON(rr.Body, &folderGet) 7501 assert.NoError(t, err) 7502 assert.Equal(t, usedQuotaFiles*2, folderGet.UsedQuotaFiles) 7503 assert.Equal(t, usedQuotaSize*2, folderGet.UsedQuotaSize) 7504 req, _ = http.NewRequest(http.MethodPut, updateFolderUsedQuotaCompatPath, bytes.NewBuffer([]byte("string"))) 7505 setBearerForReq(req, token) 7506 rr = executeRequest(req) 7507 checkResponseCode(t, http.StatusBadRequest, rr) 7508 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage"), 7509 bytes.NewBuffer([]byte("not a json"))) 7510 setBearerForReq(req, token) 7511 rr = executeRequest(req) 7512 checkResponseCode(t, http.StatusBadRequest, rr) 7513 7514 assert.True(t, common.QuotaScans.AddVFolderQuotaScan(folderName)) 7515 req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage"), 7516 bytes.NewBuffer(folderAsJSON)) 7517 setBearerForReq(req, token) 7518 rr = executeRequest(req) 7519 checkResponseCode(t, http.StatusConflict, rr) 7520 assert.True(t, common.QuotaScans.RemoveVFolderQuotaScan(folderName)) 7521 7522 req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil) 7523 setBearerForReq(req, token) 7524 rr = executeRequest(req) 7525 checkResponseCode(t, http.StatusOK, rr) 7526} 7527 7528func TestStartFolderQuotaScanMock(t *testing.T) { 7529 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7530 assert.NoError(t, err) 7531 mappedPath := filepath.Join(os.TempDir(), "vfolder") 7532 folderName := filepath.Base(mappedPath) 7533 folder := vfs.BaseVirtualFolder{ 7534 Name: folderName, 7535 MappedPath: mappedPath, 7536 } 7537 folderAsJSON, err := json.Marshal(folder) 7538 assert.NoError(t, err) 7539 req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON)) 7540 setBearerForReq(req, token) 7541 rr := executeRequest(req) 7542 checkResponseCode(t, http.StatusCreated, rr) 7543 _, err = os.Stat(mappedPath) 7544 if err == nil { 7545 err = os.Remove(mappedPath) 7546 assert.NoError(t, err) 7547 } 7548 // simulate a duplicate quota scan 7549 common.QuotaScans.AddVFolderQuotaScan(folderName) 7550 req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "folders", folder.Name, "scan"), nil) 7551 setBearerForReq(req, token) 7552 rr = executeRequest(req) 7553 checkResponseCode(t, http.StatusConflict, rr) 7554 assert.True(t, common.QuotaScans.RemoveVFolderQuotaScan(folderName)) 7555 // and now a real quota scan 7556 _, err = os.Stat(mappedPath) 7557 if err != nil && os.IsNotExist(err) { 7558 err = os.MkdirAll(mappedPath, os.ModePerm) 7559 assert.NoError(t, err) 7560 } 7561 req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "folders", folder.Name, "scan"), nil) 7562 setBearerForReq(req, token) 7563 rr = executeRequest(req) 7564 checkResponseCode(t, http.StatusAccepted, rr) 7565 waitForFoldersQuotaScanPath(t, token) 7566 7567 asJSON, err := json.Marshal(folder) 7568 assert.NoError(t, err) 7569 req, _ = http.NewRequest(http.MethodPost, quotaScanVFolderCompatPath, bytes.NewBuffer(asJSON)) 7570 setBearerForReq(req, token) 7571 rr = executeRequest(req) 7572 checkResponseCode(t, http.StatusAccepted, rr) 7573 waitForFoldersQuotaScanPath(t, token) 7574 7575 // cleanup 7576 7577 req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil) 7578 setBearerForReq(req, token) 7579 rr = executeRequest(req) 7580 checkResponseCode(t, http.StatusOK, rr) 7581 err = os.RemoveAll(folderPath) 7582 assert.NoError(t, err) 7583 err = os.RemoveAll(mappedPath) 7584 assert.NoError(t, err) 7585} 7586 7587func TestStartQuotaScanNonExistentUserMock(t *testing.T) { 7588 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7589 assert.NoError(t, err) 7590 user := getTestUser() 7591 7592 req, _ := http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil) 7593 setBearerForReq(req, token) 7594 rr := executeRequest(req) 7595 checkResponseCode(t, http.StatusNotFound, rr) 7596} 7597 7598func TestStartQuotaScanBadUserMock(t *testing.T) { 7599 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7600 assert.NoError(t, err) 7601 req, _ := http.NewRequest(http.MethodPost, quotaScanCompatPath, bytes.NewBuffer([]byte("invalid json"))) 7602 setBearerForReq(req, token) 7603 rr := executeRequest(req) 7604 checkResponseCode(t, http.StatusBadRequest, rr) 7605} 7606 7607func TestStartQuotaScanBadFolderMock(t *testing.T) { 7608 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7609 assert.NoError(t, err) 7610 req, _ := http.NewRequest(http.MethodPost, quotaScanVFolderCompatPath, bytes.NewBuffer([]byte("invalid json"))) 7611 setBearerForReq(req, token) 7612 rr := executeRequest(req) 7613 checkResponseCode(t, http.StatusBadRequest, rr) 7614} 7615 7616func TestStartQuotaScanNonExistentFolderMock(t *testing.T) { 7617 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7618 assert.NoError(t, err) 7619 folder := vfs.BaseVirtualFolder{ 7620 MappedPath: os.TempDir(), 7621 Name: "afolder", 7622 } 7623 req, _ := http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "folders", folder.Name, "scan"), nil) 7624 setBearerForReq(req, token) 7625 rr := executeRequest(req) 7626 checkResponseCode(t, http.StatusNotFound, rr) 7627} 7628 7629func TestGetFoldersMock(t *testing.T) { 7630 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7631 assert.NoError(t, err) 7632 mappedPath := filepath.Join(os.TempDir(), "vfolder") 7633 folderName := filepath.Base(mappedPath) 7634 folder := vfs.BaseVirtualFolder{ 7635 Name: folderName, 7636 MappedPath: mappedPath, 7637 } 7638 folderAsJSON, err := json.Marshal(folder) 7639 assert.NoError(t, err) 7640 req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON)) 7641 setBearerForReq(req, token) 7642 rr := executeRequest(req) 7643 checkResponseCode(t, http.StatusCreated, rr) 7644 err = render.DecodeJSON(rr.Body, &folder) 7645 assert.NoError(t, err) 7646 7647 var folders []vfs.BaseVirtualFolder 7648 url, err := url.Parse(folderPath + "?limit=510&offset=0&order=DESC") 7649 assert.NoError(t, err) 7650 req, _ = http.NewRequest(http.MethodGet, url.String(), nil) 7651 setBearerForReq(req, token) 7652 rr = executeRequest(req) 7653 checkResponseCode(t, http.StatusOK, rr) 7654 err = render.DecodeJSON(rr.Body, &folders) 7655 assert.NoError(t, err) 7656 assert.GreaterOrEqual(t, len(folders), 1) 7657 req, _ = http.NewRequest(http.MethodGet, folderPath+"?limit=a&offset=0&order=ASC", nil) 7658 setBearerForReq(req, token) 7659 rr = executeRequest(req) 7660 checkResponseCode(t, http.StatusBadRequest, rr) 7661 req, _ = http.NewRequest(http.MethodGet, folderPath+"?limit=1&offset=a&order=ASC", nil) 7662 setBearerForReq(req, token) 7663 rr = executeRequest(req) 7664 checkResponseCode(t, http.StatusBadRequest, rr) 7665 req, _ = http.NewRequest(http.MethodGet, folderPath+"?limit=1&offset=0&order=ASCa", nil) 7666 setBearerForReq(req, token) 7667 rr = executeRequest(req) 7668 checkResponseCode(t, http.StatusBadRequest, rr) 7669 7670 req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil) 7671 setBearerForReq(req, token) 7672 rr = executeRequest(req) 7673 checkResponseCode(t, http.StatusOK, rr) 7674} 7675 7676func TestGetVersionMock(t *testing.T) { 7677 req, _ := http.NewRequest(http.MethodGet, versionPath, nil) 7678 rr := executeRequest(req) 7679 checkResponseCode(t, http.StatusUnauthorized, rr) 7680 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7681 assert.NoError(t, err) 7682 req, _ = http.NewRequest(http.MethodGet, versionPath, nil) 7683 setBearerForReq(req, token) 7684 rr = executeRequest(req) 7685 checkResponseCode(t, http.StatusOK, rr) 7686 req, _ = http.NewRequest(http.MethodGet, versionPath, nil) 7687 setBearerForReq(req, "abcde") 7688 rr = executeRequest(req) 7689 checkResponseCode(t, http.StatusUnauthorized, rr) 7690} 7691 7692func TestGetConnectionsMock(t *testing.T) { 7693 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7694 assert.NoError(t, err) 7695 req, _ := http.NewRequest(http.MethodGet, activeConnectionsPath, nil) 7696 setBearerForReq(req, token) 7697 rr := executeRequest(req) 7698 checkResponseCode(t, http.StatusOK, rr) 7699} 7700 7701func TestGetStatusMock(t *testing.T) { 7702 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7703 assert.NoError(t, err) 7704 req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil) 7705 setBearerForReq(req, token) 7706 rr := executeRequest(req) 7707 checkResponseCode(t, http.StatusOK, rr) 7708} 7709 7710func TestDeleteActiveConnectionMock(t *testing.T) { 7711 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7712 assert.NoError(t, err) 7713 req, _ := http.NewRequest(http.MethodDelete, activeConnectionsPath+"/connectionID", nil) 7714 setBearerForReq(req, token) 7715 rr := executeRequest(req) 7716 checkResponseCode(t, http.StatusNotFound, rr) 7717} 7718 7719func TestNotFoundMock(t *testing.T) { 7720 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7721 assert.NoError(t, err) 7722 req, _ := http.NewRequest(http.MethodGet, "/non/existing/path", nil) 7723 setBearerForReq(req, token) 7724 rr := executeRequest(req) 7725 checkResponseCode(t, http.StatusNotFound, rr) 7726} 7727 7728func TestMethodNotAllowedMock(t *testing.T) { 7729 req, _ := http.NewRequest(http.MethodPost, activeConnectionsPath, nil) 7730 rr := executeRequest(req) 7731 checkResponseCode(t, http.StatusMethodNotAllowed, rr) 7732} 7733 7734func TestHealthCheck(t *testing.T) { 7735 req, _ := http.NewRequest(http.MethodGet, "/healthz", nil) 7736 rr := executeRequest(req) 7737 checkResponseCode(t, http.StatusOK, rr) 7738 assert.Equal(t, "ok", rr.Body.String()) 7739} 7740 7741func TestGetWebRootMock(t *testing.T) { 7742 req, _ := http.NewRequest(http.MethodGet, "/", nil) 7743 rr := executeRequest(req) 7744 checkResponseCode(t, http.StatusMovedPermanently, rr) 7745 assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) 7746 req, _ = http.NewRequest(http.MethodGet, webBasePath, nil) 7747 rr = executeRequest(req) 7748 checkResponseCode(t, http.StatusMovedPermanently, rr) 7749 assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) 7750 req, _ = http.NewRequest(http.MethodGet, webBasePathAdmin, nil) 7751 rr = executeRequest(req) 7752 checkResponseCode(t, http.StatusMovedPermanently, rr) 7753 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 7754 req, _ = http.NewRequest(http.MethodGet, webBasePathClient, nil) 7755 rr = executeRequest(req) 7756 checkResponseCode(t, http.StatusMovedPermanently, rr) 7757 assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) 7758} 7759 7760func TestWebNotFoundURI(t *testing.T) { 7761 urlString := httpBaseURL + webBasePath + "/a" 7762 req, err := http.NewRequest(http.MethodGet, urlString, nil) 7763 assert.NoError(t, err) 7764 resp, err := httpclient.GetHTTPClient().Do(req) 7765 require.NoError(t, err) 7766 defer resp.Body.Close() 7767 assert.Equal(t, http.StatusNotFound, resp.StatusCode) 7768 7769 req, err = http.NewRequest(http.MethodGet, urlString, nil) 7770 assert.NoError(t, err) 7771 setJWTCookieForReq(req, "invalid token") 7772 resp, err = httpclient.GetHTTPClient().Do(req) 7773 require.NoError(t, err) 7774 defer resp.Body.Close() 7775 assert.Equal(t, http.StatusNotFound, resp.StatusCode) 7776 7777 urlString = httpBaseURL + webBasePathClient + "/a" 7778 req, err = http.NewRequest(http.MethodGet, urlString, nil) 7779 assert.NoError(t, err) 7780 resp, err = httpclient.GetHTTPClient().Do(req) 7781 require.NoError(t, err) 7782 defer resp.Body.Close() 7783 assert.Equal(t, http.StatusNotFound, resp.StatusCode) 7784 7785 req, err = http.NewRequest(http.MethodGet, urlString, nil) 7786 assert.NoError(t, err) 7787 setJWTCookieForReq(req, "invalid client token") 7788 resp, err = httpclient.GetHTTPClient().Do(req) 7789 require.NoError(t, err) 7790 defer resp.Body.Close() 7791 assert.Equal(t, http.StatusNotFound, resp.StatusCode) 7792} 7793 7794func TestLogout(t *testing.T) { 7795 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7796 assert.NoError(t, err) 7797 req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil) 7798 setBearerForReq(req, token) 7799 rr := executeRequest(req) 7800 checkResponseCode(t, http.StatusOK, rr) 7801 7802 req, _ = http.NewRequest(http.MethodGet, logoutPath, nil) 7803 setBearerForReq(req, token) 7804 rr = executeRequest(req) 7805 checkResponseCode(t, http.StatusOK, rr) 7806 7807 req, _ = http.NewRequest(http.MethodGet, serverStatusPath, nil) 7808 setBearerForReq(req, token) 7809 rr = executeRequest(req) 7810 checkResponseCode(t, http.StatusUnauthorized, rr) 7811 assert.Contains(t, rr.Body.String(), "Your token is no longer valid") 7812} 7813 7814func TestDefenderAPIInvalidIDMock(t *testing.T) { 7815 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7816 assert.NoError(t, err) 7817 req, _ := http.NewRequest(http.MethodGet, path.Join(defenderHosts, "abc"), nil) // not hex id 7818 setBearerForReq(req, token) 7819 rr := executeRequest(req) 7820 checkResponseCode(t, http.StatusBadRequest, rr) 7821 assert.Contains(t, rr.Body.String(), "invalid host id") 7822} 7823 7824func TestTokenHeaderCookie(t *testing.T) { 7825 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7826 assert.NoError(t, err) 7827 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7828 assert.NoError(t, err) 7829 7830 req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil) 7831 setJWTCookieForReq(req, apiToken) 7832 rr := executeRequest(req) 7833 checkResponseCode(t, http.StatusUnauthorized, rr) 7834 assert.Contains(t, rr.Body.String(), "no token found") 7835 7836 req, _ = http.NewRequest(http.MethodGet, serverStatusPath, nil) 7837 setBearerForReq(req, apiToken) 7838 rr = executeRequest(req) 7839 checkResponseCode(t, http.StatusOK, rr) 7840 7841 req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil) 7842 setBearerForReq(req, webToken) 7843 rr = executeRequest(req) 7844 checkResponseCode(t, http.StatusFound, rr) 7845 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 7846 7847 req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil) 7848 setJWTCookieForReq(req, webToken) 7849 rr = executeRequest(req) 7850 checkResponseCode(t, http.StatusOK, rr) 7851} 7852 7853func TestTokenAudience(t *testing.T) { 7854 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7855 assert.NoError(t, err) 7856 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 7857 assert.NoError(t, err) 7858 7859 req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil) 7860 setBearerForReq(req, apiToken) 7861 rr := executeRequest(req) 7862 checkResponseCode(t, http.StatusOK, rr) 7863 7864 req, _ = http.NewRequest(http.MethodGet, serverStatusPath, nil) 7865 setBearerForReq(req, webToken) 7866 rr = executeRequest(req) 7867 checkResponseCode(t, http.StatusUnauthorized, rr) 7868 assert.Contains(t, rr.Body.String(), "Your token audience is not valid") 7869 7870 req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil) 7871 setJWTCookieForReq(req, webToken) 7872 rr = executeRequest(req) 7873 checkResponseCode(t, http.StatusOK, rr) 7874 7875 req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil) 7876 setJWTCookieForReq(req, apiToken) 7877 rr = executeRequest(req) 7878 checkResponseCode(t, http.StatusFound, rr) 7879 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 7880} 7881 7882func TestWebAPILoginMock(t *testing.T) { 7883 _, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 7884 assert.Error(t, err) 7885 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 7886 assert.NoError(t, err) 7887 _, err = getJWTAPIUserTokenFromTestServer(defaultUsername+"1", defaultPassword) 7888 assert.Error(t, err) 7889 _, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword+"1") 7890 assert.Error(t, err) 7891 apiToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 7892 assert.NoError(t, err) 7893 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 7894 assert.NoError(t, err) 7895 // a web token is not valid for API usage 7896 req, err := http.NewRequest(http.MethodGet, userDirsPath, nil) 7897 assert.NoError(t, err) 7898 setBearerForReq(req, webToken) 7899 rr := executeRequest(req) 7900 checkResponseCode(t, http.StatusUnauthorized, rr) 7901 assert.Contains(t, rr.Body.String(), "Your token audience is not valid") 7902 7903 req, err = http.NewRequest(http.MethodGet, userDirsPath+"/?path=%2F", nil) 7904 assert.NoError(t, err) 7905 setBearerForReq(req, apiToken) 7906 rr = executeRequest(req) 7907 checkResponseCode(t, http.StatusOK, rr) 7908 // API token is not valid for web usage 7909 req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil) 7910 setJWTCookieForReq(req, apiToken) 7911 rr = executeRequest(req) 7912 checkResponseCode(t, http.StatusFound, rr) 7913 assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) 7914 7915 req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil) 7916 setJWTCookieForReq(req, webToken) 7917 rr = executeRequest(req) 7918 checkResponseCode(t, http.StatusOK, rr) 7919 7920 _, err = httpdtest.RemoveUser(user, http.StatusOK) 7921 assert.NoError(t, err) 7922 err = os.RemoveAll(user.GetHomeDir()) 7923 assert.NoError(t, err) 7924} 7925 7926func TestWebClientLoginMock(t *testing.T) { 7927 _, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 7928 assert.Error(t, err) 7929 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 7930 assert.NoError(t, err) 7931 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 7932 assert.NoError(t, err) 7933 // a web token is not valid for API or WebAdmin usage 7934 req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil) 7935 setBearerForReq(req, webToken) 7936 rr := executeRequest(req) 7937 checkResponseCode(t, http.StatusUnauthorized, rr) 7938 assert.Contains(t, rr.Body.String(), "Your token audience is not valid") 7939 req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil) 7940 setJWTCookieForReq(req, webToken) 7941 rr = executeRequest(req) 7942 checkResponseCode(t, http.StatusFound, rr) 7943 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 7944 // bearer should not work 7945 req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil) 7946 setBearerForReq(req, webToken) 7947 rr = executeRequest(req) 7948 checkResponseCode(t, http.StatusFound, rr) 7949 assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) 7950 // now try to render client pages 7951 req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil) 7952 setJWTCookieForReq(req, webToken) 7953 rr = executeRequest(req) 7954 checkResponseCode(t, http.StatusOK, rr) 7955 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil) 7956 setJWTCookieForReq(req, webToken) 7957 rr = executeRequest(req) 7958 checkResponseCode(t, http.StatusOK, rr) 7959 // now logout 7960 req, _ = http.NewRequest(http.MethodGet, webClientLogoutPath, nil) 7961 setJWTCookieForReq(req, webToken) 7962 rr = executeRequest(req) 7963 checkResponseCode(t, http.StatusFound, rr) 7964 assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) 7965 req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil) 7966 setJWTCookieForReq(req, webToken) 7967 rr = executeRequest(req) 7968 checkResponseCode(t, http.StatusFound, rr) 7969 assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) 7970 7971 // get a new token and use it after removing the user 7972 webToken, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 7973 assert.NoError(t, err) 7974 apiUserToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 7975 assert.NoError(t, err) 7976 _, err = httpdtest.RemoveUser(user, http.StatusOK) 7977 assert.NoError(t, err) 7978 err = os.RemoveAll(user.GetHomeDir()) 7979 assert.NoError(t, err) 7980 7981 req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil) 7982 setJWTCookieForReq(req, webToken) 7983 rr = executeRequest(req) 7984 checkResponseCode(t, http.StatusInternalServerError, rr) 7985 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil) 7986 setJWTCookieForReq(req, webToken) 7987 rr = executeRequest(req) 7988 checkResponseCode(t, http.StatusNotFound, rr) 7989 assert.Contains(t, rr.Body.String(), "Unable to retrieve your user") 7990 7991 req, _ = http.NewRequest(http.MethodGet, webClientDirsPath, nil) 7992 setJWTCookieForReq(req, webToken) 7993 rr = executeRequest(req) 7994 checkResponseCode(t, http.StatusNotFound, rr) 7995 assert.Contains(t, rr.Body.String(), "Unable to retrieve your user") 7996 7997 req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath, nil) 7998 setJWTCookieForReq(req, webToken) 7999 rr = executeRequest(req) 8000 checkResponseCode(t, http.StatusNotFound, rr) 8001 assert.Contains(t, rr.Body.String(), "Unable to retrieve your user") 8002 8003 req, _ = http.NewRequest(http.MethodGet, userDirsPath, nil) 8004 setBearerForReq(req, apiUserToken) 8005 rr = executeRequest(req) 8006 checkResponseCode(t, http.StatusNotFound, rr) 8007 assert.Contains(t, rr.Body.String(), "Unable to retrieve your user") 8008 8009 req, _ = http.NewRequest(http.MethodGet, userFilesPath, nil) 8010 setBearerForReq(req, apiUserToken) 8011 rr = executeRequest(req) 8012 checkResponseCode(t, http.StatusNotFound, rr) 8013 assert.Contains(t, rr.Body.String(), "Unable to retrieve your user") 8014 8015 req, _ = http.NewRequest(http.MethodPost, userStreamZipPath, bytes.NewBuffer([]byte(`{}`))) 8016 setBearerForReq(req, apiUserToken) 8017 rr = executeRequest(req) 8018 checkResponseCode(t, http.StatusNotFound, rr) 8019 assert.Contains(t, rr.Body.String(), "Unable to retrieve your user") 8020 8021 req, _ = http.NewRequest(http.MethodGet, userPublicKeysPath, nil) 8022 setBearerForReq(req, apiUserToken) 8023 rr = executeRequest(req) 8024 checkResponseCode(t, http.StatusNotFound, rr) 8025 assert.Contains(t, rr.Body.String(), "Unable to retrieve your user") 8026 8027 req, _ = http.NewRequest(http.MethodPut, userPublicKeysPath, bytes.NewBuffer([]byte(`{}`))) 8028 setBearerForReq(req, apiUserToken) 8029 rr = executeRequest(req) 8030 checkResponseCode(t, http.StatusNotFound, rr) 8031 assert.Contains(t, rr.Body.String(), "Unable to retrieve your user") 8032 8033 csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath) 8034 assert.NoError(t, err) 8035 form := make(url.Values) 8036 form.Set("public_keys", testPubKey) 8037 form.Set(csrfFormToken, csrfToken) 8038 req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 8039 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8040 setJWTCookieForReq(req, webToken) 8041 rr = executeRequest(req) 8042 checkResponseCode(t, http.StatusInternalServerError, rr) 8043} 8044 8045func TestWebClientLoginErrorsMock(t *testing.T) { 8046 form := getLoginForm("", "", "") 8047 req, _ := http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 8048 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8049 rr := executeRequest(req) 8050 assert.Equal(t, http.StatusOK, rr.Code) 8051 assert.Contains(t, rr.Body.String(), "Invalid credentials") 8052 8053 form = getLoginForm(defaultUsername, defaultPassword, "") 8054 req, _ = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 8055 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8056 rr = executeRequest(req) 8057 assert.Equal(t, http.StatusOK, rr.Code) 8058 assert.Contains(t, rr.Body.String(), "unable to verify form token") 8059} 8060 8061func TestWebClientMaxConnections(t *testing.T) { 8062 oldValue := common.Config.MaxTotalConnections 8063 common.Config.MaxTotalConnections = 1 8064 8065 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 8066 assert.NoError(t, err) 8067 8068 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8069 assert.NoError(t, err) 8070 req, _ := http.NewRequest(http.MethodGet, webClientFilesPath, nil) 8071 setJWTCookieForReq(req, webToken) 8072 rr := executeRequest(req) 8073 checkResponseCode(t, http.StatusOK, rr) 8074 8075 // now add a fake connection 8076 fs := vfs.NewOsFs("id", os.TempDir(), "") 8077 connection := &httpd.Connection{ 8078 BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolHTTP, "", "", user), 8079 } 8080 common.Connections.Add(connection) 8081 8082 _, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8083 assert.Error(t, err) 8084 8085 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil) 8086 setJWTCookieForReq(req, webToken) 8087 rr = executeRequest(req) 8088 checkResponseCode(t, http.StatusForbidden, rr) 8089 assert.Contains(t, rr.Body.String(), "configured connections limit reached") 8090 8091 common.Connections.Remove(connection.GetID()) 8092 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8093 assert.NoError(t, err) 8094 err = os.RemoveAll(user.GetHomeDir()) 8095 assert.NoError(t, err) 8096 assert.Len(t, common.Connections.GetStats(), 0) 8097 8098 common.Config.MaxTotalConnections = oldValue 8099} 8100 8101func TestDefender(t *testing.T) { 8102 oldConfig := config.GetCommonConfig() 8103 8104 cfg := config.GetCommonConfig() 8105 cfg.DefenderConfig.Enabled = true 8106 cfg.DefenderConfig.Threshold = 3 8107 cfg.DefenderConfig.ScoreLimitExceeded = 2 8108 8109 err := common.Initialize(cfg) 8110 assert.NoError(t, err) 8111 8112 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 8113 assert.NoError(t, err) 8114 8115 remoteAddr := "172.16.5.6:9876" 8116 8117 webAdminToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 8118 assert.NoError(t, err) 8119 webToken, err := getJWTWebClientTokenFromTestServerWithAddr(defaultUsername, defaultPassword, remoteAddr) 8120 assert.NoError(t, err) 8121 8122 req, _ := http.NewRequest(http.MethodGet, webClientFilesPath, nil) 8123 req.RemoteAddr = remoteAddr 8124 req.RequestURI = webClientFilesPath 8125 setJWTCookieForReq(req, webToken) 8126 rr := executeRequest(req) 8127 checkResponseCode(t, http.StatusOK, rr) 8128 8129 for i := 0; i < 3; i++ { 8130 _, err = getJWTWebClientTokenFromTestServerWithAddr(defaultUsername, "wrong pwd", remoteAddr) 8131 assert.Error(t, err) 8132 } 8133 8134 _, err = getJWTWebClientTokenFromTestServerWithAddr(defaultUsername, defaultPassword, remoteAddr) 8135 assert.Error(t, err) 8136 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil) 8137 req.RemoteAddr = remoteAddr 8138 req.RequestURI = webClientFilesPath 8139 setJWTCookieForReq(req, webToken) 8140 rr = executeRequest(req) 8141 checkResponseCode(t, http.StatusForbidden, rr) 8142 assert.Contains(t, rr.Body.String(), "your IP address is banned") 8143 8144 req, _ = http.NewRequest(http.MethodGet, webUsersPath, nil) 8145 req.RemoteAddr = remoteAddr 8146 req.RequestURI = webUsersPath 8147 setJWTCookieForReq(req, webAdminToken) 8148 rr = executeRequest(req) 8149 checkResponseCode(t, http.StatusForbidden, rr) 8150 assert.Contains(t, rr.Body.String(), "your IP address is banned") 8151 8152 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil) 8153 req.RemoteAddr = remoteAddr 8154 req.Header.Set("X-Real-IP", "127.0.0.1:2345") 8155 setJWTCookieForReq(req, webToken) 8156 rr = executeRequest(req) 8157 checkResponseCode(t, http.StatusForbidden, rr) 8158 assert.Contains(t, rr.Body.String(), "your IP address is banned") 8159 8160 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8161 assert.NoError(t, err) 8162 err = os.RemoveAll(user.GetHomeDir()) 8163 assert.NoError(t, err) 8164 8165 err = common.Initialize(oldConfig) 8166 assert.NoError(t, err) 8167} 8168 8169func TestPostConnectHook(t *testing.T) { 8170 if runtime.GOOS == osWindows { 8171 t.Skip("this test is not available on Windows") 8172 } 8173 common.Config.PostConnectHook = postConnectPath 8174 8175 u := getTestUser() 8176 u.Filters.AllowAPIKeyAuth = true 8177 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 8178 assert.NoError(t, err) 8179 apiKey, _, err := httpdtest.AddAPIKey(dataprovider.APIKey{ 8180 Name: "name", 8181 Scope: dataprovider.APIKeyScopeUser, 8182 User: user.Username, 8183 }, http.StatusCreated) 8184 assert.NoError(t, err) 8185 err = os.WriteFile(postConnectPath, getExitCodeScriptContent(0), os.ModePerm) 8186 assert.NoError(t, err) 8187 8188 _, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8189 assert.NoError(t, err) 8190 8191 _, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8192 assert.NoError(t, err) 8193 8194 req, err := http.NewRequest(http.MethodGet, userDirsPath, nil) 8195 assert.NoError(t, err) 8196 setAPIKeyForReq(req, apiKey.Key, "") 8197 rr := executeRequest(req) 8198 checkResponseCode(t, http.StatusOK, rr) 8199 8200 err = os.WriteFile(postConnectPath, getExitCodeScriptContent(1), os.ModePerm) 8201 assert.NoError(t, err) 8202 8203 _, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8204 assert.Error(t, err) 8205 8206 _, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8207 assert.Error(t, err) 8208 8209 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 8210 assert.NoError(t, err) 8211 setAPIKeyForReq(req, apiKey.Key, "") 8212 rr = executeRequest(req) 8213 checkResponseCode(t, http.StatusUnauthorized, rr) 8214 8215 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8216 assert.NoError(t, err) 8217 err = os.RemoveAll(user.GetHomeDir()) 8218 assert.NoError(t, err) 8219 8220 common.Config.PostConnectHook = "" 8221} 8222 8223func TestMaxSessions(t *testing.T) { 8224 u := getTestUser() 8225 u.MaxSessions = 1 8226 u.Email = "user@session.com" 8227 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 8228 assert.NoError(t, err) 8229 _, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8230 assert.NoError(t, err) 8231 _, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8232 assert.NoError(t, err) 8233 // now add a fake connection 8234 fs := vfs.NewOsFs("id", os.TempDir(), "") 8235 connection := &httpd.Connection{ 8236 BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolHTTP, "", "", user), 8237 } 8238 common.Connections.Add(connection) 8239 _, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8240 assert.Error(t, err) 8241 _, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8242 assert.Error(t, err) 8243 // test reset password 8244 smtpCfg := smtp.Config{ 8245 Host: "127.0.0.1", 8246 Port: 3525, 8247 TemplatesPath: "templates", 8248 } 8249 err = smtpCfg.Initialize("..") 8250 assert.NoError(t, err) 8251 8252 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 8253 assert.NoError(t, err) 8254 form := make(url.Values) 8255 form.Set(csrfFormToken, csrfToken) 8256 form.Set("username", user.Username) 8257 lastResetCode = "" 8258 req, err := http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 8259 assert.NoError(t, err) 8260 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8261 rr := executeRequest(req) 8262 assert.Equal(t, http.StatusFound, rr.Code) 8263 assert.GreaterOrEqual(t, len(lastResetCode), 20) 8264 form = make(url.Values) 8265 form.Set(csrfFormToken, csrfToken) 8266 form.Set("password", defaultPassword) 8267 form.Set("code", lastResetCode) 8268 req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 8269 assert.NoError(t, err) 8270 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8271 rr = executeRequest(req) 8272 assert.Equal(t, http.StatusOK, rr.Code) 8273 assert.Contains(t, rr.Body.String(), "Password reset successfully but unable to login") 8274 8275 smtpCfg = smtp.Config{} 8276 err = smtpCfg.Initialize("..") 8277 require.NoError(t, err) 8278 8279 common.Connections.Remove(connection.GetID()) 8280 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8281 assert.NoError(t, err) 8282 err = os.RemoveAll(user.GetHomeDir()) 8283 assert.NoError(t, err) 8284 assert.Len(t, common.Connections.GetStats(), 0) 8285} 8286 8287func TestSFTPLoopError(t *testing.T) { 8288 user1 := getTestUser() 8289 user2 := getTestUser() 8290 user1.Username += "1" 8291 user1.Email = "user1@test.com" 8292 user2.Username += "2" 8293 user1.FsConfig = vfs.Filesystem{ 8294 Provider: sdk.SFTPFilesystemProvider, 8295 SFTPConfig: vfs.SFTPFsConfig{ 8296 SFTPFsConfig: sdk.SFTPFsConfig{ 8297 Endpoint: sftpServerAddr, 8298 Username: user2.Username, 8299 Password: kms.NewPlainSecret(defaultPassword), 8300 }, 8301 }, 8302 } 8303 8304 user2.FsConfig.Provider = sdk.SFTPFilesystemProvider 8305 user2.FsConfig.SFTPConfig = vfs.SFTPFsConfig{ 8306 SFTPFsConfig: sdk.SFTPFsConfig{ 8307 Endpoint: sftpServerAddr, 8308 Username: user1.Username, 8309 Password: kms.NewPlainSecret(defaultPassword), 8310 }, 8311 } 8312 8313 user1, resp, err := httpdtest.AddUser(user1, http.StatusCreated) 8314 assert.NoError(t, err, string(resp)) 8315 user2, resp, err = httpdtest.AddUser(user2, http.StatusCreated) 8316 assert.NoError(t, err, string(resp)) 8317 8318 // test reset password 8319 smtpCfg := smtp.Config{ 8320 Host: "127.0.0.1", 8321 Port: 3525, 8322 TemplatesPath: "templates", 8323 } 8324 err = smtpCfg.Initialize("..") 8325 assert.NoError(t, err) 8326 8327 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 8328 assert.NoError(t, err) 8329 form := make(url.Values) 8330 form.Set(csrfFormToken, csrfToken) 8331 form.Set("username", user1.Username) 8332 lastResetCode = "" 8333 req, err := http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 8334 assert.NoError(t, err) 8335 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8336 rr := executeRequest(req) 8337 assert.Equal(t, http.StatusFound, rr.Code) 8338 assert.GreaterOrEqual(t, len(lastResetCode), 20) 8339 form = make(url.Values) 8340 form.Set(csrfFormToken, csrfToken) 8341 form.Set("password", defaultPassword) 8342 form.Set("code", lastResetCode) 8343 req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 8344 assert.NoError(t, err) 8345 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8346 rr = executeRequest(req) 8347 assert.Equal(t, http.StatusOK, rr.Code) 8348 assert.Contains(t, rr.Body.String(), "Password reset successfully but unable to login") 8349 8350 smtpCfg = smtp.Config{} 8351 err = smtpCfg.Initialize("..") 8352 require.NoError(t, err) 8353 8354 _, err = httpdtest.RemoveUser(user1, http.StatusOK) 8355 assert.NoError(t, err) 8356 err = os.RemoveAll(user1.GetHomeDir()) 8357 assert.NoError(t, err) 8358 _, err = httpdtest.RemoveUser(user2, http.StatusOK) 8359 assert.NoError(t, err) 8360 err = os.RemoveAll(user2.GetHomeDir()) 8361 assert.NoError(t, err) 8362} 8363 8364func TestLoginInvalidFs(t *testing.T) { 8365 u := getTestUser() 8366 u.Filters.AllowAPIKeyAuth = true 8367 u.FsConfig.Provider = sdk.GCSFilesystemProvider 8368 u.FsConfig.GCSConfig.Bucket = "test" 8369 u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("invalid JSON for credentials") 8370 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 8371 assert.NoError(t, err) 8372 apiKey, _, err := httpdtest.AddAPIKey(dataprovider.APIKey{ 8373 Name: "testk", 8374 Scope: dataprovider.APIKeyScopeUser, 8375 User: u.Username, 8376 }, http.StatusCreated) 8377 assert.NoError(t, err) 8378 8379 credentialsFile := filepath.Join(credentialsPath, fmt.Sprintf("%v_gcs_credentials.json", u.Username)) 8380 if !filepath.IsAbs(credentialsFile) { 8381 credentialsFile = filepath.Join(configDir, credentialsFile) 8382 } 8383 8384 // now remove the credentials file so the filesystem creation will fail 8385 err = os.Remove(credentialsFile) 8386 assert.NoError(t, err) 8387 8388 _, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8389 assert.Error(t, err) 8390 8391 _, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8392 assert.Error(t, err) 8393 8394 req, err := http.NewRequest(http.MethodGet, userDirsPath, nil) 8395 assert.NoError(t, err) 8396 setAPIKeyForReq(req, apiKey.Key, "") 8397 rr := executeRequest(req) 8398 checkResponseCode(t, http.StatusInternalServerError, rr) 8399 8400 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8401 assert.NoError(t, err) 8402 err = os.RemoveAll(user.GetHomeDir()) 8403 assert.NoError(t, err) 8404} 8405 8406func TestWebClientChangePwd(t *testing.T) { 8407 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 8408 assert.NoError(t, err) 8409 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8410 assert.NoError(t, err) 8411 csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath) 8412 assert.NoError(t, err) 8413 8414 req, err := http.NewRequest(http.MethodGet, webChangeClientPwdPath, nil) 8415 assert.NoError(t, err) 8416 setJWTCookieForReq(req, webToken) 8417 rr := executeRequest(req) 8418 checkResponseCode(t, http.StatusOK, rr) 8419 8420 form := make(url.Values) 8421 form.Set("current_password", defaultPassword) 8422 form.Set("new_password1", defaultPassword) 8423 form.Set("new_password2", defaultPassword) 8424 // no csrf token 8425 req, err = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 8426 assert.NoError(t, err) 8427 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8428 setJWTCookieForReq(req, webToken) 8429 rr = executeRequest(req) 8430 checkResponseCode(t, http.StatusForbidden, rr) 8431 assert.Contains(t, rr.Body.String(), "unable to verify form token") 8432 8433 form.Set(csrfFormToken, csrfToken) 8434 req, _ = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 8435 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8436 setJWTCookieForReq(req, webToken) 8437 rr = executeRequest(req) 8438 checkResponseCode(t, http.StatusOK, rr) 8439 assert.Contains(t, rr.Body.String(), "the new password must be different from the current one") 8440 8441 form.Set("current_password", defaultPassword+"2") 8442 form.Set("new_password1", defaultPassword+"1") 8443 form.Set("new_password2", defaultPassword+"1") 8444 req, _ = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 8445 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8446 setJWTCookieForReq(req, webToken) 8447 rr = executeRequest(req) 8448 checkResponseCode(t, http.StatusOK, rr) 8449 assert.Contains(t, rr.Body.String(), "current password does not match") 8450 8451 form.Set("current_password", defaultPassword) 8452 form.Set("new_password1", defaultPassword+"1") 8453 form.Set("new_password2", defaultPassword+"1") 8454 req, _ = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 8455 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8456 setJWTCookieForReq(req, webToken) 8457 rr = executeRequest(req) 8458 checkResponseCode(t, http.StatusFound, rr) 8459 assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) 8460 8461 _, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8462 assert.Error(t, err) 8463 _, err = getJWTWebClientTokenFromTestServer(defaultUsername+"1", defaultPassword+"1") 8464 assert.Error(t, err) 8465 _, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword+"1") 8466 assert.NoError(t, err) 8467 8468 // remove the change password permission 8469 user.Filters.WebClient = []string{sdk.WebClientPasswordChangeDisabled} 8470 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 8471 assert.NoError(t, err) 8472 assert.Len(t, user.Filters.WebClient, 1) 8473 assert.Contains(t, user.Filters.WebClient, sdk.WebClientPasswordChangeDisabled) 8474 8475 webToken, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword+"1") 8476 assert.NoError(t, err) 8477 form.Set("current_password", defaultPassword+"1") 8478 form.Set("new_password1", defaultPassword) 8479 form.Set("new_password2", defaultPassword) 8480 req, _ = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 8481 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 8482 setJWTCookieForReq(req, webToken) 8483 rr = executeRequest(req) 8484 checkResponseCode(t, http.StatusForbidden, rr) 8485 8486 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8487 assert.NoError(t, err) 8488 err = os.RemoveAll(user.GetHomeDir()) 8489 assert.NoError(t, err) 8490} 8491 8492func TestWebAPIPublicKeys(t *testing.T) { 8493 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 8494 assert.NoError(t, err) 8495 apiToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8496 assert.NoError(t, err) 8497 8498 req, err := http.NewRequest(http.MethodGet, userPublicKeysPath, nil) 8499 assert.NoError(t, err) 8500 setBearerForReq(req, apiToken) 8501 rr := executeRequest(req) 8502 checkResponseCode(t, http.StatusOK, rr) 8503 var keys []string 8504 err = json.Unmarshal(rr.Body.Bytes(), &keys) 8505 assert.NoError(t, err) 8506 assert.Len(t, keys, 0) 8507 8508 keys = []string{testPubKey, testPubKey1} 8509 asJSON, err := json.Marshal(keys) 8510 assert.NoError(t, err) 8511 req, err = http.NewRequest(http.MethodPut, userPublicKeysPath, bytes.NewBuffer(asJSON)) 8512 assert.NoError(t, err) 8513 setBearerForReq(req, apiToken) 8514 rr = executeRequest(req) 8515 checkResponseCode(t, http.StatusOK, rr) 8516 8517 req, err = http.NewRequest(http.MethodGet, userPublicKeysPath, nil) 8518 assert.NoError(t, err) 8519 setBearerForReq(req, apiToken) 8520 rr = executeRequest(req) 8521 checkResponseCode(t, http.StatusOK, rr) 8522 keys = nil 8523 err = json.Unmarshal(rr.Body.Bytes(), &keys) 8524 assert.NoError(t, err) 8525 assert.Len(t, keys, 2) 8526 8527 req, err = http.NewRequest(http.MethodPut, userPublicKeysPath, bytes.NewBuffer([]byte(`invalid json`))) 8528 assert.NoError(t, err) 8529 setBearerForReq(req, apiToken) 8530 rr = executeRequest(req) 8531 checkResponseCode(t, http.StatusBadRequest, rr) 8532 8533 keys = []string{`not a public key`} 8534 asJSON, err = json.Marshal(keys) 8535 assert.NoError(t, err) 8536 req, err = http.NewRequest(http.MethodPut, userPublicKeysPath, bytes.NewBuffer(asJSON)) 8537 assert.NoError(t, err) 8538 setBearerForReq(req, apiToken) 8539 rr = executeRequest(req) 8540 checkResponseCode(t, http.StatusBadRequest, rr) 8541 assert.Contains(t, rr.Body.String(), "could not parse key") 8542 8543 user.Filters.WebClient = append(user.Filters.WebClient, sdk.WebClientPubKeyChangeDisabled) 8544 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 8545 assert.NoError(t, err) 8546 8547 apiToken, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8548 assert.NoError(t, err) 8549 req, err = http.NewRequest(http.MethodGet, userPublicKeysPath, nil) 8550 assert.NoError(t, err) 8551 setBearerForReq(req, apiToken) 8552 rr = executeRequest(req) 8553 checkResponseCode(t, http.StatusForbidden, rr) 8554 8555 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8556 assert.NoError(t, err) 8557 err = os.RemoveAll(user.GetHomeDir()) 8558 assert.NoError(t, err) 8559} 8560 8561func TestPreDownloadHook(t *testing.T) { 8562 if runtime.GOOS == osWindows { 8563 t.Skip("this test is not available on Windows") 8564 } 8565 oldExecuteOn := common.Config.Actions.ExecuteOn 8566 oldHook := common.Config.Actions.Hook 8567 8568 common.Config.Actions.ExecuteOn = []string{common.OperationPreDownload} 8569 common.Config.Actions.Hook = preActionPath 8570 8571 u := getTestUser() 8572 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 8573 assert.NoError(t, err) 8574 err = os.WriteFile(preActionPath, getExitCodeScriptContent(0), os.ModePerm) 8575 assert.NoError(t, err) 8576 8577 testFileName := "testfile" 8578 testFileContents := []byte("file contents") 8579 err = os.MkdirAll(filepath.Join(user.GetHomeDir()), os.ModePerm) 8580 assert.NoError(t, err) 8581 err = os.WriteFile(filepath.Join(user.GetHomeDir(), testFileName), testFileContents, os.ModePerm) 8582 assert.NoError(t, err) 8583 8584 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 8585 assert.NoError(t, err) 8586 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8587 assert.NoError(t, err) 8588 req, err := http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 8589 assert.NoError(t, err) 8590 setJWTCookieForReq(req, webToken) 8591 rr := executeRequest(req) 8592 checkResponseCode(t, http.StatusOK, rr) 8593 assert.Equal(t, testFileContents, rr.Body.Bytes()) 8594 8595 req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil) 8596 assert.NoError(t, err) 8597 setBearerForReq(req, webAPIToken) 8598 rr = executeRequest(req) 8599 checkResponseCode(t, http.StatusOK, rr) 8600 assert.Equal(t, testFileContents, rr.Body.Bytes()) 8601 8602 err = os.WriteFile(preActionPath, getExitCodeScriptContent(1), os.ModePerm) 8603 assert.NoError(t, err) 8604 req, err = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 8605 assert.NoError(t, err) 8606 setJWTCookieForReq(req, webToken) 8607 rr = executeRequest(req) 8608 checkResponseCode(t, http.StatusOK, rr) 8609 assert.Contains(t, rr.Body.String(), "permission denied") 8610 8611 req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil) 8612 assert.NoError(t, err) 8613 setBearerForReq(req, webAPIToken) 8614 rr = executeRequest(req) 8615 checkResponseCode(t, http.StatusForbidden, rr) 8616 assert.Contains(t, rr.Body.String(), "permission denied") 8617 8618 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8619 assert.NoError(t, err) 8620 err = os.RemoveAll(user.GetHomeDir()) 8621 assert.NoError(t, err) 8622 8623 common.Config.Actions.ExecuteOn = oldExecuteOn 8624 common.Config.Actions.Hook = oldHook 8625} 8626 8627func TestPreUploadHook(t *testing.T) { 8628 if runtime.GOOS == osWindows { 8629 t.Skip("this test is not available on Windows") 8630 } 8631 oldExecuteOn := common.Config.Actions.ExecuteOn 8632 oldHook := common.Config.Actions.Hook 8633 8634 common.Config.Actions.ExecuteOn = []string{common.OperationPreUpload} 8635 common.Config.Actions.Hook = preActionPath 8636 8637 u := getTestUser() 8638 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 8639 assert.NoError(t, err) 8640 err = os.WriteFile(preActionPath, getExitCodeScriptContent(0), os.ModePerm) 8641 assert.NoError(t, err) 8642 8643 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8644 assert.NoError(t, err) 8645 8646 body := new(bytes.Buffer) 8647 writer := multipart.NewWriter(body) 8648 part, err := writer.CreateFormFile("filenames", "filepre") 8649 assert.NoError(t, err) 8650 _, err = part.Write([]byte("file content")) 8651 assert.NoError(t, err) 8652 err = writer.Close() 8653 assert.NoError(t, err) 8654 reader := bytes.NewReader(body.Bytes()) 8655 _, err = reader.Seek(0, io.SeekStart) 8656 assert.NoError(t, err) 8657 req, err := http.NewRequest(http.MethodPost, userFilesPath, reader) 8658 assert.NoError(t, err) 8659 req.Header.Add("Content-Type", writer.FormDataContentType()) 8660 setBearerForReq(req, webAPIToken) 8661 rr := executeRequest(req) 8662 checkResponseCode(t, http.StatusCreated, rr) 8663 8664 err = os.WriteFile(preActionPath, getExitCodeScriptContent(1), os.ModePerm) 8665 assert.NoError(t, err) 8666 _, err = reader.Seek(0, io.SeekStart) 8667 assert.NoError(t, err) 8668 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 8669 assert.NoError(t, err) 8670 req.Header.Add("Content-Type", writer.FormDataContentType()) 8671 setBearerForReq(req, webAPIToken) 8672 rr = executeRequest(req) 8673 checkResponseCode(t, http.StatusForbidden, rr) 8674 8675 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8676 assert.NoError(t, err) 8677 err = os.RemoveAll(user.GetHomeDir()) 8678 assert.NoError(t, err) 8679 8680 common.Config.Actions.ExecuteOn = oldExecuteOn 8681 common.Config.Actions.Hook = oldHook 8682} 8683 8684func TestShareUsage(t *testing.T) { 8685 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 8686 assert.NoError(t, err) 8687 8688 testFileName := "testfile.dat" 8689 testFileSize := int64(65536) 8690 testFilePath := filepath.Join(user.GetHomeDir(), testFileName) 8691 err = createTestFile(testFilePath, testFileSize) 8692 assert.NoError(t, err) 8693 8694 token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8695 assert.NoError(t, err) 8696 8697 share := dataprovider.Share{ 8698 Name: "test share", 8699 Scope: dataprovider.ShareScopeRead, 8700 Paths: []string{"/"}, 8701 Password: defaultPassword, 8702 MaxTokens: 2, 8703 ExpiresAt: util.GetTimeAsMsSinceEpoch(time.Now().Add(1 * time.Second)), 8704 } 8705 asJSON, err := json.Marshal(share) 8706 assert.NoError(t, err) 8707 req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 8708 assert.NoError(t, err) 8709 setBearerForReq(req, token) 8710 rr := executeRequest(req) 8711 checkResponseCode(t, http.StatusCreated, rr) 8712 objectID := rr.Header().Get("X-Object-ID") 8713 assert.NotEmpty(t, objectID) 8714 8715 req, err = http.NewRequest(http.MethodGet, sharesPath+"/unknownid", nil) 8716 assert.NoError(t, err) 8717 rr = executeRequest(req) 8718 checkResponseCode(t, http.StatusNotFound, rr) 8719 8720 req, err = http.NewRequest(http.MethodGet, sharesPath+"/"+objectID, nil) 8721 assert.NoError(t, err) 8722 rr = executeRequest(req) 8723 checkResponseCode(t, http.StatusUnauthorized, rr) 8724 8725 req.SetBasicAuth(defaultUsername, "wrong password") 8726 rr = executeRequest(req) 8727 checkResponseCode(t, http.StatusUnauthorized, rr) 8728 8729 req.SetBasicAuth(defaultUsername, defaultPassword) 8730 rr = executeRequest(req) 8731 checkResponseCode(t, http.StatusOK, rr) 8732 8733 time.Sleep(2 * time.Second) 8734 8735 req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID, nil) 8736 assert.NoError(t, err) 8737 req.SetBasicAuth(defaultUsername, defaultPassword) 8738 rr = executeRequest(req) 8739 checkResponseCode(t, http.StatusNotFound, rr) 8740 8741 share.ExpiresAt = 0 8742 jsonReq := make(map[string]interface{}) 8743 jsonReq["name"] = share.Name 8744 jsonReq["scope"] = share.Scope 8745 jsonReq["paths"] = share.Paths 8746 jsonReq["password"] = share.Password 8747 jsonReq["max_tokens"] = share.MaxTokens 8748 jsonReq["expires_at"] = share.ExpiresAt 8749 asJSON, err = json.Marshal(jsonReq) 8750 assert.NoError(t, err) 8751 req, err = http.NewRequest(http.MethodPut, userSharesPath+"/"+objectID, bytes.NewBuffer(asJSON)) 8752 assert.NoError(t, err) 8753 setBearerForReq(req, token) 8754 rr = executeRequest(req) 8755 checkResponseCode(t, http.StatusOK, rr) 8756 8757 req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID, nil) 8758 assert.NoError(t, err) 8759 req.SetBasicAuth(defaultUsername, defaultPassword) 8760 rr = executeRequest(req) 8761 checkResponseCode(t, http.StatusOK, rr) 8762 8763 rr = executeRequest(req) 8764 checkResponseCode(t, http.StatusNotFound, rr) 8765 8766 req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, nil) 8767 assert.NoError(t, err) 8768 rr = executeRequest(req) 8769 checkResponseCode(t, http.StatusForbidden, rr) 8770 assert.Contains(t, rr.Body.String(), "Invalid share scope") 8771 8772 share.MaxTokens = 3 8773 share.Scope = dataprovider.ShareScopeWrite 8774 asJSON, err = json.Marshal(share) 8775 assert.NoError(t, err) 8776 req, err = http.NewRequest(http.MethodPut, userSharesPath+"/"+objectID, bytes.NewBuffer(asJSON)) 8777 assert.NoError(t, err) 8778 setBearerForReq(req, token) 8779 rr = executeRequest(req) 8780 checkResponseCode(t, http.StatusOK, rr) 8781 8782 body := new(bytes.Buffer) 8783 writer := multipart.NewWriter(body) 8784 part1, err := writer.CreateFormFile("filenames", "file1.txt") 8785 assert.NoError(t, err) 8786 _, err = part1.Write([]byte("file1 content")) 8787 assert.NoError(t, err) 8788 part2, err := writer.CreateFormFile("filenames", "file2.txt") 8789 assert.NoError(t, err) 8790 _, err = part2.Write([]byte("file2 content")) 8791 assert.NoError(t, err) 8792 err = writer.Close() 8793 assert.NoError(t, err) 8794 reader := bytes.NewReader(body.Bytes()) 8795 8796 req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader) 8797 assert.NoError(t, err) 8798 req.SetBasicAuth(defaultUsername, defaultPassword) 8799 rr = executeRequest(req) 8800 checkResponseCode(t, http.StatusBadRequest, rr) 8801 assert.Contains(t, rr.Body.String(), "Unable to parse multipart form") 8802 8803 _, err = reader.Seek(0, io.SeekStart) 8804 assert.NoError(t, err) 8805 // set the proper content type 8806 req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader) 8807 assert.NoError(t, err) 8808 req.Header.Add("Content-Type", writer.FormDataContentType()) 8809 req.SetBasicAuth(defaultUsername, defaultPassword) 8810 rr = executeRequest(req) 8811 checkResponseCode(t, http.StatusBadRequest, rr) 8812 assert.Contains(t, rr.Body.String(), "Allowed usage exceeded") 8813 8814 share.MaxTokens = 6 8815 share.Scope = dataprovider.ShareScopeWrite 8816 asJSON, err = json.Marshal(share) 8817 assert.NoError(t, err) 8818 req, err = http.NewRequest(http.MethodPut, userSharesPath+"/"+objectID, bytes.NewBuffer(asJSON)) 8819 assert.NoError(t, err) 8820 setBearerForReq(req, token) 8821 rr = executeRequest(req) 8822 checkResponseCode(t, http.StatusOK, rr) 8823 8824 _, err = reader.Seek(0, io.SeekStart) 8825 assert.NoError(t, err) 8826 req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader) 8827 assert.NoError(t, err) 8828 req.Header.Add("Content-Type", writer.FormDataContentType()) 8829 req.SetBasicAuth(defaultUsername, defaultPassword) 8830 rr = executeRequest(req) 8831 checkResponseCode(t, http.StatusCreated, rr) 8832 8833 _, err = reader.Seek(0, io.SeekStart) 8834 assert.NoError(t, err) 8835 req, err = http.NewRequest(http.MethodPost, webClientPubSharesPath+"/"+objectID, reader) 8836 assert.NoError(t, err) 8837 req.Header.Add("Content-Type", writer.FormDataContentType()) 8838 req.SetBasicAuth(defaultUsername, defaultPassword) 8839 rr = executeRequest(req) 8840 checkResponseCode(t, http.StatusCreated, rr) 8841 8842 share, err = dataprovider.ShareExists(objectID, user.Username) 8843 assert.NoError(t, err) 8844 assert.Equal(t, 6, share.UsedTokens) 8845 8846 _, err = reader.Seek(0, io.SeekStart) 8847 assert.NoError(t, err) 8848 req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader) 8849 assert.NoError(t, err) 8850 req.Header.Add("Content-Type", writer.FormDataContentType()) 8851 req.SetBasicAuth(defaultUsername, defaultPassword) 8852 rr = executeRequest(req) 8853 checkResponseCode(t, http.StatusNotFound, rr) 8854 8855 share.MaxTokens = 0 8856 err = dataprovider.UpdateShare(&share, user.Username, "") 8857 assert.NoError(t, err) 8858 8859 user.Permissions["/"] = []string{dataprovider.PermListItems, dataprovider.PermDownload} 8860 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 8861 assert.NoError(t, err) 8862 8863 _, err = reader.Seek(0, io.SeekStart) 8864 assert.NoError(t, err) 8865 req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader) 8866 assert.NoError(t, err) 8867 req.Header.Add("Content-Type", writer.FormDataContentType()) 8868 req.SetBasicAuth(defaultUsername, defaultPassword) 8869 rr = executeRequest(req) 8870 checkResponseCode(t, http.StatusInternalServerError, rr) 8871 assert.Contains(t, rr.Body.String(), "permission denied") 8872 8873 body = new(bytes.Buffer) 8874 writer = multipart.NewWriter(body) 8875 part, err := writer.CreateFormFile("filename", "file1.txt") 8876 assert.NoError(t, err) 8877 _, err = part.Write([]byte("file content")) 8878 assert.NoError(t, err) 8879 err = writer.Close() 8880 assert.NoError(t, err) 8881 reader = bytes.NewReader(body.Bytes()) 8882 8883 req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader) 8884 assert.NoError(t, err) 8885 req.Header.Add("Content-Type", writer.FormDataContentType()) 8886 req.SetBasicAuth(defaultUsername, defaultPassword) 8887 rr = executeRequest(req) 8888 checkResponseCode(t, http.StatusBadRequest, rr) 8889 assert.Contains(t, rr.Body.String(), "No files uploaded!") 8890 8891 share.Scope = dataprovider.ShareScopeRead 8892 share.Paths = []string{"/missing"} 8893 err = dataprovider.UpdateShare(&share, user.Username, "") 8894 assert.NoError(t, err) 8895 8896 defer func() { 8897 rcv := recover() 8898 assert.Equal(t, http.ErrAbortHandler, rcv) 8899 8900 share, err = dataprovider.ShareExists(objectID, user.Username) 8901 assert.NoError(t, err) 8902 assert.Equal(t, 6, share.UsedTokens) 8903 8904 _, err = httpdtest.RemoveUser(user, http.StatusOK) 8905 assert.NoError(t, err) 8906 err = os.RemoveAll(user.GetHomeDir()) 8907 assert.NoError(t, err) 8908 }() 8909 8910 req, err = http.NewRequest(http.MethodGet, sharesPath+"/"+objectID, nil) 8911 assert.NoError(t, err) 8912 req.SetBasicAuth(defaultUsername, defaultPassword) 8913 executeRequest(req) 8914} 8915 8916func TestUserAPIShareErrors(t *testing.T) { 8917 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 8918 assert.NoError(t, err) 8919 token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 8920 assert.NoError(t, err) 8921 8922 share := dataprovider.Share{ 8923 Scope: 1000, 8924 } 8925 asJSON, err := json.Marshal(share) 8926 assert.NoError(t, err) 8927 8928 req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 8929 assert.NoError(t, err) 8930 setBearerForReq(req, token) 8931 rr := executeRequest(req) 8932 checkResponseCode(t, http.StatusBadRequest, rr) 8933 assert.Contains(t, rr.Body.String(), "invalid scope") 8934 // invalid json 8935 req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer([]byte("{"))) 8936 assert.NoError(t, err) 8937 setBearerForReq(req, token) 8938 rr = executeRequest(req) 8939 checkResponseCode(t, http.StatusBadRequest, rr) 8940 8941 share.Scope = dataprovider.ShareScopeWrite 8942 asJSON, err = json.Marshal(share) 8943 assert.NoError(t, err) 8944 req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 8945 assert.NoError(t, err) 8946 setBearerForReq(req, token) 8947 rr = executeRequest(req) 8948 checkResponseCode(t, http.StatusBadRequest, rr) 8949 assert.Contains(t, rr.Body.String(), "at least a shared path is required") 8950 8951 share.Paths = []string{"path1", "../path1", "/path2"} 8952 asJSON, err = json.Marshal(share) 8953 assert.NoError(t, err) 8954 req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 8955 assert.NoError(t, err) 8956 setBearerForReq(req, token) 8957 rr = executeRequest(req) 8958 checkResponseCode(t, http.StatusBadRequest, rr) 8959 assert.Contains(t, rr.Body.String(), "the write share scope requires exactly one path") 8960 8961 share.Paths = []string{"", ""} 8962 asJSON, err = json.Marshal(share) 8963 assert.NoError(t, err) 8964 req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 8965 assert.NoError(t, err) 8966 setBearerForReq(req, token) 8967 rr = executeRequest(req) 8968 checkResponseCode(t, http.StatusBadRequest, rr) 8969 assert.Contains(t, rr.Body.String(), "at least a shared path is required") 8970 8971 share.Paths = []string{"path1", "../path1", "/path1"} 8972 share.Password = redactedSecret 8973 asJSON, err = json.Marshal(share) 8974 assert.NoError(t, err) 8975 req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 8976 assert.NoError(t, err) 8977 setBearerForReq(req, token) 8978 rr = executeRequest(req) 8979 checkResponseCode(t, http.StatusBadRequest, rr) 8980 assert.Contains(t, rr.Body.String(), "cannot save a share with a redacted password") 8981 8982 share.Password = "newpass" 8983 share.AllowFrom = []string{"not valid"} 8984 asJSON, err = json.Marshal(share) 8985 assert.NoError(t, err) 8986 req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 8987 assert.NoError(t, err) 8988 setBearerForReq(req, token) 8989 rr = executeRequest(req) 8990 checkResponseCode(t, http.StatusBadRequest, rr) 8991 assert.Contains(t, rr.Body.String(), "could not parse allow from entry") 8992 8993 share.AllowFrom = []string{"127.0.0.1/8"} 8994 share.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-12 * time.Hour)) 8995 asJSON, err = json.Marshal(share) 8996 assert.NoError(t, err) 8997 req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 8998 assert.NoError(t, err) 8999 setBearerForReq(req, token) 9000 rr = executeRequest(req) 9001 checkResponseCode(t, http.StatusBadRequest, rr) 9002 assert.Contains(t, rr.Body.String(), "expiration must be in the future") 9003 9004 share.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(12 * time.Hour)) 9005 asJSON, err = json.Marshal(share) 9006 assert.NoError(t, err) 9007 req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 9008 assert.NoError(t, err) 9009 setBearerForReq(req, token) 9010 rr = executeRequest(req) 9011 checkResponseCode(t, http.StatusCreated, rr) 9012 location := rr.Header().Get("Location") 9013 9014 asJSON, err = json.Marshal(share) 9015 assert.NoError(t, err) 9016 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON)) 9017 assert.NoError(t, err) 9018 setBearerForReq(req, token) 9019 rr = executeRequest(req) 9020 checkResponseCode(t, http.StatusBadRequest, rr) 9021 assert.Contains(t, rr.Body.String(), "name is mandatory") 9022 // invalid json 9023 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer([]byte("}"))) 9024 assert.NoError(t, err) 9025 setBearerForReq(req, token) 9026 rr = executeRequest(req) 9027 checkResponseCode(t, http.StatusBadRequest, rr) 9028 9029 req, err = http.NewRequest(http.MethodGet, userSharesPath+"?limit=a", nil) 9030 assert.NoError(t, err) 9031 setBearerForReq(req, token) 9032 rr = executeRequest(req) 9033 checkResponseCode(t, http.StatusBadRequest, rr) 9034 9035 _, err = httpdtest.RemoveUser(user, http.StatusOK) 9036 assert.NoError(t, err) 9037 err = os.RemoveAll(user.GetHomeDir()) 9038 assert.NoError(t, err) 9039} 9040 9041func TestUserAPIShares(t *testing.T) { 9042 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 9043 assert.NoError(t, err) 9044 token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 9045 assert.NoError(t, err) 9046 9047 u := getTestUser() 9048 u.Username = altAdminUsername 9049 user1, _, err := httpdtest.AddUser(u, http.StatusCreated) 9050 assert.NoError(t, err) 9051 token1, err := getJWTAPIUserTokenFromTestServer(user1.Username, defaultPassword) 9052 assert.NoError(t, err) 9053 9054 // the share username will be set from 9055 share := dataprovider.Share{ 9056 Name: "share1", 9057 Description: "description1", 9058 Scope: dataprovider.ShareScopeRead, 9059 Paths: []string{"/"}, 9060 CreatedAt: 1, 9061 UpdatedAt: 2, 9062 LastUseAt: 3, 9063 ExpiresAt: util.GetTimeAsMsSinceEpoch(time.Now().Add(2 * time.Hour)), 9064 Password: defaultPassword, 9065 MaxTokens: 10, 9066 UsedTokens: 2, 9067 AllowFrom: []string{"192.168.1.0/24"}, 9068 } 9069 asJSON, err := json.Marshal(share) 9070 assert.NoError(t, err) 9071 9072 req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 9073 assert.NoError(t, err) 9074 setBearerForReq(req, token) 9075 rr := executeRequest(req) 9076 checkResponseCode(t, http.StatusCreated, rr) 9077 location := rr.Header().Get("Location") 9078 assert.NotEmpty(t, location) 9079 objectID := rr.Header().Get("X-Object-ID") 9080 assert.NotEmpty(t, objectID) 9081 assert.Equal(t, fmt.Sprintf("%v/%v", userSharesPath, objectID), location) 9082 9083 req, err = http.NewRequest(http.MethodGet, location, nil) 9084 assert.NoError(t, err) 9085 setBearerForReq(req, token) 9086 rr = executeRequest(req) 9087 checkResponseCode(t, http.StatusOK, rr) 9088 var shareGet dataprovider.Share 9089 err = json.Unmarshal(rr.Body.Bytes(), &shareGet) 9090 assert.NoError(t, err) 9091 assert.Equal(t, objectID, shareGet.ShareID) 9092 assert.Equal(t, share.Name, shareGet.Name) 9093 assert.Equal(t, share.Description, shareGet.Description) 9094 assert.Equal(t, share.Scope, shareGet.Scope) 9095 assert.Equal(t, share.Paths, shareGet.Paths) 9096 assert.Equal(t, int64(0), shareGet.LastUseAt) 9097 assert.Greater(t, shareGet.CreatedAt, share.CreatedAt) 9098 assert.Greater(t, shareGet.UpdatedAt, share.UpdatedAt) 9099 assert.Equal(t, share.ExpiresAt, shareGet.ExpiresAt) 9100 assert.Equal(t, share.MaxTokens, shareGet.MaxTokens) 9101 assert.Equal(t, 0, shareGet.UsedTokens) 9102 assert.Equal(t, share.Paths, shareGet.Paths) 9103 assert.Equal(t, redactedSecret, shareGet.Password) 9104 9105 req, err = http.NewRequest(http.MethodGet, location, nil) 9106 assert.NoError(t, err) 9107 setBearerForReq(req, token1) 9108 rr = executeRequest(req) 9109 checkResponseCode(t, http.StatusNotFound, rr) 9110 9111 s, err := dataprovider.ShareExists(objectID, defaultUsername) 9112 assert.NoError(t, err) 9113 match, err := s.CheckPassword(defaultPassword) 9114 assert.True(t, match) 9115 assert.NoError(t, err) 9116 match, err = s.CheckPassword(defaultPassword + "mod") 9117 assert.False(t, match) 9118 assert.Error(t, err) 9119 9120 shareGet.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(3 * time.Hour)) 9121 asJSON, err = json.Marshal(shareGet) 9122 assert.NoError(t, err) 9123 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON)) 9124 assert.NoError(t, err) 9125 setBearerForReq(req, token) 9126 rr = executeRequest(req) 9127 checkResponseCode(t, http.StatusOK, rr) 9128 9129 s, err = dataprovider.ShareExists(objectID, defaultUsername) 9130 assert.NoError(t, err) 9131 match, err = s.CheckPassword(defaultPassword) 9132 assert.True(t, match) 9133 assert.NoError(t, err) 9134 match, err = s.CheckPassword(defaultPassword + "mod") 9135 assert.False(t, match) 9136 assert.Error(t, err) 9137 9138 req, err = http.NewRequest(http.MethodGet, location, nil) 9139 assert.NoError(t, err) 9140 setBearerForReq(req, token) 9141 rr = executeRequest(req) 9142 checkResponseCode(t, http.StatusOK, rr) 9143 var shareGetNew dataprovider.Share 9144 err = json.Unmarshal(rr.Body.Bytes(), &shareGetNew) 9145 assert.NoError(t, err) 9146 assert.NotEqual(t, shareGet.UpdatedAt, shareGetNew.UpdatedAt) 9147 shareGet.UpdatedAt = shareGetNew.UpdatedAt 9148 assert.Equal(t, shareGet, shareGetNew) 9149 9150 req, err = http.NewRequest(http.MethodGet, userSharesPath, nil) 9151 assert.NoError(t, err) 9152 setBearerForReq(req, token) 9153 rr = executeRequest(req) 9154 checkResponseCode(t, http.StatusOK, rr) 9155 var shares []dataprovider.Share 9156 err = json.Unmarshal(rr.Body.Bytes(), &shares) 9157 assert.NoError(t, err) 9158 if assert.Len(t, shares, 1) { 9159 assert.Equal(t, shareGetNew, shares[0]) 9160 } 9161 9162 err = dataprovider.UpdateShareLastUse(&shareGetNew, 2) 9163 assert.NoError(t, err) 9164 req, err = http.NewRequest(http.MethodGet, location, nil) 9165 assert.NoError(t, err) 9166 setBearerForReq(req, token) 9167 rr = executeRequest(req) 9168 checkResponseCode(t, http.StatusOK, rr) 9169 shareGetNew = dataprovider.Share{} 9170 err = json.Unmarshal(rr.Body.Bytes(), &shareGetNew) 9171 assert.NoError(t, err) 9172 assert.Equal(t, 2, shareGetNew.UsedTokens, "share: %v", shareGetNew) 9173 assert.Greater(t, shareGetNew.LastUseAt, int64(0), "share: %v", shareGetNew) 9174 9175 req, err = http.NewRequest(http.MethodGet, userSharesPath, nil) 9176 assert.NoError(t, err) 9177 setBearerForReq(req, token1) 9178 rr = executeRequest(req) 9179 checkResponseCode(t, http.StatusOK, rr) 9180 shares = nil 9181 err = json.Unmarshal(rr.Body.Bytes(), &shares) 9182 assert.NoError(t, err) 9183 assert.Len(t, shares, 0) 9184 9185 // set an empty password 9186 shareGet.Password = "" 9187 asJSON, err = json.Marshal(shareGet) 9188 assert.NoError(t, err) 9189 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON)) 9190 assert.NoError(t, err) 9191 setBearerForReq(req, token) 9192 rr = executeRequest(req) 9193 checkResponseCode(t, http.StatusOK, rr) 9194 9195 req, err = http.NewRequest(http.MethodGet, location, nil) 9196 assert.NoError(t, err) 9197 setBearerForReq(req, token) 9198 rr = executeRequest(req) 9199 checkResponseCode(t, http.StatusOK, rr) 9200 shareGetNew = dataprovider.Share{} 9201 err = json.Unmarshal(rr.Body.Bytes(), &shareGetNew) 9202 assert.NoError(t, err) 9203 assert.Empty(t, shareGetNew.Password) 9204 9205 req, err = http.NewRequest(http.MethodDelete, location, nil) 9206 assert.NoError(t, err) 9207 setBearerForReq(req, token) 9208 rr = executeRequest(req) 9209 checkResponseCode(t, http.StatusOK, rr) 9210 9211 share.Name = "" 9212 asJSON, err = json.Marshal(share) 9213 assert.NoError(t, err) 9214 9215 req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON)) 9216 assert.NoError(t, err) 9217 setBearerForReq(req, token) 9218 rr = executeRequest(req) 9219 checkResponseCode(t, http.StatusCreated, rr) 9220 location = rr.Header().Get("Location") 9221 9222 _, err = httpdtest.RemoveUser(user, http.StatusOK) 9223 assert.NoError(t, err) 9224 err = os.RemoveAll(user.GetHomeDir()) 9225 assert.NoError(t, err) 9226 // the share should be deleted with the associated user 9227 req, err = http.NewRequest(http.MethodGet, location, nil) 9228 assert.NoError(t, err) 9229 setBearerForReq(req, token) 9230 rr = executeRequest(req) 9231 checkResponseCode(t, http.StatusNotFound, rr) 9232 9233 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON)) 9234 assert.NoError(t, err) 9235 setBearerForReq(req, token) 9236 rr = executeRequest(req) 9237 checkResponseCode(t, http.StatusNotFound, rr) 9238 9239 req, err = http.NewRequest(http.MethodDelete, location, nil) 9240 assert.NoError(t, err) 9241 setBearerForReq(req, token) 9242 rr = executeRequest(req) 9243 checkResponseCode(t, http.StatusNotFound, rr) 9244 9245 _, err = httpdtest.RemoveUser(user1, http.StatusOK) 9246 assert.NoError(t, err) 9247 err = os.RemoveAll(user1.GetHomeDir()) 9248 assert.NoError(t, err) 9249} 9250 9251func TestUserAPIKey(t *testing.T) { 9252 u := getTestUser() 9253 u.Filters.AllowAPIKeyAuth = true 9254 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 9255 assert.NoError(t, err) 9256 apiKey := dataprovider.APIKey{ 9257 Name: "testkey", 9258 User: user.Username + "1", 9259 Scope: dataprovider.APIKeyScopeUser, 9260 } 9261 _, _, err = httpdtest.AddAPIKey(apiKey, http.StatusBadRequest) 9262 assert.NoError(t, err) 9263 apiKey.User = user.Username 9264 apiKey, _, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated) 9265 assert.NoError(t, err) 9266 9267 body := new(bytes.Buffer) 9268 writer := multipart.NewWriter(body) 9269 part, err := writer.CreateFormFile("filenames", "filenametest") 9270 assert.NoError(t, err) 9271 _, err = part.Write([]byte("test file content")) 9272 assert.NoError(t, err) 9273 err = writer.Close() 9274 assert.NoError(t, err) 9275 reader := bytes.NewReader(body.Bytes()) 9276 _, err = reader.Seek(0, io.SeekStart) 9277 assert.NoError(t, err) 9278 req, err := http.NewRequest(http.MethodPost, userFilesPath, reader) 9279 assert.NoError(t, err) 9280 req.Header.Add("Content-Type", writer.FormDataContentType()) 9281 setAPIKeyForReq(req, apiKey.Key, "") 9282 rr := executeRequest(req) 9283 checkResponseCode(t, http.StatusCreated, rr) 9284 9285 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9286 assert.NoError(t, err) 9287 setAPIKeyForReq(req, apiKey.Key, "") 9288 rr = executeRequest(req) 9289 checkResponseCode(t, http.StatusOK, rr) 9290 var dirEntries []map[string]interface{} 9291 err = json.Unmarshal(rr.Body.Bytes(), &dirEntries) 9292 assert.NoError(t, err) 9293 assert.Len(t, dirEntries, 1) 9294 9295 user.Status = 0 9296 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 9297 assert.NoError(t, err) 9298 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9299 assert.NoError(t, err) 9300 setAPIKeyForReq(req, apiKey.Key, "") 9301 rr = executeRequest(req) 9302 checkResponseCode(t, http.StatusUnauthorized, rr) 9303 9304 user.Status = 1 9305 user.Filters.DeniedProtocols = []string{common.ProtocolHTTP} 9306 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 9307 assert.NoError(t, err) 9308 9309 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9310 assert.NoError(t, err) 9311 setAPIKeyForReq(req, apiKey.Key, "") 9312 rr = executeRequest(req) 9313 checkResponseCode(t, http.StatusUnauthorized, rr) 9314 9315 user.Filters.DeniedProtocols = []string{common.ProtocolFTP} 9316 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 9317 assert.NoError(t, err) 9318 9319 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9320 assert.NoError(t, err) 9321 setAPIKeyForReq(req, apiKey.Key, "") 9322 rr = executeRequest(req) 9323 checkResponseCode(t, http.StatusOK, rr) 9324 apiKeyNew := dataprovider.APIKey{ 9325 Name: apiKey.Name, 9326 Scope: dataprovider.APIKeyScopeUser, 9327 } 9328 9329 apiKeyNew, _, err = httpdtest.AddAPIKey(apiKeyNew, http.StatusCreated) 9330 assert.NoError(t, err) 9331 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9332 assert.NoError(t, err) 9333 setAPIKeyForReq(req, apiKeyNew.Key, "") 9334 rr = executeRequest(req) 9335 checkResponseCode(t, http.StatusUnauthorized, rr) 9336 // now associate a user 9337 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9338 assert.NoError(t, err) 9339 setAPIKeyForReq(req, apiKeyNew.Key, user.Username) 9340 rr = executeRequest(req) 9341 checkResponseCode(t, http.StatusOK, rr) 9342 // now with a missing user 9343 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9344 assert.NoError(t, err) 9345 setAPIKeyForReq(req, apiKeyNew.Key, user.Username+"1") 9346 rr = executeRequest(req) 9347 checkResponseCode(t, http.StatusUnauthorized, rr) 9348 // empty user and key not associated to any user 9349 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9350 assert.NoError(t, err) 9351 setAPIKeyForReq(req, apiKeyNew.Key, "") 9352 rr = executeRequest(req) 9353 checkResponseCode(t, http.StatusUnauthorized, rr) 9354 apiKeyNew.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-24 * time.Hour)) 9355 _, _, err = httpdtest.UpdateAPIKey(apiKeyNew, http.StatusOK) 9356 assert.NoError(t, err) 9357 // expired API key 9358 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9359 assert.NoError(t, err) 9360 setAPIKeyForReq(req, apiKeyNew.Key, user.Username) 9361 rr = executeRequest(req) 9362 checkResponseCode(t, http.StatusUnauthorized, rr) 9363 9364 _, err = httpdtest.RemoveUser(user, http.StatusOK) 9365 assert.NoError(t, err) 9366 err = os.RemoveAll(user.GetHomeDir()) 9367 assert.NoError(t, err) 9368 9369 _, err = httpdtest.RemoveAPIKey(apiKeyNew, http.StatusOK) 9370 assert.NoError(t, err) 9371} 9372 9373func TestWebClientViewPDF(t *testing.T) { 9374 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 9375 assert.NoError(t, err) 9376 9377 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 9378 assert.NoError(t, err) 9379 9380 req, err := http.NewRequest(http.MethodGet, webClientViewPDFPath, nil) 9381 assert.NoError(t, err) 9382 setJWTCookieForReq(req, webToken) 9383 rr := executeRequest(req) 9384 checkResponseCode(t, http.StatusBadRequest, rr) 9385 9386 req, err = http.NewRequest(http.MethodGet, webClientViewPDFPath+"?path=test.pdf", nil) 9387 assert.NoError(t, err) 9388 setJWTCookieForReq(req, webToken) 9389 rr = executeRequest(req) 9390 checkResponseCode(t, http.StatusOK, rr) 9391 9392 _, err = httpdtest.RemoveUser(user, http.StatusOK) 9393 assert.NoError(t, err) 9394 err = os.RemoveAll(user.GetHomeDir()) 9395 assert.NoError(t, err) 9396} 9397 9398func TestWebEditFile(t *testing.T) { 9399 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 9400 assert.NoError(t, err) 9401 testFile1 := "testfile1.txt" 9402 testFile2 := "testfile2" 9403 file1Size := int64(65536) 9404 file2Size := int64(1048576 * 2) 9405 err = createTestFile(filepath.Join(user.GetHomeDir(), testFile1), file1Size) 9406 assert.NoError(t, err) 9407 err = createTestFile(filepath.Join(user.GetHomeDir(), testFile2), file2Size) 9408 assert.NoError(t, err) 9409 9410 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 9411 assert.NoError(t, err) 9412 9413 req, err := http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile1, nil) 9414 assert.NoError(t, err) 9415 setJWTCookieForReq(req, webToken) 9416 rr := executeRequest(req) 9417 checkResponseCode(t, http.StatusOK, rr) 9418 9419 req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile2, nil) 9420 assert.NoError(t, err) 9421 setJWTCookieForReq(req, webToken) 9422 rr = executeRequest(req) 9423 checkResponseCode(t, http.StatusBadRequest, rr) 9424 assert.Contains(t, rr.Body.String(), "exceeds the maximum allowed size") 9425 9426 req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path=missing", nil) 9427 assert.NoError(t, err) 9428 setJWTCookieForReq(req, webToken) 9429 rr = executeRequest(req) 9430 checkResponseCode(t, http.StatusBadRequest, rr) 9431 assert.Contains(t, rr.Body.String(), "Unable to stat file") 9432 9433 req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path=%2F", nil) 9434 assert.NoError(t, err) 9435 setJWTCookieForReq(req, webToken) 9436 rr = executeRequest(req) 9437 checkResponseCode(t, http.StatusBadRequest, rr) 9438 assert.Contains(t, rr.Body.String(), "does not point to a file") 9439 9440 user.Filters.DeniedProtocols = []string{common.ProtocolHTTP} 9441 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 9442 assert.NoError(t, err) 9443 9444 req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile1, nil) 9445 assert.NoError(t, err) 9446 setJWTCookieForReq(req, webToken) 9447 rr = executeRequest(req) 9448 checkResponseCode(t, http.StatusForbidden, rr) 9449 9450 user.Filters.DeniedProtocols = []string{common.ProtocolFTP} 9451 user.Filters.FilePatterns = []sdk.PatternsFilter{ 9452 { 9453 Path: "/", 9454 DeniedPatterns: []string{"*.txt"}, 9455 }, 9456 } 9457 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 9458 assert.NoError(t, err) 9459 9460 req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile1, nil) 9461 assert.NoError(t, err) 9462 setJWTCookieForReq(req, webToken) 9463 rr = executeRequest(req) 9464 checkResponseCode(t, http.StatusForbidden, rr) 9465 assert.Contains(t, rr.Body.String(), "Unable to get a reader") 9466 9467 _, err = httpdtest.RemoveUser(user, http.StatusOK) 9468 assert.NoError(t, err) 9469 err = os.RemoveAll(user.GetHomeDir()) 9470 assert.NoError(t, err) 9471 9472 req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile1, nil) 9473 assert.NoError(t, err) 9474 setJWTCookieForReq(req, webToken) 9475 rr = executeRequest(req) 9476 checkResponseCode(t, http.StatusNotFound, rr) 9477} 9478 9479func TestWebGetFiles(t *testing.T) { 9480 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 9481 assert.NoError(t, err) 9482 testFileName := "testfile" 9483 testDir := "testdir" 9484 testFileContents := []byte("file contents") 9485 err = os.MkdirAll(filepath.Join(user.GetHomeDir(), testDir), os.ModePerm) 9486 assert.NoError(t, err) 9487 extensions := []string{"", ".doc", ".ppt", ".xls", ".pdf", ".mkv", ".png", ".go", ".zip", ".txt"} 9488 for _, ext := range extensions { 9489 err = os.WriteFile(filepath.Join(user.GetHomeDir(), testFileName+ext), testFileContents, os.ModePerm) 9490 assert.NoError(t, err) 9491 } 9492 err = os.Symlink(filepath.Join(user.GetHomeDir(), testFileName+".doc"), filepath.Join(user.GetHomeDir(), testDir, testFileName+".link")) 9493 assert.NoError(t, err) 9494 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 9495 assert.NoError(t, err) 9496 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 9497 assert.NoError(t, err) 9498 req, _ := http.NewRequest(http.MethodGet, webClientFilesPath, nil) 9499 setJWTCookieForReq(req, webToken) 9500 rr := executeRequest(req) 9501 checkResponseCode(t, http.StatusOK, rr) 9502 9503 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testDir, nil) 9504 setJWTCookieForReq(req, webToken) 9505 rr = executeRequest(req) 9506 checkResponseCode(t, http.StatusOK, rr) 9507 9508 req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path="+testDir, nil) 9509 setJWTCookieForReq(req, webToken) 9510 rr = executeRequest(req) 9511 checkResponseCode(t, http.StatusOK, rr) 9512 var dirContents []map[string]string 9513 err = json.Unmarshal(rr.Body.Bytes(), &dirContents) 9514 assert.NoError(t, err) 9515 assert.Len(t, dirContents, 1) 9516 9517 req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil) 9518 setBearerForReq(req, webAPIToken) 9519 rr = executeRequest(req) 9520 checkResponseCode(t, http.StatusOK, rr) 9521 var dirEntries []map[string]interface{} 9522 err = json.Unmarshal(rr.Body.Bytes(), &dirEntries) 9523 assert.NoError(t, err) 9524 assert.Len(t, dirEntries, 1) 9525 9526 req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath+"?path="+url.QueryEscape("/")+"&files="+ 9527 url.QueryEscape(fmt.Sprintf(`["%v","%v","%v"]`, testFileName, testDir, testFileName+extensions[2])), nil) 9528 setJWTCookieForReq(req, webToken) 9529 rr = executeRequest(req) 9530 checkResponseCode(t, http.StatusOK, rr) 9531 9532 filesList := []string{testFileName, testDir, testFileName + extensions[2]} 9533 asJSON, err := json.Marshal(filesList) 9534 assert.NoError(t, err) 9535 req, _ = http.NewRequest(http.MethodPost, userStreamZipPath, bytes.NewBuffer(asJSON)) 9536 setBearerForReq(req, webAPIToken) 9537 rr = executeRequest(req) 9538 checkResponseCode(t, http.StatusOK, rr) 9539 9540 assert.NoError(t, err) 9541 req, _ = http.NewRequest(http.MethodPost, userStreamZipPath, bytes.NewBuffer([]byte(`file`))) 9542 setBearerForReq(req, webAPIToken) 9543 rr = executeRequest(req) 9544 checkResponseCode(t, http.StatusBadRequest, rr) 9545 9546 req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath+"?path="+url.QueryEscape("/")+"&files="+ 9547 url.QueryEscape(fmt.Sprintf(`["%v"]`, testDir)), nil) 9548 setJWTCookieForReq(req, webToken) 9549 rr = executeRequest(req) 9550 checkResponseCode(t, http.StatusOK, rr) 9551 9552 req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath+"?path="+url.QueryEscape("/")+"&files=notalist", nil) 9553 setJWTCookieForReq(req, webToken) 9554 rr = executeRequest(req) 9555 checkResponseCode(t, http.StatusInternalServerError, rr) 9556 assert.Contains(t, rr.Body.String(), "Unable to get files list") 9557 9558 req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path=/", nil) 9559 setJWTCookieForReq(req, webToken) 9560 rr = executeRequest(req) 9561 checkResponseCode(t, http.StatusOK, rr) 9562 dirContents = nil 9563 err = json.Unmarshal(rr.Body.Bytes(), &dirContents) 9564 assert.NoError(t, err) 9565 assert.Len(t, dirContents, len(extensions)+1) 9566 9567 req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path=/", nil) 9568 setBearerForReq(req, webAPIToken) 9569 rr = executeRequest(req) 9570 checkResponseCode(t, http.StatusOK, rr) 9571 dirEntries = nil 9572 err = json.Unmarshal(rr.Body.Bytes(), &dirEntries) 9573 assert.NoError(t, err) 9574 assert.Len(t, dirEntries, len(extensions)+1) 9575 9576 req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path=/missing", nil) 9577 setJWTCookieForReq(req, webToken) 9578 rr = executeRequest(req) 9579 checkResponseCode(t, http.StatusNotFound, rr) 9580 assert.Contains(t, rr.Body.String(), "Unable to get directory contents") 9581 9582 req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path=missing", nil) 9583 setBearerForReq(req, webAPIToken) 9584 rr = executeRequest(req) 9585 checkResponseCode(t, http.StatusNotFound, rr) 9586 assert.Contains(t, rr.Body.String(), "Unable to get directory contents") 9587 9588 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 9589 setJWTCookieForReq(req, webToken) 9590 rr = executeRequest(req) 9591 checkResponseCode(t, http.StatusOK, rr) 9592 assert.Equal(t, testFileContents, rr.Body.Bytes()) 9593 9594 req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil) 9595 setBearerForReq(req, webAPIToken) 9596 rr = executeRequest(req) 9597 checkResponseCode(t, http.StatusOK, rr) 9598 assert.Equal(t, testFileContents, rr.Body.Bytes()) 9599 9600 req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path=", nil) 9601 setBearerForReq(req, webAPIToken) 9602 rr = executeRequest(req) 9603 checkResponseCode(t, http.StatusBadRequest, rr) 9604 assert.Contains(t, rr.Body.String(), "Please set the path to a valid file") 9605 9606 req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testDir, nil) 9607 setBearerForReq(req, webAPIToken) 9608 rr = executeRequest(req) 9609 checkResponseCode(t, http.StatusBadRequest, rr) 9610 assert.Contains(t, rr.Body.String(), "is a directory") 9611 9612 req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path=notafile", nil) 9613 setBearerForReq(req, webAPIToken) 9614 rr = executeRequest(req) 9615 checkResponseCode(t, http.StatusNotFound, rr) 9616 assert.Contains(t, rr.Body.String(), "Unable to stat the requested file") 9617 9618 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 9619 req.Header.Set("Range", "bytes=2-") 9620 setJWTCookieForReq(req, webToken) 9621 rr = executeRequest(req) 9622 checkResponseCode(t, http.StatusPartialContent, rr) 9623 assert.Equal(t, testFileContents[2:], rr.Body.Bytes()) 9624 9625 req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil) 9626 req.Header.Set("Range", "bytes=2-") 9627 setBearerForReq(req, webAPIToken) 9628 rr = executeRequest(req) 9629 checkResponseCode(t, http.StatusPartialContent, rr) 9630 assert.Equal(t, testFileContents[2:], rr.Body.Bytes()) 9631 9632 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 9633 req.Header.Set("Range", "bytes=-2") 9634 setJWTCookieForReq(req, webToken) 9635 rr = executeRequest(req) 9636 checkResponseCode(t, http.StatusPartialContent, rr) 9637 assert.Equal(t, testFileContents[11:], rr.Body.Bytes()) 9638 9639 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 9640 req.Header.Set("Range", "bytes=-2,") 9641 setJWTCookieForReq(req, webToken) 9642 rr = executeRequest(req) 9643 checkResponseCode(t, http.StatusRequestedRangeNotSatisfiable, rr) 9644 9645 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 9646 req.Header.Set("Range", "bytes=1a-") 9647 setJWTCookieForReq(req, webToken) 9648 rr = executeRequest(req) 9649 checkResponseCode(t, http.StatusRequestedRangeNotSatisfiable, rr) 9650 9651 req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil) 9652 req.Header.Set("Range", "bytes=2b-") 9653 setBearerForReq(req, webAPIToken) 9654 rr = executeRequest(req) 9655 checkResponseCode(t, http.StatusRequestedRangeNotSatisfiable, rr) 9656 9657 req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil) 9658 req.Header.Set("Range", "bytes=2-") 9659 req.Header.Set("If-Range", time.Now().UTC().Add(120*time.Second).Format(http.TimeFormat)) 9660 setJWTCookieForReq(req, webToken) 9661 rr = executeRequest(req) 9662 checkResponseCode(t, http.StatusPartialContent, rr) 9663 9664 req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil) 9665 req.Header.Set("Range", "bytes=2-") 9666 req.Header.Set("If-Range", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat)) 9667 setJWTCookieForReq(req, webToken) 9668 rr = executeRequest(req) 9669 checkResponseCode(t, http.StatusOK, rr) 9670 9671 req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil) 9672 req.Header.Set("If-Modified-Since", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat)) 9673 setJWTCookieForReq(req, webToken) 9674 rr = executeRequest(req) 9675 checkResponseCode(t, http.StatusOK, rr) 9676 9677 req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil) 9678 req.Header.Set("If-Modified-Since", time.Now().UTC().Add(120*time.Second).Format(http.TimeFormat)) 9679 setJWTCookieForReq(req, webToken) 9680 rr = executeRequest(req) 9681 checkResponseCode(t, http.StatusNotModified, rr) 9682 9683 req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil) 9684 req.Header.Set("If-Unmodified-Since", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat)) 9685 setJWTCookieForReq(req, webToken) 9686 rr = executeRequest(req) 9687 checkResponseCode(t, http.StatusPreconditionFailed, rr) 9688 9689 req, _ = http.NewRequest(http.MethodHead, userFilesPath+"?path="+testFileName, nil) 9690 req.Header.Set("If-Unmodified-Since", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat)) 9691 setBearerForReq(req, webAPIToken) 9692 rr = executeRequest(req) 9693 checkResponseCode(t, http.StatusPreconditionFailed, rr) 9694 9695 req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil) 9696 req.Header.Set("If-Unmodified-Since", time.Now().UTC().Add(120*time.Second).Format(http.TimeFormat)) 9697 setJWTCookieForReq(req, webToken) 9698 rr = executeRequest(req) 9699 checkResponseCode(t, http.StatusOK, rr) 9700 9701 user.Filters.DeniedProtocols = []string{common.ProtocolHTTP} 9702 _, resp, err := httpdtest.UpdateUser(user, http.StatusOK, "") 9703 assert.NoError(t, err, string(resp)) 9704 9705 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil) 9706 setJWTCookieForReq(req, webToken) 9707 rr = executeRequest(req) 9708 checkResponseCode(t, http.StatusForbidden, rr) 9709 9710 req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path=/", nil) 9711 setJWTCookieForReq(req, webToken) 9712 rr = executeRequest(req) 9713 checkResponseCode(t, http.StatusForbidden, rr) 9714 9715 req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil) 9716 setBearerForReq(req, webAPIToken) 9717 rr = executeRequest(req) 9718 checkResponseCode(t, http.StatusForbidden, rr) 9719 9720 req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil) 9721 setBearerForReq(req, webAPIToken) 9722 rr = executeRequest(req) 9723 checkResponseCode(t, http.StatusForbidden, rr) 9724 9725 filesList = []string{testDir} 9726 asJSON, err = json.Marshal(filesList) 9727 assert.NoError(t, err) 9728 req, _ = http.NewRequest(http.MethodPost, userStreamZipPath, bytes.NewBuffer(asJSON)) 9729 setBearerForReq(req, webAPIToken) 9730 rr = executeRequest(req) 9731 checkResponseCode(t, http.StatusForbidden, rr) 9732 9733 user.Filters.DeniedProtocols = []string{common.ProtocolFTP} 9734 user.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword} 9735 _, resp, err = httpdtest.UpdateUser(user, http.StatusOK, "") 9736 assert.NoError(t, err, string(resp)) 9737 9738 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil) 9739 setJWTCookieForReq(req, webToken) 9740 rr = executeRequest(req) 9741 checkResponseCode(t, http.StatusForbidden, rr) 9742 9743 req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath, nil) 9744 setJWTCookieForReq(req, webToken) 9745 rr = executeRequest(req) 9746 checkResponseCode(t, http.StatusForbidden, rr) 9747 9748 req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil) 9749 setBearerForReq(req, webAPIToken) 9750 rr = executeRequest(req) 9751 checkResponseCode(t, http.StatusForbidden, rr) 9752 9753 _, err = httpdtest.RemoveUser(user, http.StatusOK) 9754 assert.NoError(t, err) 9755 err = os.RemoveAll(user.GetHomeDir()) 9756 assert.NoError(t, err) 9757} 9758 9759func TestWebDirsAPI(t *testing.T) { 9760 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 9761 assert.NoError(t, err) 9762 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 9763 assert.NoError(t, err) 9764 testDir := "testdir" 9765 9766 req, err := http.NewRequest(http.MethodGet, userDirsPath, nil) 9767 assert.NoError(t, err) 9768 setBearerForReq(req, webAPIToken) 9769 rr := executeRequest(req) 9770 checkResponseCode(t, http.StatusOK, rr) 9771 var contents []map[string]interface{} 9772 err = json.NewDecoder(rr.Body).Decode(&contents) 9773 assert.NoError(t, err) 9774 assert.Len(t, contents, 0) 9775 9776 // rename a missing folder 9777 req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir+"new", nil) 9778 assert.NoError(t, err) 9779 setBearerForReq(req, webAPIToken) 9780 rr = executeRequest(req) 9781 checkResponseCode(t, http.StatusNotFound, rr) 9782 // delete a missing folder 9783 req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path="+testDir, nil) 9784 assert.NoError(t, err) 9785 setBearerForReq(req, webAPIToken) 9786 rr = executeRequest(req) 9787 checkResponseCode(t, http.StatusNotFound, rr) 9788 // create a dir 9789 req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil) 9790 assert.NoError(t, err) 9791 setBearerForReq(req, webAPIToken) 9792 rr = executeRequest(req) 9793 checkResponseCode(t, http.StatusCreated, rr) 9794 // check the dir was created 9795 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9796 assert.NoError(t, err) 9797 setBearerForReq(req, webAPIToken) 9798 rr = executeRequest(req) 9799 checkResponseCode(t, http.StatusOK, rr) 9800 contents = nil 9801 err = json.NewDecoder(rr.Body).Decode(&contents) 9802 assert.NoError(t, err) 9803 if assert.Len(t, contents, 1) { 9804 assert.Equal(t, testDir, contents[0]["name"]) 9805 } 9806 // rename the dir 9807 req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir+"new", nil) 9808 assert.NoError(t, err) 9809 setBearerForReq(req, webAPIToken) 9810 rr = executeRequest(req) 9811 checkResponseCode(t, http.StatusOK, rr) 9812 // delete the dir 9813 req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path="+testDir+"new", nil) 9814 assert.NoError(t, err) 9815 setBearerForReq(req, webAPIToken) 9816 rr = executeRequest(req) 9817 checkResponseCode(t, http.StatusOK, rr) 9818 // the root dir cannot be created 9819 req, err = http.NewRequest(http.MethodPost, userDirsPath, nil) 9820 assert.NoError(t, err) 9821 setBearerForReq(req, webAPIToken) 9822 rr = executeRequest(req) 9823 checkResponseCode(t, http.StatusInternalServerError, rr) 9824 9825 user.Permissions["/"] = []string{dataprovider.PermListItems} 9826 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 9827 assert.NoError(t, err) 9828 // the user has no more the permission to create the directory 9829 req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil) 9830 assert.NoError(t, err) 9831 setBearerForReq(req, webAPIToken) 9832 rr = executeRequest(req) 9833 checkResponseCode(t, http.StatusForbidden, rr) 9834 9835 _, err = httpdtest.RemoveUser(user, http.StatusOK) 9836 assert.NoError(t, err) 9837 err = os.RemoveAll(user.GetHomeDir()) 9838 assert.NoError(t, err) 9839 9840 // the user is deleted, any API call should fail 9841 req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil) 9842 assert.NoError(t, err) 9843 setBearerForReq(req, webAPIToken) 9844 rr = executeRequest(req) 9845 checkResponseCode(t, http.StatusNotFound, rr) 9846 9847 req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir+"new", nil) 9848 assert.NoError(t, err) 9849 setBearerForReq(req, webAPIToken) 9850 rr = executeRequest(req) 9851 checkResponseCode(t, http.StatusNotFound, rr) 9852 9853 req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path="+testDir+"new", nil) 9854 assert.NoError(t, err) 9855 setBearerForReq(req, webAPIToken) 9856 rr = executeRequest(req) 9857 checkResponseCode(t, http.StatusNotFound, rr) 9858} 9859 9860func TestWebFilesAPI(t *testing.T) { 9861 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 9862 assert.NoError(t, err) 9863 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 9864 assert.NoError(t, err) 9865 9866 body := new(bytes.Buffer) 9867 writer := multipart.NewWriter(body) 9868 part1, err := writer.CreateFormFile("filenames", "file1.txt") 9869 assert.NoError(t, err) 9870 _, err = part1.Write([]byte("file1 content")) 9871 assert.NoError(t, err) 9872 part2, err := writer.CreateFormFile("filenames", "file2.txt") 9873 assert.NoError(t, err) 9874 _, err = part2.Write([]byte("file2 content")) 9875 assert.NoError(t, err) 9876 err = writer.Close() 9877 assert.NoError(t, err) 9878 reader := bytes.NewReader(body.Bytes()) 9879 9880 req, err := http.NewRequest(http.MethodPost, userFilesPath, reader) 9881 assert.NoError(t, err) 9882 setBearerForReq(req, webAPIToken) 9883 rr := executeRequest(req) 9884 checkResponseCode(t, http.StatusBadRequest, rr) 9885 assert.Contains(t, rr.Body.String(), "Unable to parse multipart form") 9886 _, err = reader.Seek(0, io.SeekStart) 9887 assert.NoError(t, err) 9888 // set the proper content type 9889 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 9890 assert.NoError(t, err) 9891 req.Header.Add("Content-Type", writer.FormDataContentType()) 9892 setBearerForReq(req, webAPIToken) 9893 rr = executeRequest(req) 9894 checkResponseCode(t, http.StatusCreated, rr) 9895 // check we have 2 files 9896 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9897 assert.NoError(t, err) 9898 setBearerForReq(req, webAPIToken) 9899 rr = executeRequest(req) 9900 checkResponseCode(t, http.StatusOK, rr) 9901 var contents []map[string]interface{} 9902 err = json.NewDecoder(rr.Body).Decode(&contents) 9903 assert.NoError(t, err) 9904 assert.Len(t, contents, 2) 9905 // overwrite the existing files 9906 _, err = reader.Seek(0, io.SeekStart) 9907 assert.NoError(t, err) 9908 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 9909 assert.NoError(t, err) 9910 req.Header.Add("Content-Type", writer.FormDataContentType()) 9911 setBearerForReq(req, webAPIToken) 9912 rr = executeRequest(req) 9913 checkResponseCode(t, http.StatusCreated, rr) 9914 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9915 assert.NoError(t, err) 9916 setBearerForReq(req, webAPIToken) 9917 rr = executeRequest(req) 9918 checkResponseCode(t, http.StatusOK, rr) 9919 contents = nil 9920 err = json.NewDecoder(rr.Body).Decode(&contents) 9921 assert.NoError(t, err) 9922 assert.Len(t, contents, 2) 9923 // now create a dir and upload to that dir 9924 testDir := "tdir" 9925 req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil) 9926 assert.NoError(t, err) 9927 setBearerForReq(req, webAPIToken) 9928 rr = executeRequest(req) 9929 checkResponseCode(t, http.StatusCreated, rr) 9930 _, err = reader.Seek(0, io.SeekStart) 9931 assert.NoError(t, err) 9932 req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path="+testDir, reader) 9933 assert.NoError(t, err) 9934 req.Header.Add("Content-Type", writer.FormDataContentType()) 9935 setBearerForReq(req, webAPIToken) 9936 rr = executeRequest(req) 9937 checkResponseCode(t, http.StatusCreated, rr) 9938 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 9939 assert.NoError(t, err) 9940 setBearerForReq(req, webAPIToken) 9941 rr = executeRequest(req) 9942 checkResponseCode(t, http.StatusOK, rr) 9943 contents = nil 9944 err = json.NewDecoder(rr.Body).Decode(&contents) 9945 assert.NoError(t, err) 9946 assert.Len(t, contents, 3) 9947 req, err = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil) 9948 assert.NoError(t, err) 9949 setBearerForReq(req, webAPIToken) 9950 rr = executeRequest(req) 9951 checkResponseCode(t, http.StatusOK, rr) 9952 contents = nil 9953 err = json.NewDecoder(rr.Body).Decode(&contents) 9954 assert.NoError(t, err) 9955 assert.Len(t, contents, 2) 9956 // rename a file 9957 req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil) 9958 assert.NoError(t, err) 9959 setBearerForReq(req, webAPIToken) 9960 rr = executeRequest(req) 9961 checkResponseCode(t, http.StatusOK, rr) 9962 // rename a missing file 9963 req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil) 9964 assert.NoError(t, err) 9965 setBearerForReq(req, webAPIToken) 9966 rr = executeRequest(req) 9967 checkResponseCode(t, http.StatusNotFound, rr) 9968 // delete a file 9969 req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil) 9970 assert.NoError(t, err) 9971 setBearerForReq(req, webAPIToken) 9972 rr = executeRequest(req) 9973 checkResponseCode(t, http.StatusOK, rr) 9974 // delete a missing file 9975 req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil) 9976 assert.NoError(t, err) 9977 setBearerForReq(req, webAPIToken) 9978 rr = executeRequest(req) 9979 checkResponseCode(t, http.StatusNotFound, rr) 9980 // delete a directory 9981 req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=tdir", nil) 9982 assert.NoError(t, err) 9983 setBearerForReq(req, webAPIToken) 9984 rr = executeRequest(req) 9985 checkResponseCode(t, http.StatusBadRequest, rr) 9986 // make a symlink outside the home dir and then try to delete it 9987 extPath := filepath.Join(os.TempDir(), "file") 9988 err = os.WriteFile(extPath, []byte("contents"), os.ModePerm) 9989 assert.NoError(t, err) 9990 err = os.Symlink(extPath, filepath.Join(user.GetHomeDir(), "file")) 9991 assert.NoError(t, err) 9992 req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file", nil) 9993 assert.NoError(t, err) 9994 setBearerForReq(req, webAPIToken) 9995 rr = executeRequest(req) 9996 checkResponseCode(t, http.StatusForbidden, rr) 9997 err = os.Remove(extPath) 9998 assert.NoError(t, err) 9999 // remove delete and overwrite permissions 10000 user.Permissions["/"] = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload} 10001 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 10002 assert.NoError(t, err) 10003 _, err = reader.Seek(0, io.SeekStart) 10004 assert.NoError(t, err) 10005 req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=tdir", reader) 10006 assert.NoError(t, err) 10007 req.Header.Add("Content-Type", writer.FormDataContentType()) 10008 setBearerForReq(req, webAPIToken) 10009 rr = executeRequest(req) 10010 checkResponseCode(t, http.StatusForbidden, rr) 10011 10012 req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=%2Ftdir%2Ffile1.txt", nil) 10013 assert.NoError(t, err) 10014 setBearerForReq(req, webAPIToken) 10015 rr = executeRequest(req) 10016 checkResponseCode(t, http.StatusForbidden, rr) 10017 10018 _, err = httpdtest.RemoveUser(user, http.StatusOK) 10019 assert.NoError(t, err) 10020 err = os.RemoveAll(user.GetHomeDir()) 10021 assert.NoError(t, err) 10022 // the user is deleted, any API call should fail 10023 _, err = reader.Seek(0, io.SeekStart) 10024 assert.NoError(t, err) 10025 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 10026 assert.NoError(t, err) 10027 req.Header.Add("Content-Type", writer.FormDataContentType()) 10028 setBearerForReq(req, webAPIToken) 10029 rr = executeRequest(req) 10030 checkResponseCode(t, http.StatusNotFound, rr) 10031 10032 req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil) 10033 assert.NoError(t, err) 10034 setBearerForReq(req, webAPIToken) 10035 rr = executeRequest(req) 10036 checkResponseCode(t, http.StatusNotFound, rr) 10037 10038 req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil) 10039 assert.NoError(t, err) 10040 setBearerForReq(req, webAPIToken) 10041 rr = executeRequest(req) 10042 checkResponseCode(t, http.StatusNotFound, rr) 10043} 10044 10045func TestWebUploadErrors(t *testing.T) { 10046 u := getTestUser() 10047 u.QuotaSize = 65535 10048 subDir1 := "sub1" 10049 subDir2 := "sub2" 10050 u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems} 10051 u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload, 10052 dataprovider.PermDelete} 10053 u.Filters.FilePatterns = []sdk.PatternsFilter{ 10054 { 10055 Path: "/sub2", 10056 AllowedPatterns: []string{}, 10057 DeniedPatterns: []string{"*.zip"}, 10058 }, 10059 } 10060 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 10061 assert.NoError(t, err) 10062 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 10063 assert.NoError(t, err) 10064 10065 body := new(bytes.Buffer) 10066 writer := multipart.NewWriter(body) 10067 part, err := writer.CreateFormFile("filenames", "file.zip") 10068 assert.NoError(t, err) 10069 _, err = part.Write([]byte("file content")) 10070 assert.NoError(t, err) 10071 err = writer.Close() 10072 assert.NoError(t, err) 10073 reader := bytes.NewReader(body.Bytes()) 10074 _, err = reader.Seek(0, io.SeekStart) 10075 assert.NoError(t, err) 10076 // zip file are not allowed within sub2 10077 req, err := http.NewRequest(http.MethodPost, userFilesPath+"?path=sub2", reader) 10078 assert.NoError(t, err) 10079 req.Header.Add("Content-Type", writer.FormDataContentType()) 10080 setBearerForReq(req, webAPIToken) 10081 rr := executeRequest(req) 10082 checkResponseCode(t, http.StatusForbidden, rr) 10083 10084 _, err = reader.Seek(0, io.SeekStart) 10085 assert.NoError(t, err) 10086 // we have no upload permissions within sub1 10087 req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=sub1", reader) 10088 assert.NoError(t, err) 10089 req.Header.Add("Content-Type", writer.FormDataContentType()) 10090 setBearerForReq(req, webAPIToken) 10091 rr = executeRequest(req) 10092 checkResponseCode(t, http.StatusForbidden, rr) 10093 10094 // create a dir and try to overwrite it with a file 10095 req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path=file.zip", nil) 10096 assert.NoError(t, err) 10097 setBearerForReq(req, webAPIToken) 10098 rr = executeRequest(req) 10099 checkResponseCode(t, http.StatusCreated, rr) 10100 10101 _, err = reader.Seek(0, io.SeekStart) 10102 assert.NoError(t, err) 10103 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 10104 assert.NoError(t, err) 10105 req.Header.Add("Content-Type", writer.FormDataContentType()) 10106 setBearerForReq(req, webAPIToken) 10107 rr = executeRequest(req) 10108 checkResponseCode(t, http.StatusInternalServerError, rr) 10109 assert.Contains(t, rr.Body.String(), "operation unsupported") 10110 // try to upload to a missing parent directory 10111 _, err = reader.Seek(0, io.SeekStart) 10112 assert.NoError(t, err) 10113 req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=missingdir", reader) 10114 assert.NoError(t, err) 10115 req.Header.Add("Content-Type", writer.FormDataContentType()) 10116 setBearerForReq(req, webAPIToken) 10117 rr = executeRequest(req) 10118 checkResponseCode(t, http.StatusNotFound, rr) 10119 10120 req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path=file.zip", nil) 10121 assert.NoError(t, err) 10122 setBearerForReq(req, webAPIToken) 10123 rr = executeRequest(req) 10124 checkResponseCode(t, http.StatusOK, rr) 10125 // upload will work now 10126 _, err = reader.Seek(0, io.SeekStart) 10127 assert.NoError(t, err) 10128 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 10129 assert.NoError(t, err) 10130 req.Header.Add("Content-Type", writer.FormDataContentType()) 10131 setBearerForReq(req, webAPIToken) 10132 rr = executeRequest(req) 10133 checkResponseCode(t, http.StatusCreated, rr) 10134 // overwrite the file 10135 _, err = reader.Seek(0, io.SeekStart) 10136 assert.NoError(t, err) 10137 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 10138 assert.NoError(t, err) 10139 req.Header.Add("Content-Type", writer.FormDataContentType()) 10140 setBearerForReq(req, webAPIToken) 10141 rr = executeRequest(req) 10142 checkResponseCode(t, http.StatusCreated, rr) 10143 10144 vfs.SetTempPath(filepath.Join(os.TempDir(), "missingpath")) 10145 10146 _, err = reader.Seek(0, io.SeekStart) 10147 assert.NoError(t, err) 10148 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 10149 assert.NoError(t, err) 10150 req.Header.Add("Content-Type", writer.FormDataContentType()) 10151 setBearerForReq(req, webAPIToken) 10152 rr = executeRequest(req) 10153 checkResponseCode(t, http.StatusNotFound, rr) 10154 10155 if runtime.GOOS != osWindows { 10156 req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file.zip", reader) 10157 assert.NoError(t, err) 10158 setBearerForReq(req, webAPIToken) 10159 rr = executeRequest(req) 10160 checkResponseCode(t, http.StatusOK, rr) 10161 10162 vfs.SetTempPath(filepath.Clean(os.TempDir())) 10163 err = os.Chmod(user.GetHomeDir(), 0555) 10164 assert.NoError(t, err) 10165 10166 _, err = reader.Seek(0, io.SeekStart) 10167 assert.NoError(t, err) 10168 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 10169 assert.NoError(t, err) 10170 req.Header.Add("Content-Type", writer.FormDataContentType()) 10171 setBearerForReq(req, webAPIToken) 10172 rr = executeRequest(req) 10173 checkResponseCode(t, http.StatusForbidden, rr) 10174 assert.Contains(t, rr.Body.String(), "Error closing file") 10175 10176 err = os.Chmod(user.GetHomeDir(), os.ModePerm) 10177 assert.NoError(t, err) 10178 } 10179 10180 vfs.SetTempPath("") 10181 10182 // upload a multipart form with no files 10183 body = new(bytes.Buffer) 10184 writer = multipart.NewWriter(body) 10185 err = writer.Close() 10186 assert.NoError(t, err) 10187 reader = bytes.NewReader(body.Bytes()) 10188 _, err = reader.Seek(0, io.SeekStart) 10189 assert.NoError(t, err) 10190 req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=sub2", reader) 10191 assert.NoError(t, err) 10192 req.Header.Add("Content-Type", writer.FormDataContentType()) 10193 setBearerForReq(req, webAPIToken) 10194 rr = executeRequest(req) 10195 checkResponseCode(t, http.StatusBadRequest, rr) 10196 assert.Contains(t, rr.Body.String(), "No files uploaded!") 10197 10198 _, err = httpdtest.RemoveUser(user, http.StatusOK) 10199 assert.NoError(t, err) 10200 err = os.RemoveAll(user.GetHomeDir()) 10201 assert.NoError(t, err) 10202} 10203 10204func TestWebAPIVFolder(t *testing.T) { 10205 u := getTestUser() 10206 u.QuotaSize = 65535 10207 vdir := "/vdir" 10208 mappedPath := filepath.Join(os.TempDir(), "vdir") 10209 folderName := filepath.Base(mappedPath) 10210 u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{ 10211 BaseVirtualFolder: vfs.BaseVirtualFolder{ 10212 Name: folderName, 10213 MappedPath: mappedPath, 10214 }, 10215 VirtualPath: vdir, 10216 QuotaSize: -1, 10217 QuotaFiles: -1, 10218 }) 10219 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 10220 assert.NoError(t, err) 10221 10222 webAPIToken, err := getJWTAPIUserTokenFromTestServer(user.Username, defaultPassword) 10223 assert.NoError(t, err) 10224 10225 fileContents := []byte("test contents") 10226 10227 body := new(bytes.Buffer) 10228 writer := multipart.NewWriter(body) 10229 part, err := writer.CreateFormFile("filenames", "file.txt") 10230 assert.NoError(t, err) 10231 _, err = part.Write(fileContents) 10232 assert.NoError(t, err) 10233 err = writer.Close() 10234 assert.NoError(t, err) 10235 reader := bytes.NewReader(body.Bytes()) 10236 10237 req, err := http.NewRequest(http.MethodPost, userFilesPath+"?path=vdir", reader) 10238 assert.NoError(t, err) 10239 req.Header.Add("Content-Type", writer.FormDataContentType()) 10240 setBearerForReq(req, webAPIToken) 10241 rr := executeRequest(req) 10242 checkResponseCode(t, http.StatusCreated, rr) 10243 10244 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 10245 assert.NoError(t, err) 10246 assert.Equal(t, int64(len(fileContents)), user.UsedQuotaSize) 10247 10248 folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK) 10249 assert.NoError(t, err) 10250 assert.Equal(t, int64(len(fileContents)), folder.UsedQuotaSize) 10251 10252 _, err = reader.Seek(0, io.SeekStart) 10253 assert.NoError(t, err) 10254 req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=vdir", reader) 10255 assert.NoError(t, err) 10256 req.Header.Add("Content-Type", writer.FormDataContentType()) 10257 setBearerForReq(req, webAPIToken) 10258 rr = executeRequest(req) 10259 checkResponseCode(t, http.StatusCreated, rr) 10260 10261 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 10262 assert.NoError(t, err) 10263 assert.Equal(t, int64(len(fileContents)), user.UsedQuotaSize) 10264 10265 folder, _, err = httpdtest.GetFolderByName(folderName, http.StatusOK) 10266 assert.NoError(t, err) 10267 assert.Equal(t, int64(len(fileContents)), folder.UsedQuotaSize) 10268 10269 _, err = httpdtest.RemoveUser(user, http.StatusOK) 10270 assert.NoError(t, err) 10271 _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK) 10272 assert.NoError(t, err) 10273 err = os.RemoveAll(user.GetHomeDir()) 10274 assert.NoError(t, err) 10275 err = os.RemoveAll(mappedPath) 10276 assert.NoError(t, err) 10277} 10278 10279func TestWebAPIWritePermission(t *testing.T) { 10280 u := getTestUser() 10281 u.Filters.WebClient = append(u.Filters.WebClient, sdk.WebClientWriteDisabled) 10282 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 10283 assert.NoError(t, err) 10284 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 10285 assert.NoError(t, err) 10286 10287 body := new(bytes.Buffer) 10288 writer := multipart.NewWriter(body) 10289 part, err := writer.CreateFormFile("filenames", "file.txt") 10290 assert.NoError(t, err) 10291 _, err = part.Write([]byte("")) 10292 assert.NoError(t, err) 10293 err = writer.Close() 10294 assert.NoError(t, err) 10295 reader := bytes.NewReader(body.Bytes()) 10296 10297 req, err := http.NewRequest(http.MethodPost, userFilesPath, reader) 10298 assert.NoError(t, err) 10299 req.Header.Add("Content-Type", writer.FormDataContentType()) 10300 setBearerForReq(req, webAPIToken) 10301 rr := executeRequest(req) 10302 checkResponseCode(t, http.StatusForbidden, rr) 10303 10304 req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=a&target=b", nil) 10305 assert.NoError(t, err) 10306 req.Header.Add("Content-Type", writer.FormDataContentType()) 10307 setBearerForReq(req, webAPIToken) 10308 rr = executeRequest(req) 10309 checkResponseCode(t, http.StatusForbidden, rr) 10310 10311 req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=a", nil) 10312 assert.NoError(t, err) 10313 req.Header.Add("Content-Type", writer.FormDataContentType()) 10314 setBearerForReq(req, webAPIToken) 10315 rr = executeRequest(req) 10316 checkResponseCode(t, http.StatusForbidden, rr) 10317 10318 req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path=a.txt", nil) 10319 assert.NoError(t, err) 10320 req.Header.Add("Content-Type", writer.FormDataContentType()) 10321 setBearerForReq(req, webAPIToken) 10322 rr = executeRequest(req) 10323 checkResponseCode(t, http.StatusNotFound, rr) 10324 10325 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 10326 assert.NoError(t, err) 10327 req.Header.Add("Content-Type", writer.FormDataContentType()) 10328 setBearerForReq(req, webAPIToken) 10329 rr = executeRequest(req) 10330 checkResponseCode(t, http.StatusOK, rr) 10331 10332 req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path=dir", nil) 10333 assert.NoError(t, err) 10334 req.Header.Add("Content-Type", writer.FormDataContentType()) 10335 setBearerForReq(req, webAPIToken) 10336 rr = executeRequest(req) 10337 checkResponseCode(t, http.StatusForbidden, rr) 10338 10339 req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path=dir&target=dir1", nil) 10340 assert.NoError(t, err) 10341 req.Header.Add("Content-Type", writer.FormDataContentType()) 10342 setBearerForReq(req, webAPIToken) 10343 rr = executeRequest(req) 10344 checkResponseCode(t, http.StatusForbidden, rr) 10345 10346 req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path=dir", nil) 10347 assert.NoError(t, err) 10348 req.Header.Add("Content-Type", writer.FormDataContentType()) 10349 setBearerForReq(req, webAPIToken) 10350 rr = executeRequest(req) 10351 checkResponseCode(t, http.StatusForbidden, rr) 10352 10353 _, err = httpdtest.RemoveUser(user, http.StatusOK) 10354 assert.NoError(t, err) 10355 err = os.RemoveAll(user.GetHomeDir()) 10356 assert.NoError(t, err) 10357} 10358 10359func TestWebAPICryptFs(t *testing.T) { 10360 u := getTestUser() 10361 u.QuotaSize = 65535 10362 u.FsConfig.Provider = sdk.CryptedFilesystemProvider 10363 u.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret(defaultPassword) 10364 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 10365 assert.NoError(t, err) 10366 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 10367 assert.NoError(t, err) 10368 10369 body := new(bytes.Buffer) 10370 writer := multipart.NewWriter(body) 10371 part, err := writer.CreateFormFile("filenames", "file.txt") 10372 assert.NoError(t, err) 10373 _, err = part.Write([]byte("content")) 10374 assert.NoError(t, err) 10375 err = writer.Close() 10376 assert.NoError(t, err) 10377 reader := bytes.NewReader(body.Bytes()) 10378 10379 req, err := http.NewRequest(http.MethodPost, userFilesPath, reader) 10380 assert.NoError(t, err) 10381 req.Header.Add("Content-Type", writer.FormDataContentType()) 10382 setBearerForReq(req, webAPIToken) 10383 rr := executeRequest(req) 10384 checkResponseCode(t, http.StatusCreated, rr) 10385 10386 _, err = reader.Seek(0, io.SeekStart) 10387 assert.NoError(t, err) 10388 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 10389 assert.NoError(t, err) 10390 req.Header.Add("Content-Type", writer.FormDataContentType()) 10391 setBearerForReq(req, webAPIToken) 10392 rr = executeRequest(req) 10393 checkResponseCode(t, http.StatusCreated, rr) 10394 10395 _, err = httpdtest.RemoveUser(user, http.StatusOK) 10396 assert.NoError(t, err) 10397 err = os.RemoveAll(user.GetHomeDir()) 10398 assert.NoError(t, err) 10399} 10400 10401func TestWebUploadSFTP(t *testing.T) { 10402 u := getTestUser() 10403 localUser, _, err := httpdtest.AddUser(u, http.StatusCreated) 10404 assert.NoError(t, err) 10405 u = getTestSFTPUser() 10406 u.QuotaFiles = 100 10407 u.FsConfig.SFTPConfig.BufferSize = 2 10408 u.HomeDir = filepath.Join(os.TempDir(), u.Username) 10409 sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated) 10410 assert.NoError(t, err) 10411 10412 webAPIToken, err := getJWTAPIUserTokenFromTestServer(sftpUser.Username, defaultPassword) 10413 assert.NoError(t, err) 10414 10415 body := new(bytes.Buffer) 10416 writer := multipart.NewWriter(body) 10417 part, err := writer.CreateFormFile("filenames", "file.txt") 10418 assert.NoError(t, err) 10419 _, err = part.Write([]byte("test file content")) 10420 assert.NoError(t, err) 10421 err = writer.Close() 10422 assert.NoError(t, err) 10423 reader := bytes.NewReader(body.Bytes()) 10424 10425 req, err := http.NewRequest(http.MethodPost, userFilesPath, reader) 10426 assert.NoError(t, err) 10427 req.Header.Add("Content-Type", writer.FormDataContentType()) 10428 setBearerForReq(req, webAPIToken) 10429 rr := executeRequest(req) 10430 checkResponseCode(t, http.StatusCreated, rr) 10431 10432 expectedQuotaSize := int64(17) 10433 expectedQuotaFiles := 1 10434 user, _, err := httpdtest.GetUserByUsername(sftpUser.Username, http.StatusOK) 10435 assert.NoError(t, err) 10436 assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles) 10437 assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize) 10438 10439 user.QuotaSize = 10 10440 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 10441 assert.NoError(t, err) 10442 // we are now overquota on overwrite 10443 _, err = reader.Seek(0, io.SeekStart) 10444 assert.NoError(t, err) 10445 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 10446 assert.NoError(t, err) 10447 req.Header.Add("Content-Type", writer.FormDataContentType()) 10448 setBearerForReq(req, webAPIToken) 10449 rr = executeRequest(req) 10450 checkResponseCode(t, http.StatusRequestEntityTooLarge, rr) 10451 assert.Contains(t, rr.Body.String(), "denying write due to space limit") 10452 // delete the file 10453 req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file.txt", nil) 10454 assert.NoError(t, err) 10455 setBearerForReq(req, webAPIToken) 10456 rr = executeRequest(req) 10457 checkResponseCode(t, http.StatusOK, rr) 10458 10459 _, err = reader.Seek(0, io.SeekStart) 10460 assert.NoError(t, err) 10461 req, err = http.NewRequest(http.MethodPost, userFilesPath, reader) 10462 assert.NoError(t, err) 10463 req.Header.Add("Content-Type", writer.FormDataContentType()) 10464 setBearerForReq(req, webAPIToken) 10465 rr = executeRequest(req) 10466 checkResponseCode(t, http.StatusRequestEntityTooLarge, rr) 10467 assert.Contains(t, rr.Body.String(), "denying write due to space limit") 10468 10469 _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) 10470 assert.NoError(t, err) 10471 _, err = httpdtest.RemoveUser(localUser, http.StatusOK) 10472 assert.NoError(t, err) 10473 err = os.RemoveAll(localUser.GetHomeDir()) 10474 assert.NoError(t, err) 10475 err = os.RemoveAll(sftpUser.GetHomeDir()) 10476 assert.NoError(t, err) 10477} 10478 10479func TestWebUploadMultipartFormReadError(t *testing.T) { 10480 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 10481 assert.NoError(t, err) 10482 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 10483 assert.NoError(t, err) 10484 10485 req, err := http.NewRequest(http.MethodPost, userFilesPath, nil) 10486 assert.NoError(t, err) 10487 10488 mpartForm := &multipart.Form{ 10489 File: make(map[string][]*multipart.FileHeader), 10490 } 10491 mpartForm.File["filenames"] = append(mpartForm.File["filenames"], &multipart.FileHeader{Filename: "missing"}) 10492 req.MultipartForm = mpartForm 10493 req.Header.Add("Content-Type", "multipart/form-data") 10494 setBearerForReq(req, webAPIToken) 10495 rr := executeRequest(req) 10496 checkResponseCode(t, http.StatusInternalServerError, rr) 10497 assert.Contains(t, rr.Body.String(), "Unable to read uploaded file") 10498 10499 _, err = httpdtest.RemoveUser(user, http.StatusOK) 10500 assert.NoError(t, err) 10501 err = os.RemoveAll(user.GetHomeDir()) 10502 assert.NoError(t, err) 10503} 10504 10505func TestCompressionErrorMock(t *testing.T) { 10506 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 10507 assert.NoError(t, err) 10508 10509 defer func() { 10510 rcv := recover() 10511 assert.Equal(t, http.ErrAbortHandler, rcv) 10512 _, err := httpdtest.RemoveUser(user, http.StatusOK) 10513 assert.NoError(t, err) 10514 err = os.RemoveAll(user.GetHomeDir()) 10515 assert.NoError(t, err) 10516 }() 10517 10518 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 10519 assert.NoError(t, err) 10520 10521 req, _ := http.NewRequest(http.MethodGet, webClientDownloadZipPath+"?path="+url.QueryEscape("/")+"&files="+ 10522 url.QueryEscape(`["missing"]`), nil) 10523 setJWTCookieForReq(req, webToken) 10524 executeRequest(req) 10525} 10526 10527func TestGetFilesSFTPBackend(t *testing.T) { 10528 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 10529 assert.NoError(t, err) 10530 u := getTestSFTPUser() 10531 u.FsConfig.SFTPConfig.BufferSize = 2 10532 u.Permissions["/adir"] = nil 10533 u.Permissions["/adir1"] = []string{dataprovider.PermListItems} 10534 u.Filters.FilePatterns = []sdk.PatternsFilter{ 10535 { 10536 Path: "/adir2", 10537 DeniedPatterns: []string{"*.txt"}, 10538 }, 10539 } 10540 sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated) 10541 assert.NoError(t, err) 10542 10543 testFileName := "testsftpfile" 10544 testDir := "testsftpdir" 10545 testFileContents := []byte("sftp file contents") 10546 err = os.MkdirAll(filepath.Join(user.GetHomeDir(), testDir, "sub"), os.ModePerm) 10547 assert.NoError(t, err) 10548 err = os.MkdirAll(filepath.Join(user.GetHomeDir(), "adir1"), os.ModePerm) 10549 assert.NoError(t, err) 10550 err = os.MkdirAll(filepath.Join(user.GetHomeDir(), "adir2"), os.ModePerm) 10551 assert.NoError(t, err) 10552 err = os.WriteFile(filepath.Join(user.GetHomeDir(), testFileName), testFileContents, os.ModePerm) 10553 assert.NoError(t, err) 10554 err = os.WriteFile(filepath.Join(user.GetHomeDir(), "adir1", "afile"), testFileContents, os.ModePerm) 10555 assert.NoError(t, err) 10556 err = os.WriteFile(filepath.Join(user.GetHomeDir(), "adir2", "afile.txt"), testFileContents, os.ModePerm) 10557 assert.NoError(t, err) 10558 webToken, err := getJWTWebClientTokenFromTestServer(sftpUser.Username, defaultPassword) 10559 assert.NoError(t, err) 10560 req, _ := http.NewRequest(http.MethodGet, webClientFilesPath, nil) 10561 setJWTCookieForReq(req, webToken) 10562 rr := executeRequest(req) 10563 checkResponseCode(t, http.StatusOK, rr) 10564 10565 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+path.Join(testDir, "sub"), nil) 10566 setJWTCookieForReq(req, webToken) 10567 rr = executeRequest(req) 10568 checkResponseCode(t, http.StatusOK, rr) 10569 10570 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+path.Join(testDir, "missing"), nil) 10571 setJWTCookieForReq(req, webToken) 10572 rr = executeRequest(req) 10573 checkResponseCode(t, http.StatusOK, rr) 10574 assert.Contains(t, rr.Body.String(), "card-body text-form-error") 10575 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path=adir/sub", nil) 10576 setJWTCookieForReq(req, webToken) 10577 rr = executeRequest(req) 10578 checkResponseCode(t, http.StatusOK, rr) 10579 assert.Contains(t, rr.Body.String(), "card-body text-form-error") 10580 10581 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path=adir1/afile", nil) 10582 setJWTCookieForReq(req, webToken) 10583 rr = executeRequest(req) 10584 checkResponseCode(t, http.StatusOK, rr) 10585 assert.Contains(t, rr.Body.String(), "card-body text-form-error") 10586 10587 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path=adir2/afile.txt", nil) 10588 setJWTCookieForReq(req, webToken) 10589 rr = executeRequest(req) 10590 checkResponseCode(t, http.StatusOK, rr) 10591 assert.Contains(t, rr.Body.String(), "card-body text-form-error") 10592 10593 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 10594 setJWTCookieForReq(req, webToken) 10595 rr = executeRequest(req) 10596 checkResponseCode(t, http.StatusOK, rr) 10597 assert.Equal(t, testFileContents, rr.Body.Bytes()) 10598 10599 req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 10600 req.Header.Set("Range", "bytes=2-") 10601 setJWTCookieForReq(req, webToken) 10602 rr = executeRequest(req) 10603 checkResponseCode(t, http.StatusPartialContent, rr) 10604 assert.Equal(t, testFileContents[2:], rr.Body.Bytes()) 10605 10606 _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) 10607 assert.NoError(t, err) 10608 err = os.RemoveAll(sftpUser.GetHomeDir()) 10609 assert.NoError(t, err) 10610 _, err = httpdtest.RemoveUser(user, http.StatusOK) 10611 assert.NoError(t, err) 10612 err = os.RemoveAll(user.GetHomeDir()) 10613 assert.NoError(t, err) 10614} 10615 10616func TestClientUserClose(t *testing.T) { 10617 u := getTestUser() 10618 u.UploadBandwidth = 32 10619 u.DownloadBandwidth = 32 10620 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 10621 assert.NoError(t, err) 10622 testFileName := "file.dat" 10623 testFileSize := int64(524288) 10624 testFilePath := filepath.Join(user.GetHomeDir(), testFileName) 10625 err = createTestFile(testFilePath, testFileSize) 10626 assert.NoError(t, err) 10627 uploadContent := make([]byte, testFileSize) 10628 _, err = rand.Read(uploadContent) 10629 assert.NoError(t, err) 10630 webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 10631 assert.NoError(t, err) 10632 webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 10633 assert.NoError(t, err) 10634 10635 var wg sync.WaitGroup 10636 wg.Add(1) 10637 go func() { 10638 defer wg.Done() 10639 req, _ := http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil) 10640 setJWTCookieForReq(req, webToken) 10641 rr := executeRequest(req) 10642 checkResponseCode(t, http.StatusOK, rr) 10643 }() 10644 wg.Add(1) 10645 go func() { 10646 defer wg.Done() 10647 req, _ := http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFileName, nil) 10648 setJWTCookieForReq(req, webToken) 10649 rr := executeRequest(req) 10650 checkResponseCode(t, http.StatusInternalServerError, rr) 10651 assert.Contains(t, rr.Body.String(), "Unable to read the file") 10652 }() 10653 wg.Add(1) 10654 go func() { 10655 defer wg.Done() 10656 body := new(bytes.Buffer) 10657 writer := multipart.NewWriter(body) 10658 part, err := writer.CreateFormFile("filenames", "upload.dat") 10659 assert.NoError(t, err) 10660 n, err := part.Write(uploadContent) 10661 assert.NoError(t, err) 10662 assert.Equal(t, testFileSize, int64(n)) 10663 err = writer.Close() 10664 assert.NoError(t, err) 10665 reader := bytes.NewReader(body.Bytes()) 10666 req, err := http.NewRequest(http.MethodPost, userFilesPath, reader) 10667 assert.NoError(t, err) 10668 req.Header.Add("Content-Type", writer.FormDataContentType()) 10669 setBearerForReq(req, webAPIToken) 10670 rr := executeRequest(req) 10671 checkResponseCode(t, http.StatusInternalServerError, rr) 10672 assert.Contains(t, rr.Body.String(), "transfer aborted") 10673 }() 10674 // wait for the transfers 10675 assert.Eventually(t, func() bool { 10676 stats := common.Connections.GetStats() 10677 if len(stats) == 3 { 10678 if len(stats[0].Transfers) > 0 && len(stats[1].Transfers) > 0 { 10679 return true 10680 } 10681 } 10682 return false 10683 }, 1*time.Second, 50*time.Millisecond) 10684 10685 for _, stat := range common.Connections.GetStats() { 10686 // close all the active transfers 10687 common.Connections.Close(stat.ConnectionID) 10688 } 10689 wg.Wait() 10690 assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 }, 10691 1*time.Second, 100*time.Millisecond) 10692 10693 _, err = httpdtest.RemoveUser(user, http.StatusOK) 10694 assert.NoError(t, err) 10695 err = os.RemoveAll(user.GetHomeDir()) 10696 assert.NoError(t, err) 10697} 10698 10699func TestWebAdminSetupMock(t *testing.T) { 10700 req, err := http.NewRequest(http.MethodGet, webAdminSetupPath, nil) 10701 assert.NoError(t, err) 10702 rr := executeRequest(req) 10703 checkResponseCode(t, http.StatusFound, rr) 10704 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 10705 // now delete all the admins 10706 admins, err := dataprovider.GetAdmins(100, 0, dataprovider.OrderASC) 10707 assert.NoError(t, err) 10708 for _, admin := range admins { 10709 err = dataprovider.DeleteAdmin(admin.Username, "", "") 10710 assert.NoError(t, err) 10711 } 10712 // close the provider and initializes it without creating the default admin 10713 os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "0") 10714 err = dataprovider.Close() 10715 assert.NoError(t, err) 10716 err = config.LoadConfig(configDir, "") 10717 assert.NoError(t, err) 10718 providerConf := config.GetProviderConf() 10719 providerConf.CredentialsPath = credentialsPath 10720 err = os.RemoveAll(credentialsPath) 10721 assert.NoError(t, err) 10722 err = dataprovider.Initialize(providerConf, configDir, true) 10723 assert.NoError(t, err) 10724 // now the setup page must be rendered 10725 req, err = http.NewRequest(http.MethodGet, webAdminSetupPath, nil) 10726 assert.NoError(t, err) 10727 rr = executeRequest(req) 10728 checkResponseCode(t, http.StatusOK, rr) 10729 // check redirects to the setup page 10730 req, err = http.NewRequest(http.MethodGet, "/", nil) 10731 assert.NoError(t, err) 10732 rr = executeRequest(req) 10733 checkResponseCode(t, http.StatusFound, rr) 10734 assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location")) 10735 req, err = http.NewRequest(http.MethodGet, webBasePath, nil) 10736 assert.NoError(t, err) 10737 rr = executeRequest(req) 10738 checkResponseCode(t, http.StatusFound, rr) 10739 assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location")) 10740 req, err = http.NewRequest(http.MethodGet, webBasePathAdmin, nil) 10741 assert.NoError(t, err) 10742 rr = executeRequest(req) 10743 checkResponseCode(t, http.StatusFound, rr) 10744 assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location")) 10745 req, err = http.NewRequest(http.MethodGet, webLoginPath, nil) 10746 assert.NoError(t, err) 10747 rr = executeRequest(req) 10748 checkResponseCode(t, http.StatusFound, rr) 10749 assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location")) 10750 req, err = http.NewRequest(http.MethodGet, webClientLoginPath, nil) 10751 assert.NoError(t, err) 10752 rr = executeRequest(req) 10753 checkResponseCode(t, http.StatusFound, rr) 10754 assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location")) 10755 10756 csrfToken, err := getCSRFToken(httpBaseURL + webAdminSetupPath) 10757 assert.NoError(t, err) 10758 form := make(url.Values) 10759 req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode()))) 10760 assert.NoError(t, err) 10761 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10762 rr = executeRequest(req) 10763 checkResponseCode(t, http.StatusForbidden, rr) 10764 form.Set(csrfFormToken, csrfToken) 10765 req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode()))) 10766 assert.NoError(t, err) 10767 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10768 rr = executeRequest(req) 10769 checkResponseCode(t, http.StatusOK, rr) 10770 assert.Contains(t, rr.Body.String(), "Please set a username") 10771 form.Set("username", defaultTokenAuthUser) 10772 req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode()))) 10773 assert.NoError(t, err) 10774 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10775 rr = executeRequest(req) 10776 checkResponseCode(t, http.StatusOK, rr) 10777 assert.Contains(t, rr.Body.String(), "Please set a password") 10778 form.Set("password", defaultTokenAuthPass) 10779 req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode()))) 10780 assert.NoError(t, err) 10781 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10782 rr = executeRequest(req) 10783 checkResponseCode(t, http.StatusOK, rr) 10784 assert.Contains(t, rr.Body.String(), "Passwords mismatch") 10785 form.Set("confirm_password", defaultTokenAuthPass) 10786 // test a parse form error 10787 req, err = http.NewRequest(http.MethodPost, webAdminSetupPath+"?param=p%C3%AO%GH", bytes.NewBuffer([]byte(form.Encode()))) 10788 assert.NoError(t, err) 10789 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10790 rr = executeRequest(req) 10791 checkResponseCode(t, http.StatusOK, rr) 10792 // test a dataprovider error 10793 err = dataprovider.Close() 10794 assert.NoError(t, err) 10795 req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode()))) 10796 assert.NoError(t, err) 10797 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10798 rr = executeRequest(req) 10799 checkResponseCode(t, http.StatusOK, rr) 10800 // finally initialize the provider and create the default admin 10801 err = config.LoadConfig(configDir, "") 10802 assert.NoError(t, err) 10803 providerConf = config.GetProviderConf() 10804 providerConf.CredentialsPath = credentialsPath 10805 err = os.RemoveAll(credentialsPath) 10806 assert.NoError(t, err) 10807 err = dataprovider.Initialize(providerConf, configDir, true) 10808 assert.NoError(t, err) 10809 req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode()))) 10810 assert.NoError(t, err) 10811 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10812 rr = executeRequest(req) 10813 checkResponseCode(t, http.StatusFound, rr) 10814 assert.Equal(t, webUsersPath, rr.Header().Get("Location")) 10815 // if we resubmit the form we get a bad request, an admin already exists 10816 req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode()))) 10817 assert.NoError(t, err) 10818 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10819 rr = executeRequest(req) 10820 checkResponseCode(t, http.StatusBadRequest, rr) 10821 assert.Contains(t, rr.Body.String(), "an admin user already exists") 10822 os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1") 10823} 10824 10825func TestWebAdminLoginMock(t *testing.T) { 10826 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 10827 assert.NoError(t, err) 10828 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 10829 assert.NoError(t, err) 10830 10831 req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil) 10832 setBearerForReq(req, apiToken) 10833 rr := executeRequest(req) 10834 checkResponseCode(t, http.StatusOK, rr) 10835 10836 req, _ = http.NewRequest(http.MethodGet, webStatusPath+"notfound", nil) 10837 req.RequestURI = webStatusPath + "notfound" 10838 setJWTCookieForReq(req, webToken) 10839 rr = executeRequest(req) 10840 checkResponseCode(t, http.StatusNotFound, rr) 10841 10842 req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil) 10843 setJWTCookieForReq(req, webToken) 10844 rr = executeRequest(req) 10845 checkResponseCode(t, http.StatusOK, rr) 10846 10847 req, _ = http.NewRequest(http.MethodGet, webLogoutPath, nil) 10848 setJWTCookieForReq(req, webToken) 10849 rr = executeRequest(req) 10850 checkResponseCode(t, http.StatusFound, rr) 10851 cookie := rr.Header().Get("Cookie") 10852 assert.Empty(t, cookie) 10853 10854 req, _ = http.NewRequest(http.MethodGet, logoutPath, nil) 10855 setBearerForReq(req, apiToken) 10856 rr = executeRequest(req) 10857 checkResponseCode(t, http.StatusOK, rr) 10858 10859 req, _ = http.NewRequest(http.MethodGet, serverStatusPath, nil) 10860 setBearerForReq(req, apiToken) 10861 rr = executeRequest(req) 10862 checkResponseCode(t, http.StatusUnauthorized, rr) 10863 assert.Contains(t, rr.Body.String(), "Your token is no longer valid") 10864 10865 req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil) 10866 setJWTCookieForReq(req, webToken) 10867 rr = executeRequest(req) 10868 checkResponseCode(t, http.StatusFound, rr) 10869 10870 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 10871 assert.NoError(t, err) 10872 // now try using wrong credentials 10873 form := getLoginForm(defaultTokenAuthUser, "wrong pwd", csrfToken) 10874 req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 10875 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10876 rr = executeRequest(req) 10877 checkResponseCode(t, http.StatusOK, rr) 10878 // try from an ip not allowed 10879 a := getTestAdmin() 10880 a.Username = altAdminUsername 10881 a.Password = altAdminPassword 10882 a.Filters.AllowList = []string{"10.0.0.0/8"} 10883 10884 _, _, err = httpdtest.AddAdmin(a, http.StatusCreated) 10885 assert.NoError(t, err) 10886 10887 form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken) 10888 req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 10889 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10890 req.RemoteAddr = "127.1.1.1:1234" 10891 rr = executeRequest(req) 10892 checkResponseCode(t, http.StatusOK, rr) 10893 assert.Contains(t, rr.Body.String(), "login from IP 127.1.1.1 not allowed") 10894 10895 req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 10896 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10897 req.RemoteAddr = "10.9.9.9:1234" 10898 rr = executeRequest(req) 10899 checkResponseCode(t, http.StatusFound, rr) 10900 10901 req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 10902 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10903 req.RemoteAddr = "127.0.1.1:4567" 10904 req.Header.Set("X-Forwarded-For", "10.9.9.9") 10905 rr = executeRequest(req) 10906 checkResponseCode(t, http.StatusOK, rr) 10907 assert.Contains(t, rr.Body.String(), "login from IP 127.0.1.1 not allowed") 10908 10909 // invalid csrf token 10910 form = getLoginForm(altAdminUsername, altAdminPassword, "invalid csrf") 10911 req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 10912 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10913 req.RemoteAddr = "10.9.9.8:1234" 10914 rr = executeRequest(req) 10915 checkResponseCode(t, http.StatusOK, rr) 10916 assert.Contains(t, rr.Body.String(), "unable to verify form token") 10917 10918 req, _ = http.NewRequest(http.MethodGet, webLoginPath, nil) 10919 rr = executeRequest(req) 10920 checkResponseCode(t, http.StatusOK, rr) 10921 10922 _, err = httpdtest.RemoveAdmin(a, http.StatusOK) 10923 assert.NoError(t, err) 10924} 10925 10926func TestAdminNoToken(t *testing.T) { 10927 req, _ := http.NewRequest(http.MethodGet, webAdminProfilePath, nil) 10928 rr := executeRequest(req) 10929 checkResponseCode(t, http.StatusFound, rr) 10930 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 10931 10932 req, _ = http.NewRequest(http.MethodGet, webUserPath, nil) 10933 rr = executeRequest(req) 10934 checkResponseCode(t, http.StatusFound, rr) 10935 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 10936 10937 req, _ = http.NewRequest(http.MethodGet, userPath, nil) 10938 rr = executeRequest(req) 10939 checkResponseCode(t, http.StatusUnauthorized, rr) 10940 10941 req, _ = http.NewRequest(http.MethodGet, activeConnectionsPath, nil) 10942 rr = executeRequest(req) 10943 checkResponseCode(t, http.StatusUnauthorized, rr) 10944} 10945 10946func TestWebUserShare(t *testing.T) { 10947 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 10948 assert.NoError(t, err) 10949 10950 csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath) 10951 assert.NoError(t, err) 10952 token, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 10953 assert.NoError(t, err) 10954 userAPItoken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) 10955 assert.NoError(t, err) 10956 10957 share := dataprovider.Share{ 10958 Name: "test share", 10959 Description: "test share desc", 10960 Scope: dataprovider.ShareScopeRead, 10961 Paths: []string{"/"}, 10962 ExpiresAt: util.GetTimeAsMsSinceEpoch(time.Now().Add(24 * time.Hour)), 10963 MaxTokens: 100, 10964 AllowFrom: []string{"127.0.0.0/8", "172.16.0.0/16"}, 10965 Password: defaultPassword, 10966 } 10967 form := make(url.Values) 10968 form.Set("name", share.Name) 10969 form.Set("scope", strconv.Itoa(int(share.Scope))) 10970 form.Set("paths", "/") 10971 form.Set("max_tokens", strconv.Itoa(share.MaxTokens)) 10972 form.Set("allowed_ip", strings.Join(share.AllowFrom, ",")) 10973 form.Set("description", share.Description) 10974 form.Set("password", share.Password) 10975 form.Set("expiration_date", "123") 10976 // invalid expiration date 10977 req, err := http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode()))) 10978 assert.NoError(t, err) 10979 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10980 setJWTCookieForReq(req, token) 10981 rr := executeRequest(req) 10982 checkResponseCode(t, http.StatusOK, rr) 10983 assert.Contains(t, rr.Body.String(), "cannot parse") 10984 form.Set("expiration_date", util.GetTimeFromMsecSinceEpoch(share.ExpiresAt).UTC().Format("2006-01-02 15:04:05")) 10985 form.Set("scope", "") 10986 // invalid scope 10987 req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode()))) 10988 assert.NoError(t, err) 10989 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 10990 setJWTCookieForReq(req, token) 10991 rr = executeRequest(req) 10992 checkResponseCode(t, http.StatusOK, rr) 10993 assert.Contains(t, rr.Body.String(), "invalid syntax") 10994 form.Set("scope", strconv.Itoa(int(share.Scope))) 10995 // invalid max tokens 10996 form.Set("max_tokens", "t") 10997 req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode()))) 10998 assert.NoError(t, err) 10999 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11000 setJWTCookieForReq(req, token) 11001 rr = executeRequest(req) 11002 checkResponseCode(t, http.StatusOK, rr) 11003 assert.Contains(t, rr.Body.String(), "invalid syntax") 11004 form.Set("max_tokens", strconv.Itoa(share.MaxTokens)) 11005 // no csrf token 11006 req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode()))) 11007 assert.NoError(t, err) 11008 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11009 setJWTCookieForReq(req, token) 11010 rr = executeRequest(req) 11011 checkResponseCode(t, http.StatusForbidden, rr) 11012 assert.Contains(t, rr.Body.String(), "unable to verify form token") 11013 11014 form.Set(csrfFormToken, csrfToken) 11015 form.Set("scope", "100") 11016 req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode()))) 11017 assert.NoError(t, err) 11018 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11019 setJWTCookieForReq(req, token) 11020 rr = executeRequest(req) 11021 checkResponseCode(t, http.StatusOK, rr) 11022 assert.Contains(t, rr.Body.String(), "Validation error: invalid scope") 11023 11024 form.Set("scope", strconv.Itoa(int(share.Scope))) 11025 req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode()))) 11026 assert.NoError(t, err) 11027 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11028 setJWTCookieForReq(req, token) 11029 rr = executeRequest(req) 11030 checkResponseCode(t, http.StatusSeeOther, rr) 11031 11032 req, err = http.NewRequest(http.MethodGet, userSharesPath, nil) 11033 assert.NoError(t, err) 11034 setBearerForReq(req, userAPItoken) 11035 rr = executeRequest(req) 11036 checkResponseCode(t, http.StatusOK, rr) 11037 var shares []dataprovider.Share 11038 err = json.Unmarshal(rr.Body.Bytes(), &shares) 11039 assert.NoError(t, err) 11040 if assert.Len(t, shares, 1) { 11041 s := shares[0] 11042 assert.Equal(t, share.Name, s.Name) 11043 assert.Equal(t, share.Description, s.Description) 11044 assert.Equal(t, share.Scope, s.Scope) 11045 assert.Equal(t, share.Paths, s.Paths) 11046 assert.InDelta(t, share.ExpiresAt, s.ExpiresAt, 999) 11047 assert.Equal(t, share.MaxTokens, s.MaxTokens) 11048 assert.Equal(t, share.AllowFrom, s.AllowFrom) 11049 assert.Equal(t, redactedSecret, s.Password) 11050 share.ShareID = s.ShareID 11051 } 11052 form.Set("password", redactedSecret) 11053 form.Set("expiration_date", "123") 11054 req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/unknowid", bytes.NewBuffer([]byte(form.Encode()))) 11055 assert.NoError(t, err) 11056 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11057 setJWTCookieForReq(req, token) 11058 rr = executeRequest(req) 11059 checkResponseCode(t, http.StatusNotFound, rr) 11060 11061 req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/"+share.ShareID, bytes.NewBuffer([]byte(form.Encode()))) 11062 assert.NoError(t, err) 11063 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11064 setJWTCookieForReq(req, token) 11065 rr = executeRequest(req) 11066 checkResponseCode(t, http.StatusOK, rr) 11067 assert.Contains(t, rr.Body.String(), "cannot parse") 11068 11069 form.Set("expiration_date", "") 11070 form.Set(csrfFormToken, "") 11071 req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/"+share.ShareID, bytes.NewBuffer([]byte(form.Encode()))) 11072 assert.NoError(t, err) 11073 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11074 setJWTCookieForReq(req, token) 11075 rr = executeRequest(req) 11076 checkResponseCode(t, http.StatusForbidden, rr) 11077 assert.Contains(t, rr.Body.String(), "unable to verify form token") 11078 11079 form.Set(csrfFormToken, csrfToken) 11080 form.Set("allowed_ip", "1.1.1") 11081 req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/"+share.ShareID, bytes.NewBuffer([]byte(form.Encode()))) 11082 assert.NoError(t, err) 11083 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11084 setJWTCookieForReq(req, token) 11085 rr = executeRequest(req) 11086 checkResponseCode(t, http.StatusOK, rr) 11087 assert.Contains(t, rr.Body.String(), "Validation error: could not parse allow from entry") 11088 11089 form.Set("allowed_ip", "") 11090 req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/"+share.ShareID, bytes.NewBuffer([]byte(form.Encode()))) 11091 assert.NoError(t, err) 11092 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11093 setJWTCookieForReq(req, token) 11094 rr = executeRequest(req) 11095 checkResponseCode(t, http.StatusSeeOther, rr) 11096 11097 req, err = http.NewRequest(http.MethodGet, userSharesPath, nil) 11098 assert.NoError(t, err) 11099 setBearerForReq(req, userAPItoken) 11100 rr = executeRequest(req) 11101 checkResponseCode(t, http.StatusOK, rr) 11102 shares = nil 11103 err = json.Unmarshal(rr.Body.Bytes(), &shares) 11104 assert.NoError(t, err) 11105 if assert.Len(t, shares, 1) { 11106 s := shares[0] 11107 assert.Equal(t, share.Name, s.Name) 11108 assert.Equal(t, share.Description, s.Description) 11109 assert.Equal(t, share.Scope, s.Scope) 11110 assert.Equal(t, share.Paths, s.Paths) 11111 assert.Equal(t, int64(0), s.ExpiresAt) 11112 assert.Equal(t, share.MaxTokens, s.MaxTokens) 11113 assert.Empty(t, s.AllowFrom) 11114 } 11115 // check the password 11116 s, err := dataprovider.ShareExists(share.ShareID, user.Username) 11117 assert.NoError(t, err) 11118 match, err := s.CheckPassword(defaultPassword) 11119 assert.NoError(t, err) 11120 assert.True(t, match) 11121 11122 req, err = http.NewRequest(http.MethodGet, webClientSharePath+"?path=%2F&files=a", nil) 11123 assert.NoError(t, err) 11124 setJWTCookieForReq(req, token) 11125 rr = executeRequest(req) 11126 checkResponseCode(t, http.StatusBadRequest, rr) 11127 assert.Contains(t, rr.Body.String(), "Invalid share list") 11128 11129 req, err = http.NewRequest(http.MethodGet, webClientSharePath+"?path=%2F&files=%5B\"adir\"%5D", nil) 11130 assert.NoError(t, err) 11131 setJWTCookieForReq(req, token) 11132 rr = executeRequest(req) 11133 checkResponseCode(t, http.StatusOK, rr) 11134 11135 req, err = http.NewRequest(http.MethodGet, webClientSharePath+"/unknown", nil) 11136 assert.NoError(t, err) 11137 setJWTCookieForReq(req, token) 11138 rr = executeRequest(req) 11139 checkResponseCode(t, http.StatusNotFound, rr) 11140 11141 req, err = http.NewRequest(http.MethodGet, webClientSharePath+"/"+share.ShareID, nil) 11142 assert.NoError(t, err) 11143 setJWTCookieForReq(req, token) 11144 rr = executeRequest(req) 11145 checkResponseCode(t, http.StatusOK, rr) 11146 11147 req, err = http.NewRequest(http.MethodGet, webClientSharesPath+"?qlimit=a", nil) 11148 assert.NoError(t, err) 11149 setJWTCookieForReq(req, token) 11150 rr = executeRequest(req) 11151 checkResponseCode(t, http.StatusOK, rr) 11152 11153 req, err = http.NewRequest(http.MethodGet, webClientSharesPath+"?qlimit=1", nil) 11154 assert.NoError(t, err) 11155 setJWTCookieForReq(req, token) 11156 rr = executeRequest(req) 11157 checkResponseCode(t, http.StatusOK, rr) 11158 11159 err = os.RemoveAll(user.GetHomeDir()) 11160 assert.NoError(t, err) 11161 _, err = httpdtest.RemoveUser(user, http.StatusOK) 11162 assert.NoError(t, err) 11163} 11164 11165func TestWebUserProfile(t *testing.T) { 11166 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 11167 assert.NoError(t, err) 11168 11169 csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath) 11170 assert.NoError(t, err) 11171 token, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 11172 assert.NoError(t, err) 11173 11174 email := "user@user.com" 11175 description := "User" 11176 11177 form := make(url.Values) 11178 form.Set("allow_api_key_auth", "1") 11179 form.Set("email", email) 11180 form.Set("description", description) 11181 form.Set("public_keys", testPubKey) 11182 form.Add("public_keys", testPubKey1) 11183 // no csrf token 11184 req, err := http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11185 assert.NoError(t, err) 11186 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11187 setJWTCookieForReq(req, token) 11188 rr := executeRequest(req) 11189 checkResponseCode(t, http.StatusForbidden, rr) 11190 assert.Contains(t, rr.Body.String(), "unable to verify form token") 11191 11192 form.Set(csrfFormToken, csrfToken) 11193 req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11194 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11195 setJWTCookieForReq(req, token) 11196 rr = executeRequest(req) 11197 checkResponseCode(t, http.StatusOK, rr) 11198 assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated") 11199 11200 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 11201 assert.NoError(t, err) 11202 assert.True(t, user.Filters.AllowAPIKeyAuth) 11203 assert.Len(t, user.PublicKeys, 2) 11204 assert.Equal(t, email, user.Email) 11205 assert.Equal(t, description, user.Description) 11206 11207 // set an invalid email 11208 form.Set("email", "not an email") 11209 req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11210 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11211 setJWTCookieForReq(req, token) 11212 rr = executeRequest(req) 11213 checkResponseCode(t, http.StatusOK, rr) 11214 assert.Contains(t, rr.Body.String(), "Validation error: email") 11215 // invalid public key 11216 form.Set("email", email) 11217 form.Set("public_keys", "invalid") 11218 req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11219 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11220 setJWTCookieForReq(req, token) 11221 rr = executeRequest(req) 11222 checkResponseCode(t, http.StatusOK, rr) 11223 assert.Contains(t, rr.Body.String(), "Validation error: could not parse key") 11224 // now remove permissions 11225 form.Set("public_keys", testPubKey) 11226 user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled} 11227 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 11228 assert.NoError(t, err) 11229 token, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 11230 assert.NoError(t, err) 11231 11232 form.Set("allow_api_key_auth", "0") 11233 form.Set(csrfFormToken, csrfToken) 11234 req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11235 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11236 setJWTCookieForReq(req, token) 11237 rr = executeRequest(req) 11238 checkResponseCode(t, http.StatusOK, rr) 11239 assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated") 11240 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 11241 assert.NoError(t, err) 11242 assert.True(t, user.Filters.AllowAPIKeyAuth) 11243 assert.Len(t, user.PublicKeys, 1) 11244 assert.Equal(t, email, user.Email) 11245 assert.Equal(t, description, user.Description) 11246 11247 user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientPubKeyChangeDisabled} 11248 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 11249 assert.NoError(t, err) 11250 token, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 11251 assert.NoError(t, err) 11252 form.Set("public_keys", testPubKey) 11253 form.Add("public_keys", testPubKey1) 11254 req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11255 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11256 setJWTCookieForReq(req, token) 11257 rr = executeRequest(req) 11258 checkResponseCode(t, http.StatusOK, rr) 11259 assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated") 11260 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 11261 assert.NoError(t, err) 11262 assert.True(t, user.Filters.AllowAPIKeyAuth) 11263 assert.Len(t, user.PublicKeys, 1) 11264 assert.Equal(t, email, user.Email) 11265 assert.Equal(t, description, user.Description) 11266 11267 user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientInfoChangeDisabled} 11268 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 11269 assert.NoError(t, err) 11270 token, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 11271 assert.NoError(t, err) 11272 form.Set("email", "newemail@user.com") 11273 form.Set("description", "new description") 11274 req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11275 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11276 setJWTCookieForReq(req, token) 11277 rr = executeRequest(req) 11278 checkResponseCode(t, http.StatusOK, rr) 11279 assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated") 11280 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 11281 assert.NoError(t, err) 11282 assert.True(t, user.Filters.AllowAPIKeyAuth) 11283 assert.Len(t, user.PublicKeys, 2) 11284 assert.Equal(t, email, user.Email) 11285 assert.Equal(t, description, user.Description) 11286 // finally disable all profile permissions 11287 user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientInfoChangeDisabled, 11288 sdk.WebClientPubKeyChangeDisabled} 11289 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 11290 assert.NoError(t, err) 11291 token, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 11292 assert.NoError(t, err) 11293 req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11294 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11295 setJWTCookieForReq(req, token) 11296 rr = executeRequest(req) 11297 checkResponseCode(t, http.StatusForbidden, rr) 11298 11299 err = os.RemoveAll(user.GetHomeDir()) 11300 assert.NoError(t, err) 11301 _, err = httpdtest.RemoveUser(user, http.StatusOK) 11302 assert.NoError(t, err) 11303 11304 form = make(url.Values) 11305 form.Set(csrfFormToken, csrfToken) 11306 req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11307 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11308 setJWTCookieForReq(req, token) 11309 rr = executeRequest(req) 11310 checkResponseCode(t, http.StatusInternalServerError, rr) 11311} 11312 11313func TestWebAdminProfile(t *testing.T) { 11314 admin := getTestAdmin() 11315 admin.Username = altAdminUsername 11316 admin.Password = altAdminPassword 11317 admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) 11318 assert.NoError(t, err) 11319 token, err := getJWTWebTokenFromTestServer(admin.Username, altAdminPassword) 11320 assert.NoError(t, err) 11321 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 11322 assert.NoError(t, err) 11323 req, err := http.NewRequest(http.MethodGet, webAdminProfilePath, nil) 11324 assert.NoError(t, err) 11325 setJWTCookieForReq(req, token) 11326 rr := executeRequest(req) 11327 checkResponseCode(t, http.StatusOK, rr) 11328 11329 form := make(url.Values) 11330 form.Set("allow_api_key_auth", "1") 11331 form.Set("email", "admin@example.com") 11332 form.Set("description", "admin desc") 11333 // no csrf token 11334 req, err = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11335 assert.NoError(t, err) 11336 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11337 setJWTCookieForReq(req, token) 11338 rr = executeRequest(req) 11339 checkResponseCode(t, http.StatusForbidden, rr) 11340 assert.Contains(t, rr.Body.String(), "unable to verify form token") 11341 11342 form.Set(csrfFormToken, csrfToken) 11343 req, _ = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11344 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11345 setJWTCookieForReq(req, token) 11346 rr = executeRequest(req) 11347 checkResponseCode(t, http.StatusOK, rr) 11348 assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated") 11349 11350 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 11351 assert.NoError(t, err) 11352 assert.True(t, admin.Filters.AllowAPIKeyAuth) 11353 assert.Equal(t, "admin@example.com", admin.Email) 11354 assert.Equal(t, "admin desc", admin.Description) 11355 11356 form = make(url.Values) 11357 form.Set(csrfFormToken, csrfToken) 11358 req, _ = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11359 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11360 setJWTCookieForReq(req, token) 11361 rr = executeRequest(req) 11362 checkResponseCode(t, http.StatusOK, rr) 11363 assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated") 11364 11365 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 11366 assert.NoError(t, err) 11367 assert.False(t, admin.Filters.AllowAPIKeyAuth) 11368 assert.Empty(t, admin.Email) 11369 assert.Empty(t, admin.Description) 11370 11371 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 11372 assert.NoError(t, err) 11373 11374 form = make(url.Values) 11375 form.Set(csrfFormToken, csrfToken) 11376 req, _ = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode()))) 11377 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11378 setJWTCookieForReq(req, token) 11379 rr = executeRequest(req) 11380 checkResponseCode(t, http.StatusInternalServerError, rr) 11381} 11382 11383func TestWebAdminPwdChange(t *testing.T) { 11384 admin := getTestAdmin() 11385 admin.Username = altAdminUsername 11386 admin.Password = altAdminPassword 11387 admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) 11388 assert.NoError(t, err) 11389 11390 token, err := getJWTWebTokenFromTestServer(admin.Username, altAdminPassword) 11391 assert.NoError(t, err) 11392 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 11393 assert.NoError(t, err) 11394 req, err := http.NewRequest(http.MethodGet, webChangeAdminPwdPath, nil) 11395 assert.NoError(t, err) 11396 setJWTCookieForReq(req, token) 11397 rr := executeRequest(req) 11398 checkResponseCode(t, http.StatusOK, rr) 11399 form := make(url.Values) 11400 form.Set("current_password", altAdminPassword) 11401 form.Set("new_password1", altAdminPassword) 11402 form.Set("new_password2", altAdminPassword) 11403 // no csrf token 11404 req, _ = http.NewRequest(http.MethodPost, webChangeAdminPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 11405 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11406 setJWTCookieForReq(req, token) 11407 rr = executeRequest(req) 11408 checkResponseCode(t, http.StatusForbidden, rr) 11409 assert.Contains(t, rr.Body.String(), "unable to verify form token") 11410 11411 form.Set(csrfFormToken, csrfToken) 11412 req, _ = http.NewRequest(http.MethodPost, webChangeAdminPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 11413 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11414 setJWTCookieForReq(req, token) 11415 rr = executeRequest(req) 11416 checkResponseCode(t, http.StatusOK, rr) 11417 assert.Contains(t, rr.Body.String(), "the new password must be different from the current one") 11418 11419 form.Set("new_password1", altAdminPassword+"1") 11420 form.Set("new_password2", altAdminPassword+"1") 11421 req, _ = http.NewRequest(http.MethodPost, webChangeAdminPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 11422 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11423 setJWTCookieForReq(req, token) 11424 rr = executeRequest(req) 11425 checkResponseCode(t, http.StatusFound, rr) 11426 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 11427 11428 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 11429 assert.NoError(t, err) 11430} 11431 11432func TestAPIKeysManagement(t *testing.T) { 11433 admin := getTestAdmin() 11434 admin.Username = altAdminUsername 11435 admin.Password = altAdminPassword 11436 admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) 11437 assert.NoError(t, err) 11438 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 11439 assert.NoError(t, err) 11440 apiKey := dataprovider.APIKey{ 11441 Name: "test key", 11442 Scope: dataprovider.APIKeyScopeAdmin, 11443 } 11444 asJSON, err := json.Marshal(apiKey) 11445 assert.NoError(t, err) 11446 req, err := http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer(asJSON)) 11447 assert.NoError(t, err) 11448 setBearerForReq(req, token) 11449 rr := executeRequest(req) 11450 checkResponseCode(t, http.StatusCreated, rr) 11451 location := rr.Header().Get("Location") 11452 assert.NotEmpty(t, location) 11453 objectID := rr.Header().Get("X-Object-ID") 11454 assert.NotEmpty(t, objectID) 11455 assert.Equal(t, fmt.Sprintf("%v/%v", apiKeysPath, objectID), location) 11456 apiKey.KeyID = objectID 11457 response := make(map[string]string) 11458 err = json.Unmarshal(rr.Body.Bytes(), &response) 11459 assert.NoError(t, err) 11460 key := response["key"] 11461 assert.NotEmpty(t, key) 11462 assert.True(t, strings.HasPrefix(key, apiKey.KeyID+".")) 11463 11464 req, err = http.NewRequest(http.MethodGet, location, nil) 11465 assert.NoError(t, err) 11466 setBearerForReq(req, token) 11467 rr = executeRequest(req) 11468 checkResponseCode(t, http.StatusOK, rr) 11469 var keyGet dataprovider.APIKey 11470 err = json.Unmarshal(rr.Body.Bytes(), &keyGet) 11471 assert.NoError(t, err) 11472 assert.Empty(t, keyGet.Key) 11473 assert.Equal(t, apiKey.KeyID, keyGet.KeyID) 11474 assert.Equal(t, apiKey.Scope, keyGet.Scope) 11475 assert.Equal(t, apiKey.Name, keyGet.Name) 11476 assert.Equal(t, int64(0), keyGet.ExpiresAt) 11477 assert.Equal(t, int64(0), keyGet.LastUseAt) 11478 assert.Greater(t, keyGet.CreatedAt, int64(0)) 11479 assert.Greater(t, keyGet.UpdatedAt, int64(0)) 11480 assert.Empty(t, keyGet.Description) 11481 assert.Empty(t, keyGet.User) 11482 assert.Empty(t, keyGet.Admin) 11483 11484 // API key is not enabled for the admin user so this request should fail 11485 req, err = http.NewRequest(http.MethodGet, versionPath, nil) 11486 assert.NoError(t, err) 11487 setAPIKeyForReq(req, key, admin.Username) 11488 rr = executeRequest(req) 11489 checkResponseCode(t, http.StatusUnauthorized, rr) 11490 assert.Contains(t, rr.Body.String(), "the admin associated with the provided api key cannot be authenticated") 11491 11492 admin.Filters.AllowAPIKeyAuth = true 11493 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 11494 assert.NoError(t, err) 11495 req, err = http.NewRequest(http.MethodGet, versionPath, nil) 11496 assert.NoError(t, err) 11497 setAPIKeyForReq(req, key, admin.Username) 11498 rr = executeRequest(req) 11499 checkResponseCode(t, http.StatusOK, rr) 11500 11501 req, err = http.NewRequest(http.MethodGet, versionPath, nil) 11502 assert.NoError(t, err) 11503 setAPIKeyForReq(req, key, admin.Username+"1") 11504 rr = executeRequest(req) 11505 checkResponseCode(t, http.StatusUnauthorized, rr) 11506 11507 req, err = http.NewRequest(http.MethodGet, versionPath, nil) 11508 assert.NoError(t, err) 11509 setAPIKeyForReq(req, key, "") 11510 rr = executeRequest(req) 11511 checkResponseCode(t, http.StatusUnauthorized, rr) 11512 11513 // now associate the key directly to the admin 11514 apiKey.Admin = admin.Username 11515 apiKey.Description = "test description" 11516 asJSON, err = json.Marshal(apiKey) 11517 assert.NoError(t, err) 11518 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON)) 11519 assert.NoError(t, err) 11520 setBearerForReq(req, token) 11521 rr = executeRequest(req) 11522 checkResponseCode(t, http.StatusOK, rr) 11523 11524 req, err = http.NewRequest(http.MethodGet, apiKeysPath, nil) 11525 assert.NoError(t, err) 11526 setBearerForReq(req, token) 11527 rr = executeRequest(req) 11528 checkResponseCode(t, http.StatusOK, rr) 11529 var keys []dataprovider.APIKey 11530 err = json.Unmarshal(rr.Body.Bytes(), &keys) 11531 assert.NoError(t, err) 11532 if assert.GreaterOrEqual(t, len(keys), 1) { 11533 found := false 11534 for _, k := range keys { 11535 if k.KeyID == apiKey.KeyID { 11536 found = true 11537 assert.Empty(t, k.Key) 11538 assert.Equal(t, apiKey.Scope, k.Scope) 11539 assert.Equal(t, apiKey.Name, k.Name) 11540 assert.Equal(t, int64(0), k.ExpiresAt) 11541 assert.Greater(t, k.LastUseAt, int64(0)) 11542 assert.Equal(t, k.CreatedAt, keyGet.CreatedAt) 11543 assert.Greater(t, k.UpdatedAt, keyGet.UpdatedAt) 11544 assert.Equal(t, apiKey.Description, k.Description) 11545 assert.Empty(t, k.User) 11546 assert.Equal(t, admin.Username, k.Admin) 11547 } 11548 } 11549 assert.True(t, found) 11550 } 11551 req, err = http.NewRequest(http.MethodGet, versionPath, nil) 11552 assert.NoError(t, err) 11553 setAPIKeyForReq(req, key, "") 11554 rr = executeRequest(req) 11555 checkResponseCode(t, http.StatusOK, rr) 11556 // invalid API keys 11557 req, err = http.NewRequest(http.MethodGet, versionPath, nil) 11558 assert.NoError(t, err) 11559 setAPIKeyForReq(req, key+"invalid", "") 11560 rr = executeRequest(req) 11561 checkResponseCode(t, http.StatusUnauthorized, rr) 11562 assert.Contains(t, rr.Body.String(), "the provided api key cannot be authenticated") 11563 req, err = http.NewRequest(http.MethodGet, versionPath, nil) 11564 assert.NoError(t, err) 11565 setAPIKeyForReq(req, "invalid", "") 11566 rr = executeRequest(req) 11567 checkResponseCode(t, http.StatusBadRequest, rr) 11568 // using an API key we cannot modify/get API keys 11569 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON)) 11570 assert.NoError(t, err) 11571 setAPIKeyForReq(req, key, "") 11572 rr = executeRequest(req) 11573 checkResponseCode(t, http.StatusForbidden, rr) 11574 11575 req, err = http.NewRequest(http.MethodGet, location, nil) 11576 assert.NoError(t, err) 11577 setAPIKeyForReq(req, key, "") 11578 rr = executeRequest(req) 11579 checkResponseCode(t, http.StatusForbidden, rr) 11580 11581 admin.Filters.AllowList = []string{"172.16.18.0/24"} 11582 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 11583 assert.NoError(t, err) 11584 req, err = http.NewRequest(http.MethodGet, versionPath, nil) 11585 assert.NoError(t, err) 11586 setAPIKeyForReq(req, key, "") 11587 rr = executeRequest(req) 11588 checkResponseCode(t, http.StatusUnauthorized, rr) 11589 11590 req, err = http.NewRequest(http.MethodDelete, location, nil) 11591 assert.NoError(t, err) 11592 setBearerForReq(req, token) 11593 rr = executeRequest(req) 11594 checkResponseCode(t, http.StatusOK, rr) 11595 11596 req, err = http.NewRequest(http.MethodGet, versionPath, nil) 11597 assert.NoError(t, err) 11598 setAPIKeyForReq(req, key, "") 11599 rr = executeRequest(req) 11600 checkResponseCode(t, http.StatusBadRequest, rr) 11601 assert.Contains(t, rr.Body.String(), "the provided api key is not valid") 11602 11603 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 11604 assert.NoError(t, err) 11605} 11606 11607func TestAPIKeySearch(t *testing.T) { 11608 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 11609 assert.NoError(t, err) 11610 apiKey := dataprovider.APIKey{ 11611 Scope: dataprovider.APIKeyScopeAdmin, 11612 } 11613 for i := 1; i < 5; i++ { 11614 apiKey.Name = fmt.Sprintf("testapikey%v", i) 11615 asJSON, err := json.Marshal(apiKey) 11616 assert.NoError(t, err) 11617 req, err := http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer(asJSON)) 11618 assert.NoError(t, err) 11619 setBearerForReq(req, token) 11620 rr := executeRequest(req) 11621 checkResponseCode(t, http.StatusCreated, rr) 11622 } 11623 11624 req, err := http.NewRequest(http.MethodGet, apiKeysPath+"?limit=1&order=ASC", nil) 11625 assert.NoError(t, err) 11626 setBearerForReq(req, token) 11627 rr := executeRequest(req) 11628 checkResponseCode(t, http.StatusOK, rr) 11629 var keys []dataprovider.APIKey 11630 err = json.Unmarshal(rr.Body.Bytes(), &keys) 11631 assert.NoError(t, err) 11632 assert.Len(t, keys, 1) 11633 firstKey := keys[0] 11634 11635 req, err = http.NewRequest(http.MethodGet, apiKeysPath+"?limit=1&order=DESC", nil) 11636 assert.NoError(t, err) 11637 setBearerForReq(req, token) 11638 rr = executeRequest(req) 11639 checkResponseCode(t, http.StatusOK, rr) 11640 keys = nil 11641 err = json.Unmarshal(rr.Body.Bytes(), &keys) 11642 assert.NoError(t, err) 11643 if assert.Len(t, keys, 1) { 11644 assert.NotEqual(t, firstKey.KeyID, keys[0].KeyID) 11645 } 11646 11647 req, err = http.NewRequest(http.MethodGet, apiKeysPath+"?limit=1&offset=100", nil) 11648 assert.NoError(t, err) 11649 setBearerForReq(req, token) 11650 rr = executeRequest(req) 11651 checkResponseCode(t, http.StatusOK, rr) 11652 keys = nil 11653 err = json.Unmarshal(rr.Body.Bytes(), &keys) 11654 assert.NoError(t, err) 11655 assert.Len(t, keys, 0) 11656 11657 req, err = http.NewRequest(http.MethodGet, apiKeysPath+"?limit=a", nil) 11658 assert.NoError(t, err) 11659 setBearerForReq(req, token) 11660 rr = executeRequest(req) 11661 checkResponseCode(t, http.StatusBadRequest, rr) 11662 11663 req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v/%v", apiKeysPath, "missingid"), nil) 11664 assert.NoError(t, err) 11665 setBearerForReq(req, token) 11666 rr = executeRequest(req) 11667 checkResponseCode(t, http.StatusNotFound, rr) 11668 11669 req, err = http.NewRequest(http.MethodGet, apiKeysPath, nil) 11670 assert.NoError(t, err) 11671 setBearerForReq(req, token) 11672 rr = executeRequest(req) 11673 checkResponseCode(t, http.StatusOK, rr) 11674 keys = nil 11675 err = json.Unmarshal(rr.Body.Bytes(), &keys) 11676 assert.NoError(t, err) 11677 counter := 0 11678 for _, k := range keys { 11679 if strings.HasPrefix(k.Name, "testapikey") { 11680 req, err = http.NewRequest(http.MethodDelete, fmt.Sprintf("%v/%v", apiKeysPath, k.KeyID), nil) 11681 assert.NoError(t, err) 11682 setBearerForReq(req, token) 11683 rr = executeRequest(req) 11684 checkResponseCode(t, http.StatusOK, rr) 11685 counter++ 11686 } 11687 } 11688 assert.Equal(t, 4, counter) 11689} 11690 11691func TestAPIKeyErrors(t *testing.T) { 11692 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 11693 assert.NoError(t, err) 11694 apiKey := dataprovider.APIKey{ 11695 Name: "testkey", 11696 Scope: dataprovider.APIKeyScopeUser, 11697 } 11698 asJSON, err := json.Marshal(apiKey) 11699 assert.NoError(t, err) 11700 req, err := http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer(asJSON)) 11701 assert.NoError(t, err) 11702 setBearerForReq(req, token) 11703 rr := executeRequest(req) 11704 checkResponseCode(t, http.StatusCreated, rr) 11705 location := rr.Header().Get("Location") 11706 assert.NotEmpty(t, location) 11707 11708 // invalid API scope 11709 apiKey.Scope = 1000 11710 asJSON, err = json.Marshal(apiKey) 11711 assert.NoError(t, err) 11712 req, err = http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer(asJSON)) 11713 assert.NoError(t, err) 11714 setBearerForReq(req, token) 11715 rr = executeRequest(req) 11716 checkResponseCode(t, http.StatusBadRequest, rr) 11717 11718 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON)) 11719 assert.NoError(t, err) 11720 setBearerForReq(req, token) 11721 rr = executeRequest(req) 11722 checkResponseCode(t, http.StatusBadRequest, rr) 11723 11724 // invalid JSON 11725 req, err = http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer([]byte(`invalid JSON`))) 11726 assert.NoError(t, err) 11727 setBearerForReq(req, token) 11728 rr = executeRequest(req) 11729 checkResponseCode(t, http.StatusBadRequest, rr) 11730 11731 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer([]byte(`invalid JSON`))) 11732 assert.NoError(t, err) 11733 setBearerForReq(req, token) 11734 rr = executeRequest(req) 11735 checkResponseCode(t, http.StatusBadRequest, rr) 11736 11737 req, err = http.NewRequest(http.MethodDelete, location, nil) 11738 assert.NoError(t, err) 11739 setBearerForReq(req, token) 11740 rr = executeRequest(req) 11741 checkResponseCode(t, http.StatusOK, rr) 11742 11743 req, err = http.NewRequest(http.MethodDelete, location, nil) 11744 assert.NoError(t, err) 11745 setBearerForReq(req, token) 11746 rr = executeRequest(req) 11747 checkResponseCode(t, http.StatusNotFound, rr) 11748 11749 req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON)) 11750 assert.NoError(t, err) 11751 setBearerForReq(req, token) 11752 rr = executeRequest(req) 11753 checkResponseCode(t, http.StatusNotFound, rr) 11754} 11755 11756func TestAPIKeyOnDeleteCascade(t *testing.T) { 11757 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 11758 assert.NoError(t, err) 11759 admin := getTestAdmin() 11760 admin.Username = altAdminUsername 11761 admin.Password = altAdminPassword 11762 admin, _, err = httpdtest.AddAdmin(admin, http.StatusCreated) 11763 assert.NoError(t, err) 11764 11765 apiKey := dataprovider.APIKey{ 11766 Name: "user api key", 11767 Scope: dataprovider.APIKeyScopeUser, 11768 User: user.Username, 11769 } 11770 11771 apiKey, _, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated) 11772 assert.NoError(t, err) 11773 11774 req, err := http.NewRequest(http.MethodGet, userDirsPath, nil) 11775 assert.NoError(t, err) 11776 setAPIKeyForReq(req, apiKey.Key, "") 11777 rr := executeRequest(req) 11778 checkResponseCode(t, http.StatusUnauthorized, rr) 11779 11780 user.Filters.AllowAPIKeyAuth = true 11781 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 11782 assert.NoError(t, err) 11783 req, err = http.NewRequest(http.MethodGet, userDirsPath, nil) 11784 assert.NoError(t, err) 11785 setAPIKeyForReq(req, apiKey.Key, "") 11786 rr = executeRequest(req) 11787 checkResponseCode(t, http.StatusOK, rr) 11788 var contents []map[string]interface{} 11789 err = json.NewDecoder(rr.Body).Decode(&contents) 11790 assert.NoError(t, err) 11791 assert.Len(t, contents, 0) 11792 11793 _, err = httpdtest.RemoveUser(user, http.StatusOK) 11794 assert.NoError(t, err) 11795 err = os.RemoveAll(user.GetHomeDir()) 11796 assert.NoError(t, err) 11797 11798 _, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusNotFound) 11799 assert.NoError(t, err) 11800 11801 apiKey.User = "" 11802 apiKey.Admin = admin.Username 11803 apiKey.Scope = dataprovider.APIKeyScopeAdmin 11804 11805 apiKey, _, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated) 11806 assert.NoError(t, err) 11807 11808 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 11809 assert.NoError(t, err) 11810 11811 _, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusNotFound) 11812 assert.NoError(t, err) 11813} 11814 11815func TestBasicWebUsersMock(t *testing.T) { 11816 token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 11817 assert.NoError(t, err) 11818 user := getTestUser() 11819 userAsJSON := getUserAsJSON(t, user) 11820 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 11821 setBearerForReq(req, token) 11822 rr := executeRequest(req) 11823 checkResponseCode(t, http.StatusCreated, rr) 11824 err = render.DecodeJSON(rr.Body, &user) 11825 assert.NoError(t, err) 11826 user1 := getTestUser() 11827 user1.Username += "1" 11828 user1AsJSON := getUserAsJSON(t, user1) 11829 req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(user1AsJSON)) 11830 setBearerForReq(req, token) 11831 rr = executeRequest(req) 11832 checkResponseCode(t, http.StatusCreated, rr) 11833 err = render.DecodeJSON(rr.Body, &user1) 11834 assert.NoError(t, err) 11835 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 11836 assert.NoError(t, err) 11837 req, _ = http.NewRequest(http.MethodGet, webUsersPath, nil) 11838 setJWTCookieForReq(req, webToken) 11839 rr = executeRequest(req) 11840 checkResponseCode(t, http.StatusOK, rr) 11841 req, _ = http.NewRequest(http.MethodGet, webUsersPath+"?qlimit=a", nil) 11842 setJWTCookieForReq(req, webToken) 11843 rr = executeRequest(req) 11844 checkResponseCode(t, http.StatusOK, rr) 11845 req, _ = http.NewRequest(http.MethodGet, webUsersPath+"?qlimit=1", nil) 11846 setJWTCookieForReq(req, webToken) 11847 rr = executeRequest(req) 11848 checkResponseCode(t, http.StatusOK, rr) 11849 req, _ = http.NewRequest(http.MethodGet, webUserPath, nil) 11850 setJWTCookieForReq(req, webToken) 11851 rr = executeRequest(req) 11852 checkResponseCode(t, http.StatusOK, rr) 11853 req, _ = http.NewRequest(http.MethodGet, path.Join(webUserPath, user.Username), nil) 11854 setJWTCookieForReq(req, webToken) 11855 rr = executeRequest(req) 11856 checkResponseCode(t, http.StatusOK, rr) 11857 req, _ = http.NewRequest(http.MethodGet, webUserPath+"/0", nil) 11858 setJWTCookieForReq(req, webToken) 11859 rr = executeRequest(req) 11860 checkResponseCode(t, http.StatusNotFound, rr) 11861 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 11862 assert.NoError(t, err) 11863 form := make(url.Values) 11864 form.Set("username", user.Username) 11865 form.Set(csrfFormToken, csrfToken) 11866 b, contentType, _ := getMultipartFormData(form, "", "") 11867 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 11868 setJWTCookieForReq(req, webToken) 11869 req.Header.Set("Content-Type", contentType) 11870 rr = executeRequest(req) 11871 checkResponseCode(t, http.StatusOK, rr) 11872 b, contentType, _ = getMultipartFormData(form, "", "") 11873 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 11874 setJWTCookieForReq(req, webToken) 11875 req.Header.Set("Content-Type", contentType) 11876 rr = executeRequest(req) 11877 checkResponseCode(t, http.StatusOK, rr) 11878 b, contentType, _ = getMultipartFormData(form, "", "") 11879 req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", &b) 11880 setJWTCookieForReq(req, webToken) 11881 req.Header.Set("Content-Type", contentType) 11882 rr = executeRequest(req) 11883 checkResponseCode(t, http.StatusNotFound, rr) 11884 req, _ = http.NewRequest(http.MethodPost, webUserPath+"/aaa", &b) 11885 setJWTCookieForReq(req, webToken) 11886 req.Header.Set("Content-Type", contentType) 11887 rr = executeRequest(req) 11888 checkResponseCode(t, http.StatusNotFound, rr) 11889 req, _ = http.NewRequest(http.MethodDelete, path.Join(webUserPath, user.Username), nil) 11890 setJWTCookieForReq(req, webToken) 11891 rr = executeRequest(req) 11892 checkResponseCode(t, http.StatusForbidden, rr) 11893 assert.Contains(t, rr.Body.String(), "Invalid token") 11894 req, _ = http.NewRequest(http.MethodDelete, path.Join(webUserPath, user.Username), nil) 11895 setJWTCookieForReq(req, webToken) 11896 setCSRFHeaderForReq(req, csrfToken) 11897 rr = executeRequest(req) 11898 checkResponseCode(t, http.StatusOK, rr) 11899 req, _ = http.NewRequest(http.MethodDelete, path.Join(webUserPath, user1.Username), nil) 11900 setJWTCookieForReq(req, webToken) 11901 setCSRFHeaderForReq(req, csrfToken) 11902 rr = executeRequest(req) 11903 checkResponseCode(t, http.StatusOK, rr) 11904} 11905 11906func TestRenderDefenderPageMock(t *testing.T) { 11907 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 11908 assert.NoError(t, err) 11909 req, err := http.NewRequest(http.MethodGet, webDefenderPath, nil) 11910 assert.NoError(t, err) 11911 setJWTCookieForReq(req, token) 11912 rr := executeRequest(req) 11913 checkResponseCode(t, http.StatusOK, rr) 11914 assert.Contains(t, rr.Body.String(), "View and manage blocklist") 11915} 11916 11917func TestWebAdminBasicMock(t *testing.T) { 11918 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 11919 assert.NoError(t, err) 11920 admin := getTestAdmin() 11921 admin.Username = altAdminUsername 11922 admin.Password = altAdminPassword 11923 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 11924 assert.NoError(t, err) 11925 form := make(url.Values) 11926 form.Set("username", admin.Username) 11927 form.Set("password", "") 11928 form.Set("status", "1") 11929 form.Set("permissions", "*") 11930 form.Set("description", admin.Description) 11931 req, _ := http.NewRequest(http.MethodPost, webAdminPath, bytes.NewBuffer([]byte(form.Encode()))) 11932 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11933 setJWTCookieForReq(req, token) 11934 rr := executeRequest(req) 11935 checkResponseCode(t, http.StatusForbidden, rr) 11936 assert.Contains(t, rr.Body.String(), "unable to verify form token") 11937 11938 form.Set(csrfFormToken, csrfToken) 11939 form.Set("status", "a") 11940 req, _ = http.NewRequest(http.MethodPost, webAdminPath, bytes.NewBuffer([]byte(form.Encode()))) 11941 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11942 setJWTCookieForReq(req, token) 11943 rr = executeRequest(req) 11944 checkResponseCode(t, http.StatusOK, rr) 11945 11946 form.Set("status", "1") 11947 req, _ = http.NewRequest(http.MethodPost, webAdminPath, bytes.NewBuffer([]byte(form.Encode()))) 11948 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11949 setJWTCookieForReq(req, token) 11950 rr = executeRequest(req) 11951 checkResponseCode(t, http.StatusOK, rr) 11952 11953 form.Set("password", admin.Password) 11954 req, _ = http.NewRequest(http.MethodPost, webAdminPath, bytes.NewBuffer([]byte(form.Encode()))) 11955 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 11956 setJWTCookieForReq(req, token) 11957 rr = executeRequest(req) 11958 checkResponseCode(t, http.StatusSeeOther, rr) 11959 11960 // add TOTP config 11961 configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], altAdminUsername) 11962 assert.NoError(t, err) 11963 altToken, err := getJWTWebTokenFromTestServer(altAdminUsername, altAdminPassword) 11964 assert.NoError(t, err) 11965 adminTOTPConfig := dataprovider.TOTPConfig{ 11966 Enabled: true, 11967 ConfigName: configName, 11968 Secret: kms.NewPlainSecret(secret), 11969 } 11970 asJSON, err := json.Marshal(adminTOTPConfig) 11971 assert.NoError(t, err) 11972 // no CSRF token 11973 req, err = http.NewRequest(http.MethodPost, webAdminTOTPSavePath, bytes.NewBuffer(asJSON)) 11974 assert.NoError(t, err) 11975 setJWTCookieForReq(req, altToken) 11976 rr = executeRequest(req) 11977 checkResponseCode(t, http.StatusForbidden, rr) 11978 assert.Contains(t, rr.Body.String(), "Invalid token") 11979 11980 req, err = http.NewRequest(http.MethodPost, webAdminTOTPSavePath, bytes.NewBuffer(asJSON)) 11981 assert.NoError(t, err) 11982 setJWTCookieForReq(req, altToken) 11983 setCSRFHeaderForReq(req, csrfToken) 11984 rr = executeRequest(req) 11985 checkResponseCode(t, http.StatusOK, rr) 11986 11987 admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK) 11988 assert.NoError(t, err) 11989 assert.True(t, admin.Filters.TOTPConfig.Enabled) 11990 secretPayload := admin.Filters.TOTPConfig.Secret.GetPayload() 11991 assert.NotEmpty(t, secretPayload) 11992 11993 adminTOTPConfig = dataprovider.TOTPConfig{ 11994 Enabled: true, 11995 ConfigName: configName, 11996 Secret: kms.NewEmptySecret(), 11997 } 11998 asJSON, err = json.Marshal(adminTOTPConfig) 11999 assert.NoError(t, err) 12000 req, err = http.NewRequest(http.MethodPost, webAdminTOTPSavePath, bytes.NewBuffer(asJSON)) 12001 assert.NoError(t, err) 12002 setJWTCookieForReq(req, altToken) 12003 setCSRFHeaderForReq(req, csrfToken) 12004 rr = executeRequest(req) 12005 checkResponseCode(t, http.StatusOK, rr) 12006 12007 admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK) 12008 assert.NoError(t, err) 12009 assert.True(t, admin.Filters.TOTPConfig.Enabled) 12010 assert.Equal(t, secretPayload, admin.Filters.TOTPConfig.Secret.GetPayload()) 12011 12012 adminTOTPConfig = dataprovider.TOTPConfig{ 12013 Enabled: true, 12014 ConfigName: configName, 12015 Secret: nil, 12016 } 12017 asJSON, err = json.Marshal(adminTOTPConfig) 12018 assert.NoError(t, err) 12019 req, err = http.NewRequest(http.MethodPost, webAdminTOTPSavePath, bytes.NewBuffer(asJSON)) 12020 assert.NoError(t, err) 12021 setJWTCookieForReq(req, altToken) 12022 setCSRFHeaderForReq(req, csrfToken) 12023 rr = executeRequest(req) 12024 checkResponseCode(t, http.StatusOK, rr) 12025 12026 req, _ = http.NewRequest(http.MethodGet, webAdminsPath+"?qlimit=a", nil) 12027 setJWTCookieForReq(req, token) 12028 rr = executeRequest(req) 12029 checkResponseCode(t, http.StatusOK, rr) 12030 req, _ = http.NewRequest(http.MethodGet, webAdminsPath+"?qlimit=1", nil) 12031 setJWTCookieForReq(req, token) 12032 rr = executeRequest(req) 12033 checkResponseCode(t, http.StatusOK, rr) 12034 12035 req, _ = http.NewRequest(http.MethodGet, webAdminPath, nil) 12036 setJWTCookieForReq(req, token) 12037 rr = executeRequest(req) 12038 checkResponseCode(t, http.StatusOK, rr) 12039 12040 form.Set("password", "") 12041 req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode()))) 12042 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 12043 setJWTCookieForReq(req, token) 12044 rr = executeRequest(req) 12045 checkResponseCode(t, http.StatusSeeOther, rr) 12046 12047 form.Set(csrfFormToken, "invalid csrf") 12048 req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode()))) 12049 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 12050 setJWTCookieForReq(req, token) 12051 rr = executeRequest(req) 12052 checkResponseCode(t, http.StatusForbidden, rr) 12053 assert.Contains(t, rr.Body.String(), "unable to verify form token") 12054 12055 form.Set(csrfFormToken, csrfToken) 12056 form.Set("email", "not-an-email") 12057 req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode()))) 12058 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 12059 setJWTCookieForReq(req, token) 12060 rr = executeRequest(req) 12061 checkResponseCode(t, http.StatusOK, rr) 12062 12063 form.Set("email", "") 12064 form.Set("status", "b") 12065 req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode()))) 12066 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 12067 setJWTCookieForReq(req, token) 12068 rr = executeRequest(req) 12069 checkResponseCode(t, http.StatusOK, rr) 12070 12071 form.Set("email", "admin@example.com") 12072 form.Set("status", "0") 12073 req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode()))) 12074 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 12075 setJWTCookieForReq(req, token) 12076 rr = executeRequest(req) 12077 checkResponseCode(t, http.StatusSeeOther, rr) 12078 12079 admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK) 12080 assert.NoError(t, err) 12081 assert.True(t, admin.Filters.TOTPConfig.Enabled) 12082 assert.Equal(t, "admin@example.com", admin.Email) 12083 assert.Equal(t, 0, admin.Status) 12084 12085 req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername+"1"), bytes.NewBuffer([]byte(form.Encode()))) 12086 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 12087 setJWTCookieForReq(req, token) 12088 rr = executeRequest(req) 12089 checkResponseCode(t, http.StatusNotFound, rr) 12090 12091 req, _ = http.NewRequest(http.MethodGet, path.Join(webAdminPath, altAdminUsername), nil) 12092 setJWTCookieForReq(req, token) 12093 rr = executeRequest(req) 12094 checkResponseCode(t, http.StatusOK, rr) 12095 12096 req, _ = http.NewRequest(http.MethodGet, path.Join(webAdminPath, altAdminUsername+"1"), nil) 12097 setJWTCookieForReq(req, token) 12098 rr = executeRequest(req) 12099 checkResponseCode(t, http.StatusNotFound, rr) 12100 12101 req, _ = http.NewRequest(http.MethodDelete, path.Join(webAdminPath, altAdminUsername), nil) 12102 setJWTCookieForReq(req, token) 12103 setCSRFHeaderForReq(req, csrfToken) 12104 rr = executeRequest(req) 12105 checkResponseCode(t, http.StatusOK, rr) 12106 12107 _, err = httpdtest.RemoveAdmin(admin, http.StatusNotFound) 12108 assert.NoError(t, err) 12109 12110 req, _ = http.NewRequest(http.MethodDelete, path.Join(webAdminPath, defaultTokenAuthUser), nil) 12111 setJWTCookieForReq(req, token) 12112 setCSRFHeaderForReq(req, csrfToken) 12113 rr = executeRequest(req) 12114 checkResponseCode(t, http.StatusBadRequest, rr) 12115 assert.Contains(t, rr.Body.String(), "you cannot delete yourself") 12116 12117 req, _ = http.NewRequest(http.MethodDelete, path.Join(webAdminPath, defaultTokenAuthUser), nil) 12118 setJWTCookieForReq(req, token) 12119 rr = executeRequest(req) 12120 checkResponseCode(t, http.StatusForbidden, rr) 12121 assert.Contains(t, rr.Body.String(), "Invalid token") 12122} 12123 12124func TestWebAdminPermissions(t *testing.T) { 12125 admin := getTestAdmin() 12126 admin.Username = altAdminUsername 12127 admin.Password = altAdminPassword 12128 admin.Permissions = []string{dataprovider.PermAdminAddUsers} 12129 _, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) 12130 assert.NoError(t, err) 12131 12132 token, err := getJWTWebToken(altAdminUsername, altAdminPassword) 12133 require.NoError(t, err) 12134 12135 req, err := http.NewRequest(http.MethodGet, httpBaseURL+webUserPath, nil) 12136 assert.NoError(t, err) 12137 setJWTCookieForReq(req, token) 12138 resp, err := httpclient.GetHTTPClient().Do(req) 12139 require.NoError(t, err) 12140 defer resp.Body.Close() 12141 assert.Equal(t, http.StatusOK, resp.StatusCode) 12142 12143 req, err = http.NewRequest(http.MethodGet, httpBaseURL+path.Join(webUserPath, "auser"), nil) 12144 assert.NoError(t, err) 12145 setJWTCookieForReq(req, token) 12146 resp, err = httpclient.GetHTTPClient().Do(req) 12147 require.NoError(t, err) 12148 defer resp.Body.Close() 12149 assert.Equal(t, http.StatusForbidden, resp.StatusCode) 12150 12151 req, err = http.NewRequest(http.MethodGet, httpBaseURL+webFolderPath, nil) 12152 assert.NoError(t, err) 12153 setJWTCookieForReq(req, token) 12154 resp, err = httpclient.GetHTTPClient().Do(req) 12155 require.NoError(t, err) 12156 defer resp.Body.Close() 12157 assert.Equal(t, http.StatusOK, resp.StatusCode) 12158 12159 req, err = http.NewRequest(http.MethodGet, httpBaseURL+webStatusPath, nil) 12160 assert.NoError(t, err) 12161 setJWTCookieForReq(req, token) 12162 resp, err = httpclient.GetHTTPClient().Do(req) 12163 require.NoError(t, err) 12164 defer resp.Body.Close() 12165 assert.Equal(t, http.StatusForbidden, resp.StatusCode) 12166 12167 req, err = http.NewRequest(http.MethodGet, httpBaseURL+webConnectionsPath, nil) 12168 assert.NoError(t, err) 12169 setJWTCookieForReq(req, token) 12170 resp, err = httpclient.GetHTTPClient().Do(req) 12171 require.NoError(t, err) 12172 defer resp.Body.Close() 12173 assert.Equal(t, http.StatusForbidden, resp.StatusCode) 12174 12175 req, err = http.NewRequest(http.MethodGet, httpBaseURL+webAdminPath, nil) 12176 assert.NoError(t, err) 12177 setJWTCookieForReq(req, token) 12178 resp, err = httpclient.GetHTTPClient().Do(req) 12179 require.NoError(t, err) 12180 defer resp.Body.Close() 12181 assert.Equal(t, http.StatusForbidden, resp.StatusCode) 12182 12183 req, err = http.NewRequest(http.MethodGet, httpBaseURL+path.Join(webAdminPath, "a"), nil) 12184 assert.NoError(t, err) 12185 setJWTCookieForReq(req, token) 12186 resp, err = httpclient.GetHTTPClient().Do(req) 12187 require.NoError(t, err) 12188 defer resp.Body.Close() 12189 assert.Equal(t, http.StatusForbidden, resp.StatusCode) 12190 12191 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 12192 assert.NoError(t, err) 12193} 12194 12195func TestAdminUpdateSelfMock(t *testing.T) { 12196 admin, _, err := httpdtest.GetAdminByUsername(defaultTokenAuthUser, http.StatusOK) 12197 assert.NoError(t, err) 12198 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12199 assert.NoError(t, err) 12200 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 12201 assert.NoError(t, err) 12202 form := make(url.Values) 12203 form.Set("username", admin.Username) 12204 form.Set("password", admin.Password) 12205 form.Set("status", "0") 12206 form.Set("permissions", dataprovider.PermAdminAddUsers) 12207 form.Set("permissions", dataprovider.PermAdminCloseConnections) 12208 form.Set(csrfFormToken, csrfToken) 12209 req, _ := http.NewRequest(http.MethodPost, path.Join(webAdminPath, defaultTokenAuthUser), bytes.NewBuffer([]byte(form.Encode()))) 12210 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 12211 setJWTCookieForReq(req, token) 12212 rr := executeRequest(req) 12213 checkResponseCode(t, http.StatusOK, rr) 12214 assert.Contains(t, rr.Body.String(), "You cannot remove these permissions to yourself") 12215 12216 form.Set("permissions", dataprovider.PermAdminAny) 12217 req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, defaultTokenAuthUser), bytes.NewBuffer([]byte(form.Encode()))) 12218 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 12219 setJWTCookieForReq(req, token) 12220 rr = executeRequest(req) 12221 checkResponseCode(t, http.StatusOK, rr) 12222 assert.Contains(t, rr.Body.String(), "You cannot disable yourself") 12223} 12224 12225func TestWebMaintenanceMock(t *testing.T) { 12226 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12227 assert.NoError(t, err) 12228 req, _ := http.NewRequest(http.MethodGet, webMaintenancePath, nil) 12229 setJWTCookieForReq(req, token) 12230 rr := executeRequest(req) 12231 checkResponseCode(t, http.StatusOK, rr) 12232 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 12233 assert.NoError(t, err) 12234 12235 form := make(url.Values) 12236 form.Set("mode", "a") 12237 b, contentType, _ := getMultipartFormData(form, "", "") 12238 req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b) 12239 setJWTCookieForReq(req, token) 12240 req.Header.Set("Content-Type", contentType) 12241 rr = executeRequest(req) 12242 checkResponseCode(t, http.StatusForbidden, rr) 12243 assert.Contains(t, rr.Body.String(), "unable to verify form token") 12244 12245 form.Set(csrfFormToken, csrfToken) 12246 b, contentType, _ = getMultipartFormData(form, "", "") 12247 req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b) 12248 setJWTCookieForReq(req, token) 12249 req.Header.Set("Content-Type", contentType) 12250 rr = executeRequest(req) 12251 checkResponseCode(t, http.StatusOK, rr) 12252 12253 form.Set("mode", "0") 12254 form.Set("quota", "a") 12255 b, contentType, _ = getMultipartFormData(form, "", "") 12256 req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b) 12257 setJWTCookieForReq(req, token) 12258 req.Header.Set("Content-Type", contentType) 12259 rr = executeRequest(req) 12260 checkResponseCode(t, http.StatusOK, rr) 12261 12262 form.Set("quota", "0") 12263 b, contentType, _ = getMultipartFormData(form, "", "") 12264 req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b) 12265 setJWTCookieForReq(req, token) 12266 req.Header.Set("Content-Type", contentType) 12267 rr = executeRequest(req) 12268 checkResponseCode(t, http.StatusOK, rr) 12269 12270 req, _ = http.NewRequest(http.MethodPost, webRestorePath+"?a=%3", &b) 12271 setJWTCookieForReq(req, token) 12272 req.Header.Set("Content-Type", contentType) 12273 rr = executeRequest(req) 12274 checkResponseCode(t, http.StatusOK, rr) 12275 12276 backupFilePath := filepath.Join(os.TempDir(), "backup.json") 12277 err = createTestFile(backupFilePath, 0) 12278 assert.NoError(t, err) 12279 12280 b, contentType, _ = getMultipartFormData(form, "backup_file", backupFilePath) 12281 req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b) 12282 setJWTCookieForReq(req, token) 12283 req.Header.Set("Content-Type", contentType) 12284 rr = executeRequest(req) 12285 checkResponseCode(t, http.StatusOK, rr) 12286 12287 err = createTestFile(backupFilePath, 10) 12288 assert.NoError(t, err) 12289 12290 b, contentType, _ = getMultipartFormData(form, "backup_file", backupFilePath) 12291 req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b) 12292 setJWTCookieForReq(req, token) 12293 req.Header.Set("Content-Type", contentType) 12294 rr = executeRequest(req) 12295 checkResponseCode(t, http.StatusOK, rr) 12296 12297 user := getTestUser() 12298 user.ID = 1 12299 user.Username = "test_user_web_restore" 12300 admin := getTestAdmin() 12301 admin.ID = 1 12302 admin.Username = "test_admin_web_restore" 12303 12304 apiKey := dataprovider.APIKey{ 12305 Name: "key name", 12306 KeyID: util.GenerateUniqueID(), 12307 Key: fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()), 12308 Scope: dataprovider.APIKeyScopeAdmin, 12309 } 12310 backupData := dataprovider.BackupData{} 12311 backupData.Users = append(backupData.Users, user) 12312 backupData.Admins = append(backupData.Admins, admin) 12313 backupData.APIKeys = append(backupData.APIKeys, apiKey) 12314 backupContent, err := json.Marshal(backupData) 12315 assert.NoError(t, err) 12316 err = os.WriteFile(backupFilePath, backupContent, os.ModePerm) 12317 assert.NoError(t, err) 12318 12319 b, contentType, _ = getMultipartFormData(form, "backup_file", backupFilePath) 12320 req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b) 12321 setJWTCookieForReq(req, token) 12322 req.Header.Set("Content-Type", contentType) 12323 rr = executeRequest(req) 12324 checkResponseCode(t, http.StatusOK, rr) 12325 assert.Contains(t, rr.Body.String(), "Your backup was successfully restored") 12326 12327 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 12328 assert.NoError(t, err) 12329 _, err = httpdtest.RemoveUser(user, http.StatusOK) 12330 assert.NoError(t, err) 12331 12332 admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) 12333 assert.NoError(t, err) 12334 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 12335 assert.NoError(t, err) 12336 12337 _, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusOK) 12338 assert.NoError(t, err) 12339 _, err = httpdtest.RemoveAPIKey(apiKey, http.StatusOK) 12340 assert.NoError(t, err) 12341 12342 err = os.Remove(backupFilePath) 12343 assert.NoError(t, err) 12344} 12345 12346func TestWebUserAddMock(t *testing.T) { 12347 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12348 assert.NoError(t, err) 12349 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12350 assert.NoError(t, err) 12351 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 12352 assert.NoError(t, err) 12353 user := getTestUser() 12354 user.UploadBandwidth = 32 12355 user.DownloadBandwidth = 64 12356 user.UID = 1000 12357 user.AdditionalInfo = "info" 12358 user.Description = "user dsc" 12359 user.Email = "test@test.com" 12360 mappedDir := filepath.Join(os.TempDir(), "mapped") 12361 folderName := filepath.Base(mappedDir) 12362 f := vfs.BaseVirtualFolder{ 12363 Name: folderName, 12364 MappedPath: mappedDir, 12365 } 12366 folderAsJSON, err := json.Marshal(f) 12367 assert.NoError(t, err) 12368 req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON)) 12369 setBearerForReq(req, apiToken) 12370 rr := executeRequest(req) 12371 checkResponseCode(t, http.StatusCreated, rr) 12372 12373 form := make(url.Values) 12374 form.Set(csrfFormToken, csrfToken) 12375 form.Set("username", user.Username) 12376 form.Set("email", user.Email) 12377 form.Set("home_dir", user.HomeDir) 12378 form.Set("password", user.Password) 12379 form.Set("status", strconv.Itoa(user.Status)) 12380 form.Set("expiration_date", "") 12381 form.Set("permissions", "*") 12382 form.Set("sub_perm_path0", "/subdir") 12383 form.Set("sub_perm_permissions0", "list") 12384 form.Add("sub_perm_permissions0", "download") 12385 form.Set("vfolder_path", " /vdir") 12386 form.Set("vfolder_name", folderName) 12387 form.Set("vfolder_quota_size", "1024") 12388 form.Set("vfolder_quota_files", "2") 12389 form.Set("pattern_path0", "/dir2") 12390 form.Set("patterns0", "*.jpg,*.png") 12391 form.Set("pattern_type0", "allowed") 12392 form.Set("pattern_path1", "/dir1") 12393 form.Set("patterns1", "*.png") 12394 form.Set("pattern_type1", "allowed") 12395 form.Set("pattern_path2", "/dir1") 12396 form.Set("patterns2", "*.zip") 12397 form.Set("pattern_type2", "denied") 12398 form.Set("pattern_path3", "/dir3") 12399 form.Set("patterns3", "*.rar") 12400 form.Set("pattern_type3", "denied") 12401 form.Set("pattern_path4", "/dir2") 12402 form.Set("patterns4", "*.mkv") 12403 form.Set("pattern_type4", "denied") 12404 form.Set("additional_info", user.AdditionalInfo) 12405 form.Set("description", user.Description) 12406 form.Add("hooks", "external_auth_disabled") 12407 form.Set("disable_fs_checks", "checked") 12408 b, contentType, _ := getMultipartFormData(form, "", "") 12409 // test invalid url escape 12410 req, _ = http.NewRequest(http.MethodPost, webUserPath+"?a=%2", &b) 12411 setJWTCookieForReq(req, webToken) 12412 req.Header.Set("Content-Type", contentType) 12413 rr = executeRequest(req) 12414 checkResponseCode(t, http.StatusOK, rr) 12415 form.Set("public_keys", testPubKey) 12416 form.Add("public_keys", testPubKey1) 12417 form.Set("uid", strconv.FormatInt(int64(user.UID), 10)) 12418 form.Set("gid", "a") 12419 b, contentType, _ = getMultipartFormData(form, "", "") 12420 // test invalid gid 12421 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12422 setJWTCookieForReq(req, webToken) 12423 req.Header.Set("Content-Type", contentType) 12424 rr = executeRequest(req) 12425 checkResponseCode(t, http.StatusOK, rr) 12426 form.Set("gid", "0") 12427 form.Set("max_sessions", "a") 12428 b, contentType, _ = getMultipartFormData(form, "", "") 12429 // test invalid max sessions 12430 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12431 setJWTCookieForReq(req, webToken) 12432 req.Header.Set("Content-Type", contentType) 12433 rr = executeRequest(req) 12434 checkResponseCode(t, http.StatusOK, rr) 12435 form.Set("max_sessions", "0") 12436 form.Set("quota_size", "a") 12437 b, contentType, _ = getMultipartFormData(form, "", "") 12438 // test invalid quota size 12439 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12440 setJWTCookieForReq(req, webToken) 12441 req.Header.Set("Content-Type", contentType) 12442 rr = executeRequest(req) 12443 checkResponseCode(t, http.StatusOK, rr) 12444 form.Set("quota_size", "0") 12445 form.Set("quota_files", "a") 12446 b, contentType, _ = getMultipartFormData(form, "", "") 12447 // test invalid quota files 12448 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12449 setJWTCookieForReq(req, webToken) 12450 req.Header.Set("Content-Type", contentType) 12451 rr = executeRequest(req) 12452 checkResponseCode(t, http.StatusOK, rr) 12453 form.Set("quota_files", "0") 12454 form.Set("upload_bandwidth", "a") 12455 b, contentType, _ = getMultipartFormData(form, "", "") 12456 // test invalid upload bandwidth 12457 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12458 setJWTCookieForReq(req, webToken) 12459 req.Header.Set("Content-Type", contentType) 12460 rr = executeRequest(req) 12461 checkResponseCode(t, http.StatusOK, rr) 12462 form.Set("upload_bandwidth", strconv.FormatInt(user.UploadBandwidth, 10)) 12463 form.Set("download_bandwidth", "a") 12464 b, contentType, _ = getMultipartFormData(form, "", "") 12465 // test invalid download bandwidth 12466 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12467 setJWTCookieForReq(req, webToken) 12468 req.Header.Set("Content-Type", contentType) 12469 rr = executeRequest(req) 12470 checkResponseCode(t, http.StatusOK, rr) 12471 form.Set("download_bandwidth", strconv.FormatInt(user.DownloadBandwidth, 10)) 12472 form.Set("status", "a") 12473 b, contentType, _ = getMultipartFormData(form, "", "") 12474 // test invalid status 12475 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12476 setJWTCookieForReq(req, webToken) 12477 req.Header.Set("Content-Type", contentType) 12478 rr = executeRequest(req) 12479 checkResponseCode(t, http.StatusOK, rr) 12480 form.Set("status", strconv.Itoa(user.Status)) 12481 form.Set("expiration_date", "123") 12482 b, contentType, _ = getMultipartFormData(form, "", "") 12483 // test invalid expiration date 12484 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12485 setJWTCookieForReq(req, webToken) 12486 req.Header.Set("Content-Type", contentType) 12487 rr = executeRequest(req) 12488 checkResponseCode(t, http.StatusOK, rr) 12489 form.Set("expiration_date", "") 12490 form.Set("allowed_ip", "invalid,ip") 12491 b, contentType, _ = getMultipartFormData(form, "", "") 12492 // test invalid allowed_ip 12493 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12494 setJWTCookieForReq(req, webToken) 12495 req.Header.Set("Content-Type", contentType) 12496 rr = executeRequest(req) 12497 checkResponseCode(t, http.StatusOK, rr) 12498 form.Set("allowed_ip", "") 12499 form.Set("denied_ip", "192.168.1.2") // it should be 192.168.1.2/32 12500 b, contentType, _ = getMultipartFormData(form, "", "") 12501 // test invalid denied_ip 12502 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12503 setJWTCookieForReq(req, webToken) 12504 req.Header.Set("Content-Type", contentType) 12505 rr = executeRequest(req) 12506 checkResponseCode(t, http.StatusOK, rr) 12507 form.Set("denied_ip", "") 12508 // test invalid max file upload size 12509 form.Set("max_upload_file_size", "a") 12510 b, contentType, _ = getMultipartFormData(form, "", "") 12511 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12512 setJWTCookieForReq(req, webToken) 12513 req.Header.Set("Content-Type", contentType) 12514 rr = executeRequest(req) 12515 checkResponseCode(t, http.StatusOK, rr) 12516 form.Set("max_upload_file_size", "1000") 12517 // test invalid tls username 12518 form.Set("tls_username", "username") 12519 b, contentType, _ = getMultipartFormData(form, "", "") 12520 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12521 setJWTCookieForReq(req, webToken) 12522 req.Header.Set("Content-Type", contentType) 12523 rr = executeRequest(req) 12524 checkResponseCode(t, http.StatusOK, rr) 12525 assert.Contains(t, rr.Body.String(), "Validation error: invalid TLS username") 12526 form.Set("tls_username", string(sdk.TLSUsernameNone)) 12527 form.Set(csrfFormToken, "invalid form token") 12528 b, contentType, _ = getMultipartFormData(form, "", "") 12529 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12530 setJWTCookieForReq(req, webToken) 12531 req.Header.Set("Content-Type", contentType) 12532 rr = executeRequest(req) 12533 checkResponseCode(t, http.StatusForbidden, rr) 12534 assert.Contains(t, rr.Body.String(), "unable to verify form token") 12535 12536 form.Set(csrfFormToken, csrfToken) 12537 b, contentType, _ = getMultipartFormData(form, "", "") 12538 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12539 setJWTCookieForReq(req, webToken) 12540 req.Header.Set("Content-Type", contentType) 12541 rr = executeRequest(req) 12542 checkResponseCode(t, http.StatusSeeOther, rr) 12543 12544 dbUser, err := dataprovider.UserExists(user.Username) 12545 assert.NoError(t, err) 12546 assert.NotEmpty(t, dbUser.Password) 12547 assert.True(t, dbUser.IsPasswordHashed()) 12548 // the user already exists, was created with the above request 12549 b, contentType, _ = getMultipartFormData(form, "", "") 12550 req, _ = http.NewRequest(http.MethodPost, webUserPath, &b) 12551 setJWTCookieForReq(req, webToken) 12552 req.Header.Set("Content-Type", contentType) 12553 rr = executeRequest(req) 12554 checkResponseCode(t, http.StatusOK, rr) 12555 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 12556 setBearerForReq(req, apiToken) 12557 rr = executeRequest(req) 12558 checkResponseCode(t, http.StatusOK, rr) 12559 newUser := dataprovider.User{} 12560 err = render.DecodeJSON(rr.Body, &newUser) 12561 assert.NoError(t, err) 12562 assert.Equal(t, user.UID, newUser.UID) 12563 assert.Equal(t, user.UploadBandwidth, newUser.UploadBandwidth) 12564 assert.Equal(t, user.DownloadBandwidth, newUser.DownloadBandwidth) 12565 assert.Equal(t, int64(1000), newUser.Filters.MaxUploadFileSize) 12566 assert.Equal(t, user.AdditionalInfo, newUser.AdditionalInfo) 12567 assert.Equal(t, user.Description, newUser.Description) 12568 assert.True(t, newUser.Filters.Hooks.ExternalAuthDisabled) 12569 assert.False(t, newUser.Filters.Hooks.PreLoginDisabled) 12570 assert.False(t, newUser.Filters.Hooks.CheckPasswordDisabled) 12571 assert.True(t, newUser.Filters.DisableFsChecks) 12572 assert.False(t, newUser.Filters.AllowAPIKeyAuth) 12573 assert.Equal(t, user.Email, newUser.Email) 12574 assert.True(t, util.IsStringInSlice(testPubKey, newUser.PublicKeys)) 12575 if val, ok := newUser.Permissions["/subdir"]; ok { 12576 assert.True(t, util.IsStringInSlice(dataprovider.PermListItems, val)) 12577 assert.True(t, util.IsStringInSlice(dataprovider.PermDownload, val)) 12578 } else { 12579 assert.Fail(t, "user permissions must contain /somedir", "actual: %v", newUser.Permissions) 12580 } 12581 assert.Len(t, newUser.PublicKeys, 2) 12582 assert.Len(t, newUser.VirtualFolders, 1) 12583 for _, v := range newUser.VirtualFolders { 12584 assert.Equal(t, v.VirtualPath, "/vdir") 12585 assert.Equal(t, v.Name, folderName) 12586 assert.Equal(t, v.MappedPath, mappedDir) 12587 assert.Equal(t, v.QuotaFiles, 2) 12588 assert.Equal(t, v.QuotaSize, int64(1024)) 12589 } 12590 assert.Len(t, newUser.Filters.FilePatterns, 3) 12591 for _, filter := range newUser.Filters.FilePatterns { 12592 if filter.Path == "/dir1" { 12593 assert.Len(t, filter.DeniedPatterns, 1) 12594 assert.Len(t, filter.AllowedPatterns, 1) 12595 assert.True(t, util.IsStringInSlice("*.png", filter.AllowedPatterns)) 12596 assert.True(t, util.IsStringInSlice("*.zip", filter.DeniedPatterns)) 12597 } 12598 if filter.Path == "/dir2" { 12599 assert.Len(t, filter.DeniedPatterns, 1) 12600 assert.Len(t, filter.AllowedPatterns, 2) 12601 assert.True(t, util.IsStringInSlice("*.jpg", filter.AllowedPatterns)) 12602 assert.True(t, util.IsStringInSlice("*.png", filter.AllowedPatterns)) 12603 assert.True(t, util.IsStringInSlice("*.mkv", filter.DeniedPatterns)) 12604 } 12605 if filter.Path == "/dir3" { 12606 assert.Len(t, filter.DeniedPatterns, 1) 12607 assert.Len(t, filter.AllowedPatterns, 0) 12608 assert.True(t, util.IsStringInSlice("*.rar", filter.DeniedPatterns)) 12609 } 12610 } 12611 assert.Equal(t, sdk.TLSUsernameNone, newUser.Filters.TLSUsername) 12612 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, newUser.Username), nil) 12613 setBearerForReq(req, apiToken) 12614 rr = executeRequest(req) 12615 checkResponseCode(t, http.StatusOK, rr) 12616 req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil) 12617 setBearerForReq(req, apiToken) 12618 rr = executeRequest(req) 12619 checkResponseCode(t, http.StatusOK, rr) 12620} 12621 12622func TestWebUserUpdateMock(t *testing.T) { 12623 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12624 assert.NoError(t, err) 12625 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12626 assert.NoError(t, err) 12627 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 12628 assert.NoError(t, err) 12629 user := getTestUser() 12630 userAsJSON := getUserAsJSON(t, user) 12631 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 12632 setBearerForReq(req, apiToken) 12633 rr := executeRequest(req) 12634 checkResponseCode(t, http.StatusCreated, rr) 12635 // add TOTP config 12636 configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) 12637 assert.NoError(t, err) 12638 userToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) 12639 assert.NoError(t, err) 12640 userTOTPConfig := sdk.TOTPConfig{ 12641 Enabled: true, 12642 ConfigName: configName, 12643 Secret: kms.NewPlainSecret(secret), 12644 Protocols: []string{common.ProtocolSSH, common.ProtocolFTP}, 12645 } 12646 asJSON, err := json.Marshal(userTOTPConfig) 12647 assert.NoError(t, err) 12648 req, err = http.NewRequest(http.MethodPost, webClientTOTPSavePath, bytes.NewBuffer(asJSON)) 12649 assert.NoError(t, err) 12650 setJWTCookieForReq(req, userToken) 12651 rr = executeRequest(req) 12652 checkResponseCode(t, http.StatusForbidden, rr) 12653 assert.Contains(t, rr.Body.String(), "Invalid token") 12654 12655 req, err = http.NewRequest(http.MethodPost, webClientTOTPSavePath, bytes.NewBuffer(asJSON)) 12656 assert.NoError(t, err) 12657 setJWTCookieForReq(req, userToken) 12658 setCSRFHeaderForReq(req, csrfToken) 12659 rr = executeRequest(req) 12660 checkResponseCode(t, http.StatusOK, rr) 12661 12662 user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) 12663 assert.NoError(t, err) 12664 assert.True(t, user.Filters.TOTPConfig.Enabled) 12665 12666 dbUser, err := dataprovider.UserExists(user.Username) 12667 assert.NoError(t, err) 12668 assert.NotEmpty(t, dbUser.Password) 12669 assert.True(t, dbUser.IsPasswordHashed()) 12670 err = render.DecodeJSON(rr.Body, &user) 12671 assert.NoError(t, err) 12672 user.MaxSessions = 1 12673 user.QuotaFiles = 2 12674 user.QuotaSize = 3 12675 user.GID = 1000 12676 user.Filters.AllowAPIKeyAuth = true 12677 user.AdditionalInfo = "new additional info" 12678 user.Email = "user@example.com" 12679 form := make(url.Values) 12680 form.Set("username", user.Username) 12681 form.Set("email", user.Email) 12682 form.Set("password", "") 12683 form.Set("public_keys", testPubKey) 12684 form.Set("home_dir", user.HomeDir) 12685 form.Set("uid", "0") 12686 form.Set("gid", strconv.FormatInt(int64(user.GID), 10)) 12687 form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10)) 12688 form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10)) 12689 form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10)) 12690 form.Set("upload_bandwidth", "0") 12691 form.Set("download_bandwidth", "0") 12692 form.Set("permissions", "*") 12693 form.Set("sub_perm_path0", "/otherdir") 12694 form.Set("sub_perm_permissions0", "list") 12695 form.Add("sub_perm_permissions0", "upload") 12696 form.Set("status", strconv.Itoa(user.Status)) 12697 form.Set("expiration_date", "2020-01-01 00:00:00") 12698 form.Set("allowed_ip", " 192.168.1.3/32, 192.168.2.0/24 ") 12699 form.Set("denied_ip", " 10.0.0.2/32 ") 12700 form.Set("pattern_path0", "/dir1") 12701 form.Set("patterns0", "*.zip") 12702 form.Set("pattern_type0", "denied") 12703 form.Set("ssh_login_methods", dataprovider.SSHLoginMethodKeyboardInteractive) 12704 form.Set("denied_protocols", common.ProtocolFTP) 12705 form.Set("max_upload_file_size", "100") 12706 form.Set("disconnect", "1") 12707 form.Set("additional_info", user.AdditionalInfo) 12708 form.Set("description", user.Description) 12709 form.Set("tls_username", string(sdk.TLSUsernameCN)) 12710 form.Set("allow_api_key_auth", "1") 12711 b, contentType, _ := getMultipartFormData(form, "", "") 12712 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 12713 setJWTCookieForReq(req, webToken) 12714 req.Header.Set("Content-Type", contentType) 12715 rr = executeRequest(req) 12716 checkResponseCode(t, http.StatusForbidden, rr) 12717 assert.Contains(t, rr.Body.String(), "unable to verify form token") 12718 12719 form.Set(csrfFormToken, csrfToken) 12720 b, contentType, _ = getMultipartFormData(form, "", "") 12721 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 12722 setJWTCookieForReq(req, webToken) 12723 req.Header.Set("Content-Type", contentType) 12724 rr = executeRequest(req) 12725 checkResponseCode(t, http.StatusSeeOther, rr) 12726 dbUser, err = dataprovider.UserExists(user.Username) 12727 assert.NoError(t, err) 12728 assert.Empty(t, dbUser.Password) 12729 assert.False(t, dbUser.IsPasswordHashed()) 12730 12731 form.Set("password", defaultPassword) 12732 b, contentType, _ = getMultipartFormData(form, "", "") 12733 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 12734 setJWTCookieForReq(req, webToken) 12735 req.Header.Set("Content-Type", contentType) 12736 rr = executeRequest(req) 12737 checkResponseCode(t, http.StatusSeeOther, rr) 12738 dbUser, err = dataprovider.UserExists(user.Username) 12739 assert.NoError(t, err) 12740 assert.NotEmpty(t, dbUser.Password) 12741 assert.True(t, dbUser.IsPasswordHashed()) 12742 prevPwd := dbUser.Password 12743 12744 form.Set("password", redactedSecret) 12745 b, contentType, _ = getMultipartFormData(form, "", "") 12746 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 12747 setJWTCookieForReq(req, webToken) 12748 req.Header.Set("Content-Type", contentType) 12749 rr = executeRequest(req) 12750 checkResponseCode(t, http.StatusSeeOther, rr) 12751 dbUser, err = dataprovider.UserExists(user.Username) 12752 assert.NoError(t, err) 12753 assert.NotEmpty(t, dbUser.Password) 12754 assert.True(t, dbUser.IsPasswordHashed()) 12755 assert.Equal(t, prevPwd, dbUser.Password) 12756 assert.True(t, dbUser.Filters.TOTPConfig.Enabled) 12757 12758 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 12759 setBearerForReq(req, apiToken) 12760 rr = executeRequest(req) 12761 checkResponseCode(t, http.StatusOK, rr) 12762 var updateUser dataprovider.User 12763 err = render.DecodeJSON(rr.Body, &updateUser) 12764 assert.NoError(t, err) 12765 assert.Equal(t, user.Email, updateUser.Email) 12766 assert.Equal(t, user.HomeDir, updateUser.HomeDir) 12767 assert.Equal(t, user.MaxSessions, updateUser.MaxSessions) 12768 assert.Equal(t, user.QuotaFiles, updateUser.QuotaFiles) 12769 assert.Equal(t, user.QuotaSize, updateUser.QuotaSize) 12770 assert.Equal(t, user.UID, updateUser.UID) 12771 assert.Equal(t, user.GID, updateUser.GID) 12772 assert.Equal(t, user.AdditionalInfo, updateUser.AdditionalInfo) 12773 assert.Equal(t, user.Description, updateUser.Description) 12774 assert.Equal(t, int64(100), updateUser.Filters.MaxUploadFileSize) 12775 assert.Equal(t, sdk.TLSUsernameCN, updateUser.Filters.TLSUsername) 12776 assert.True(t, updateUser.Filters.AllowAPIKeyAuth) 12777 assert.True(t, updateUser.Filters.TOTPConfig.Enabled) 12778 12779 if val, ok := updateUser.Permissions["/otherdir"]; ok { 12780 assert.True(t, util.IsStringInSlice(dataprovider.PermListItems, val)) 12781 assert.True(t, util.IsStringInSlice(dataprovider.PermUpload, val)) 12782 } else { 12783 assert.Fail(t, "user permissions must contains /otherdir", "actual: %v", updateUser.Permissions) 12784 } 12785 assert.True(t, util.IsStringInSlice("192.168.1.3/32", updateUser.Filters.AllowedIP)) 12786 assert.True(t, util.IsStringInSlice("10.0.0.2/32", updateUser.Filters.DeniedIP)) 12787 assert.True(t, util.IsStringInSlice(dataprovider.SSHLoginMethodKeyboardInteractive, updateUser.Filters.DeniedLoginMethods)) 12788 assert.True(t, util.IsStringInSlice(common.ProtocolFTP, updateUser.Filters.DeniedProtocols)) 12789 assert.True(t, util.IsStringInSlice("*.zip", updateUser.Filters.FilePatterns[0].DeniedPatterns)) 12790 req, err = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 12791 assert.NoError(t, err) 12792 setBearerForReq(req, apiToken) 12793 rr = executeRequest(req) 12794 checkResponseCode(t, http.StatusOK, rr) 12795} 12796 12797func TestRenderFolderTemplateMock(t *testing.T) { 12798 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12799 assert.NoError(t, err) 12800 req, err := http.NewRequest(http.MethodGet, webTemplateFolder, nil) 12801 assert.NoError(t, err) 12802 setJWTCookieForReq(req, token) 12803 rr := executeRequest(req) 12804 checkResponseCode(t, http.StatusOK, rr) 12805 12806 folder := vfs.BaseVirtualFolder{ 12807 Name: "templatefolder", 12808 MappedPath: filepath.Join(os.TempDir(), "mapped"), 12809 Description: "template folder desc", 12810 } 12811 folder, _, err = httpdtest.AddFolder(folder, http.StatusCreated) 12812 assert.NoError(t, err) 12813 12814 req, err = http.NewRequest(http.MethodGet, webTemplateFolder+fmt.Sprintf("?from=%v", folder.Name), nil) 12815 assert.NoError(t, err) 12816 setJWTCookieForReq(req, token) 12817 rr = executeRequest(req) 12818 checkResponseCode(t, http.StatusOK, rr) 12819 12820 req, err = http.NewRequest(http.MethodGet, webTemplateFolder+"?from=unknown-folder", nil) 12821 assert.NoError(t, err) 12822 setJWTCookieForReq(req, token) 12823 rr = executeRequest(req) 12824 checkResponseCode(t, http.StatusNotFound, rr) 12825 12826 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 12827 assert.NoError(t, err) 12828} 12829 12830func TestRenderUserTemplateMock(t *testing.T) { 12831 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12832 assert.NoError(t, err) 12833 req, err := http.NewRequest(http.MethodGet, webTemplateUser, nil) 12834 assert.NoError(t, err) 12835 setJWTCookieForReq(req, token) 12836 rr := executeRequest(req) 12837 checkResponseCode(t, http.StatusOK, rr) 12838 12839 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 12840 assert.NoError(t, err) 12841 12842 req, err = http.NewRequest(http.MethodGet, webTemplateUser+fmt.Sprintf("?from=%v", user.Username), nil) 12843 assert.NoError(t, err) 12844 setJWTCookieForReq(req, token) 12845 rr = executeRequest(req) 12846 checkResponseCode(t, http.StatusOK, rr) 12847 12848 req, err = http.NewRequest(http.MethodGet, webTemplateUser+"?from=unknown", nil) 12849 assert.NoError(t, err) 12850 setJWTCookieForReq(req, token) 12851 rr = executeRequest(req) 12852 checkResponseCode(t, http.StatusNotFound, rr) 12853 12854 _, err = httpdtest.RemoveUser(user, http.StatusOK) 12855 assert.NoError(t, err) 12856} 12857 12858func TestRenderWebCloneUserMock(t *testing.T) { 12859 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12860 assert.NoError(t, err) 12861 user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) 12862 assert.NoError(t, err) 12863 12864 req, err := http.NewRequest(http.MethodGet, webUserPath+fmt.Sprintf("?clone-from=%v", user.Username), nil) 12865 assert.NoError(t, err) 12866 setJWTCookieForReq(req, token) 12867 rr := executeRequest(req) 12868 checkResponseCode(t, http.StatusOK, rr) 12869 12870 req, err = http.NewRequest(http.MethodGet, webUserPath+fmt.Sprintf("?clone-from=%v", altAdminPassword), nil) 12871 assert.NoError(t, err) 12872 setJWTCookieForReq(req, token) 12873 rr = executeRequest(req) 12874 checkResponseCode(t, http.StatusNotFound, rr) 12875 12876 _, err = httpdtest.RemoveUser(user, http.StatusOK) 12877 assert.NoError(t, err) 12878} 12879 12880func TestUserTemplateWithFoldersMock(t *testing.T) { 12881 folder := vfs.BaseVirtualFolder{ 12882 Name: "vfolder", 12883 MappedPath: filepath.Join(os.TempDir(), "mapped"), 12884 Description: "vfolder desc with spéciàl ch@rs", 12885 } 12886 12887 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12888 assert.NoError(t, err) 12889 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 12890 assert.NoError(t, err) 12891 user := getTestUser() 12892 form := make(url.Values) 12893 form.Set("username", user.Username) 12894 form.Set("home_dir", filepath.Join(os.TempDir(), "%username%")) 12895 form.Set("uid", strconv.FormatInt(int64(user.UID), 10)) 12896 form.Set("gid", strconv.FormatInt(int64(user.GID), 10)) 12897 form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10)) 12898 form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10)) 12899 form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10)) 12900 form.Set("upload_bandwidth", "0") 12901 form.Set("download_bandwidth", "0") 12902 form.Set("permissions", "*") 12903 form.Set("status", strconv.Itoa(user.Status)) 12904 form.Set("expiration_date", "2020-01-01 00:00:00") 12905 form.Set("fs_provider", "0") 12906 form.Set("max_upload_file_size", "0") 12907 form.Set("description", "desc %username% %password%") 12908 form.Set("vfolder_path", "/vdir%username%") 12909 form.Set("vfolder_name", folder.Name) 12910 form.Set("vfolder_quota_size", "-1") 12911 form.Set("vfolder_quota_files", "-1") 12912 form.Add("tpl_username", "auser1") 12913 form.Add("tpl_password", "password1") 12914 form.Add("tpl_public_keys", " ") 12915 form.Add("tpl_username", "auser2") 12916 form.Add("tpl_password", "password2") 12917 form.Add("tpl_public_keys", testPubKey) 12918 form.Add("tpl_username", "auser1") 12919 form.Add("tpl_password", "password") 12920 form.Add("tpl_public_keys", "") 12921 b, contentType, _ := getMultipartFormData(form, "", "") 12922 req, _ := http.NewRequest(http.MethodPost, path.Join(webTemplateUser), &b) 12923 setJWTCookieForReq(req, token) 12924 req.Header.Set("Content-Type", contentType) 12925 rr := executeRequest(req) 12926 checkResponseCode(t, http.StatusForbidden, rr) 12927 require.Contains(t, rr.Body.String(), "unable to verify form token") 12928 12929 form.Set(csrfFormToken, csrfToken) 12930 b, contentType, _ = getMultipartFormData(form, "", "") 12931 req, _ = http.NewRequest(http.MethodPost, path.Join(webTemplateUser), &b) 12932 setJWTCookieForReq(req, token) 12933 req.Header.Set("Content-Type", contentType) 12934 rr = executeRequest(req) 12935 checkResponseCode(t, http.StatusBadRequest, rr) 12936 require.Contains(t, rr.Body.String(), "invalid folder mapped path") 12937 12938 folder, resp, err := httpdtest.AddFolder(folder, http.StatusCreated) 12939 assert.NoError(t, err, string(resp)) 12940 12941 b, contentType, _ = getMultipartFormData(form, "", "") 12942 req, _ = http.NewRequest(http.MethodPost, path.Join(webTemplateUser), &b) 12943 setJWTCookieForReq(req, token) 12944 req.Header.Set("Content-Type", contentType) 12945 rr = executeRequest(req) 12946 checkResponseCode(t, http.StatusOK, rr) 12947 12948 var dump dataprovider.BackupData 12949 err = json.Unmarshal(rr.Body.Bytes(), &dump) 12950 assert.NoError(t, err) 12951 assert.Len(t, dump.Users, 2) 12952 assert.Len(t, dump.Folders, 1) 12953 user1 := dump.Users[0] 12954 user2 := dump.Users[1] 12955 folder1 := dump.Folders[0] 12956 assert.Equal(t, "auser1", user1.Username) 12957 assert.Equal(t, "auser2", user2.Username) 12958 assert.Equal(t, "desc auser1 password1", user1.Description) 12959 assert.Equal(t, "desc auser2 password2", user2.Description) 12960 assert.Equal(t, filepath.Join(os.TempDir(), user1.Username), user1.HomeDir) 12961 assert.Equal(t, filepath.Join(os.TempDir(), user2.Username), user2.HomeDir) 12962 assert.Equal(t, folder.Name, folder1.Name) 12963 assert.Equal(t, folder.MappedPath, folder1.MappedPath) 12964 assert.Equal(t, folder.Description, folder1.Description) 12965 assert.Len(t, user1.PublicKeys, 0) 12966 assert.Len(t, user2.PublicKeys, 1) 12967 assert.Len(t, user1.VirtualFolders, 1) 12968 assert.Len(t, user2.VirtualFolders, 1) 12969 assert.Equal(t, "/vdirauser1", user1.VirtualFolders[0].VirtualPath) 12970 assert.Equal(t, "/vdirauser2", user2.VirtualFolders[0].VirtualPath) 12971 12972 _, err = httpdtest.RemoveFolder(folder, http.StatusOK) 12973 assert.NoError(t, err) 12974} 12975 12976func TestUserTemplateMock(t *testing.T) { 12977 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 12978 assert.NoError(t, err) 12979 user := getTestUser() 12980 user.FsConfig.Provider = sdk.S3FilesystemProvider 12981 user.FsConfig.S3Config.Bucket = "test" 12982 user.FsConfig.S3Config.Region = "eu-central-1" 12983 user.FsConfig.S3Config.AccessKey = "%username%" 12984 user.FsConfig.S3Config.KeyPrefix = "somedir/subdir/" 12985 user.FsConfig.S3Config.UploadPartSize = 5 12986 user.FsConfig.S3Config.UploadConcurrency = 4 12987 user.FsConfig.S3Config.DownloadPartSize = 6 12988 user.FsConfig.S3Config.DownloadConcurrency = 3 12989 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 12990 assert.NoError(t, err) 12991 form := make(url.Values) 12992 form.Set(csrfFormToken, csrfToken) 12993 form.Set("username", user.Username) 12994 form.Set("home_dir", filepath.Join(os.TempDir(), "%username%")) 12995 form.Set("uid", "0") 12996 form.Set("gid", strconv.FormatInt(int64(user.GID), 10)) 12997 form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10)) 12998 form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10)) 12999 form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10)) 13000 form.Set("upload_bandwidth", "0") 13001 form.Set("download_bandwidth", "0") 13002 form.Set("permissions", "*") 13003 form.Set("status", strconv.Itoa(user.Status)) 13004 form.Set("expiration_date", "2020-01-01 00:00:00") 13005 form.Set("allowed_ip", "") 13006 form.Set("denied_ip", "") 13007 form.Set("fs_provider", "1") 13008 form.Set("s3_bucket", user.FsConfig.S3Config.Bucket) 13009 form.Set("s3_region", user.FsConfig.S3Config.Region) 13010 form.Set("s3_access_key", "%username%") 13011 form.Set("s3_access_secret", "%password%") 13012 form.Set("s3_key_prefix", "base/%username%") 13013 form.Set("allowed_extensions", "/dir1::.jpg,.png") 13014 form.Set("denied_extensions", "/dir2::.zip") 13015 form.Set("max_upload_file_size", "0") 13016 form.Add("hooks", "external_auth_disabled") 13017 form.Add("hooks", "check_password_disabled") 13018 form.Set("disable_fs_checks", "checked") 13019 form.Set("s3_download_part_max_time", "0") 13020 // test invalid s3_upload_part_size 13021 form.Set("s3_upload_part_size", "a") 13022 b, contentType, _ := getMultipartFormData(form, "", "") 13023 req, _ := http.NewRequest(http.MethodPost, webTemplateUser, &b) 13024 setJWTCookieForReq(req, token) 13025 req.Header.Set("Content-Type", contentType) 13026 rr := executeRequest(req) 13027 checkResponseCode(t, http.StatusBadRequest, rr) 13028 form.Set("s3_upload_part_size", strconv.FormatInt(user.FsConfig.S3Config.UploadPartSize, 10)) 13029 form.Set("s3_upload_concurrency", strconv.Itoa(user.FsConfig.S3Config.UploadConcurrency)) 13030 form.Set("s3_download_part_size", strconv.FormatInt(user.FsConfig.S3Config.DownloadPartSize, 10)) 13031 form.Set("s3_download_concurrency", strconv.Itoa(user.FsConfig.S3Config.DownloadConcurrency)) 13032 13033 b, contentType, _ = getMultipartFormData(form, "", "") 13034 req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) 13035 setJWTCookieForReq(req, token) 13036 req.Header.Set("Content-Type", contentType) 13037 rr = executeRequest(req) 13038 checkResponseCode(t, http.StatusBadRequest, rr) 13039 13040 form.Set("tpl_username", "user1") 13041 form.Set("tpl_password", "password1") 13042 form.Set("tpl_public_keys", "invalid-pkey") 13043 b, contentType, _ = getMultipartFormData(form, "", "") 13044 req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) 13045 setJWTCookieForReq(req, token) 13046 req.Header.Set("Content-Type", contentType) 13047 rr = executeRequest(req) 13048 checkResponseCode(t, http.StatusBadRequest, rr) 13049 require.Contains(t, rr.Body.String(), "Error validating user") 13050 13051 form.Set("tpl_username", "user1") 13052 form.Set("tpl_password", " ") 13053 form.Set("tpl_public_keys", "") 13054 b, contentType, _ = getMultipartFormData(form, "", "") 13055 req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) 13056 setJWTCookieForReq(req, token) 13057 req.Header.Set("Content-Type", contentType) 13058 rr = executeRequest(req) 13059 checkResponseCode(t, http.StatusBadRequest, rr) 13060 require.Contains(t, rr.Body.String(), "No valid users found, export is not possible") 13061 13062 form.Set("tpl_username", "user1") 13063 form.Set("tpl_password", "password1") 13064 form.Set("tpl_public_keys", " ") 13065 form.Add("tpl_username", "user2") 13066 form.Add("tpl_password", "password2") 13067 form.Add("tpl_public_keys", testPubKey) 13068 form.Add("tpl_username", "user3") 13069 form.Add("tpl_password", "") 13070 form.Add("tpl_public_keys", "") 13071 b, contentType, _ = getMultipartFormData(form, "", "") 13072 req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) 13073 setJWTCookieForReq(req, token) 13074 req.Header.Set("Content-Type", contentType) 13075 rr = executeRequest(req) 13076 checkResponseCode(t, http.StatusOK, rr) 13077 13078 var dump dataprovider.BackupData 13079 err = json.Unmarshal(rr.Body.Bytes(), &dump) 13080 require.NoError(t, err) 13081 require.Len(t, dump.Users, 2) 13082 require.Len(t, dump.Admins, 0) 13083 require.Len(t, dump.Folders, 0) 13084 user1 := dump.Users[0] 13085 user2 := dump.Users[1] 13086 require.Equal(t, "user1", user1.Username) 13087 require.Equal(t, sdk.S3FilesystemProvider, user1.FsConfig.Provider) 13088 require.Equal(t, "user2", user2.Username) 13089 require.Equal(t, sdk.S3FilesystemProvider, user2.FsConfig.Provider) 13090 require.Len(t, user2.PublicKeys, 1) 13091 require.Equal(t, filepath.Join(os.TempDir(), user1.Username), user1.HomeDir) 13092 require.Equal(t, filepath.Join(os.TempDir(), user2.Username), user2.HomeDir) 13093 require.Equal(t, user1.Username, user1.FsConfig.S3Config.AccessKey) 13094 require.Equal(t, user2.Username, user2.FsConfig.S3Config.AccessKey) 13095 require.Equal(t, path.Join("base", user1.Username)+"/", user1.FsConfig.S3Config.KeyPrefix) 13096 require.Equal(t, path.Join("base", user2.Username)+"/", user2.FsConfig.S3Config.KeyPrefix) 13097 require.True(t, user1.FsConfig.S3Config.AccessSecret.IsEncrypted()) 13098 err = user1.FsConfig.S3Config.AccessSecret.Decrypt() 13099 require.NoError(t, err) 13100 require.Equal(t, "password1", user1.FsConfig.S3Config.AccessSecret.GetPayload()) 13101 require.True(t, user2.FsConfig.S3Config.AccessSecret.IsEncrypted()) 13102 err = user2.FsConfig.S3Config.AccessSecret.Decrypt() 13103 require.NoError(t, err) 13104 require.Equal(t, "password2", user2.FsConfig.S3Config.AccessSecret.GetPayload()) 13105 require.True(t, user1.Filters.Hooks.ExternalAuthDisabled) 13106 require.True(t, user1.Filters.Hooks.CheckPasswordDisabled) 13107 require.False(t, user1.Filters.Hooks.PreLoginDisabled) 13108 require.True(t, user2.Filters.Hooks.ExternalAuthDisabled) 13109 require.True(t, user2.Filters.Hooks.CheckPasswordDisabled) 13110 require.False(t, user2.Filters.Hooks.PreLoginDisabled) 13111 require.True(t, user1.Filters.DisableFsChecks) 13112 require.True(t, user2.Filters.DisableFsChecks) 13113} 13114 13115func TestFolderTemplateMock(t *testing.T) { 13116 folderName := "vfolder-template" 13117 mappedPath := filepath.Join(os.TempDir(), "%name%mapped%name%path") 13118 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13119 assert.NoError(t, err) 13120 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 13121 assert.NoError(t, err) 13122 form := make(url.Values) 13123 form.Set("name", folderName) 13124 form.Set("mapped_path", mappedPath) 13125 form.Set("description", "desc folder %name%") 13126 form.Add("tpl_foldername", "folder1") 13127 form.Add("tpl_foldername", "folder2") 13128 form.Add("tpl_foldername", "folder3") 13129 form.Add("tpl_foldername", "folder1 ") 13130 form.Add("tpl_foldername", " ") 13131 b, contentType, _ := getMultipartFormData(form, "", "") 13132 req, _ := http.NewRequest(http.MethodPost, webTemplateFolder, &b) 13133 setJWTCookieForReq(req, token) 13134 req.Header.Set("Content-Type", contentType) 13135 rr := executeRequest(req) 13136 checkResponseCode(t, http.StatusForbidden, rr) 13137 assert.Contains(t, rr.Body.String(), "unable to verify form token") 13138 13139 form.Set(csrfFormToken, csrfToken) 13140 b, contentType, _ = getMultipartFormData(form, "", "") 13141 req, _ = http.NewRequest(http.MethodPost, webTemplateFolder+"?param=p%C3%AO%GG", &b) 13142 setJWTCookieForReq(req, token) 13143 req.Header.Set("Content-Type", contentType) 13144 rr = executeRequest(req) 13145 checkResponseCode(t, http.StatusBadRequest, rr) 13146 assert.Contains(t, rr.Body.String(), "Error parsing folders fields") 13147 13148 folder1 := "folder1" 13149 folder2 := "folder2" 13150 folder3 := "folder3" 13151 b, contentType, _ = getMultipartFormData(form, "", "") 13152 req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b) 13153 setJWTCookieForReq(req, token) 13154 req.Header.Set("Content-Type", contentType) 13155 rr = executeRequest(req) 13156 checkResponseCode(t, http.StatusOK, rr) 13157 13158 var dump dataprovider.BackupData 13159 err = json.Unmarshal(rr.Body.Bytes(), &dump) 13160 require.NoError(t, err) 13161 require.Len(t, dump.Users, 0) 13162 require.Len(t, dump.Admins, 0) 13163 require.Len(t, dump.Folders, 3) 13164 require.Equal(t, folder1, dump.Folders[0].Name) 13165 require.Equal(t, "desc folder folder1", dump.Folders[0].Description) 13166 require.True(t, strings.HasSuffix(dump.Folders[0].MappedPath, "folder1mappedfolder1path")) 13167 require.Equal(t, folder2, dump.Folders[1].Name) 13168 require.Equal(t, "desc folder folder2", dump.Folders[1].Description) 13169 require.True(t, strings.HasSuffix(dump.Folders[1].MappedPath, "folder2mappedfolder2path")) 13170 require.Equal(t, folder3, dump.Folders[2].Name) 13171 require.Equal(t, "desc folder folder3", dump.Folders[2].Description) 13172 require.True(t, strings.HasSuffix(dump.Folders[2].MappedPath, "folder3mappedfolder3path")) 13173 13174 form.Set("fs_provider", "1") 13175 form.Set("s3_bucket", "bucket") 13176 form.Set("s3_region", "us-east-1") 13177 form.Set("s3_access_key", "%name%") 13178 form.Set("s3_access_secret", "pwd%name%") 13179 form.Set("s3_key_prefix", "base/%name%") 13180 13181 b, contentType, _ = getMultipartFormData(form, "", "") 13182 req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b) 13183 setJWTCookieForReq(req, token) 13184 req.Header.Set("Content-Type", contentType) 13185 rr = executeRequest(req) 13186 checkResponseCode(t, http.StatusBadRequest, rr) 13187 assert.Contains(t, rr.Body.String(), "Error parsing folders fields") 13188 13189 form.Set("s3_upload_part_size", "5") 13190 form.Set("s3_upload_concurrency", "4") 13191 form.Set("s3_download_part_max_time", "0") 13192 form.Set("s3_download_part_size", "6") 13193 form.Set("s3_download_concurrency", "2") 13194 b, contentType, _ = getMultipartFormData(form, "", "") 13195 req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b) 13196 setJWTCookieForReq(req, token) 13197 req.Header.Set("Content-Type", contentType) 13198 rr = executeRequest(req) 13199 checkResponseCode(t, http.StatusOK, rr) 13200 13201 dump = dataprovider.BackupData{} 13202 err = json.Unmarshal(rr.Body.Bytes(), &dump) 13203 require.NoError(t, err) 13204 require.Len(t, dump.Users, 0) 13205 require.Len(t, dump.Admins, 0) 13206 require.Len(t, dump.Folders, 3) 13207 require.Equal(t, folder1, dump.Folders[0].Name) 13208 require.Equal(t, folder1, dump.Folders[0].FsConfig.S3Config.AccessKey) 13209 err = dump.Folders[0].FsConfig.S3Config.AccessSecret.Decrypt() 13210 require.NoError(t, err) 13211 require.Equal(t, "pwd"+folder1, dump.Folders[0].FsConfig.S3Config.AccessSecret.GetPayload()) 13212 require.Equal(t, "base/"+folder1+"/", dump.Folders[0].FsConfig.S3Config.KeyPrefix) 13213 require.Equal(t, folder2, dump.Folders[1].Name) 13214 require.Equal(t, folder2, dump.Folders[1].FsConfig.S3Config.AccessKey) 13215 err = dump.Folders[1].FsConfig.S3Config.AccessSecret.Decrypt() 13216 require.NoError(t, err) 13217 require.Equal(t, "pwd"+folder2, dump.Folders[1].FsConfig.S3Config.AccessSecret.GetPayload()) 13218 require.Equal(t, "base/"+folder2+"/", dump.Folders[1].FsConfig.S3Config.KeyPrefix) 13219 require.Equal(t, folder3, dump.Folders[2].Name) 13220 require.Equal(t, folder3, dump.Folders[2].FsConfig.S3Config.AccessKey) 13221 err = dump.Folders[2].FsConfig.S3Config.AccessSecret.Decrypt() 13222 require.NoError(t, err) 13223 require.Equal(t, "pwd"+folder3, dump.Folders[2].FsConfig.S3Config.AccessSecret.GetPayload()) 13224 require.Equal(t, "base/"+folder3+"/", dump.Folders[2].FsConfig.S3Config.KeyPrefix) 13225 13226 form.Set("tpl_foldername", " ") 13227 b, contentType, _ = getMultipartFormData(form, "", "") 13228 req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b) 13229 setJWTCookieForReq(req, token) 13230 req.Header.Set("Content-Type", contentType) 13231 rr = executeRequest(req) 13232 checkResponseCode(t, http.StatusBadRequest, rr) 13233 assert.Contains(t, rr.Body.String(), "No folders to export") 13234 13235 form.Set("tpl_foldername", "name") 13236 form.Set("mapped_path", "relative-path") 13237 b, contentType, _ = getMultipartFormData(form, "", "") 13238 req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b) 13239 setJWTCookieForReq(req, token) 13240 req.Header.Set("Content-Type", contentType) 13241 rr = executeRequest(req) 13242 checkResponseCode(t, http.StatusBadRequest, rr) 13243 assert.Contains(t, rr.Body.String(), "Error validating folder") 13244} 13245 13246func TestWebUserS3Mock(t *testing.T) { 13247 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13248 assert.NoError(t, err) 13249 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13250 assert.NoError(t, err) 13251 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 13252 assert.NoError(t, err) 13253 user := getTestUser() 13254 userAsJSON := getUserAsJSON(t, user) 13255 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 13256 setBearerForReq(req, apiToken) 13257 rr := executeRequest(req) 13258 checkResponseCode(t, http.StatusCreated, rr) 13259 err = render.DecodeJSON(rr.Body, &user) 13260 assert.NoError(t, err) 13261 user.FsConfig.Provider = sdk.S3FilesystemProvider 13262 user.FsConfig.S3Config.Bucket = "test" 13263 user.FsConfig.S3Config.Region = "eu-west-1" 13264 user.FsConfig.S3Config.AccessKey = "access-key" 13265 user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("access-secret") 13266 user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b" 13267 user.FsConfig.S3Config.StorageClass = "Standard" 13268 user.FsConfig.S3Config.KeyPrefix = "somedir/subdir/" 13269 user.FsConfig.S3Config.UploadPartSize = 5 13270 user.FsConfig.S3Config.UploadConcurrency = 4 13271 user.FsConfig.S3Config.DownloadPartMaxTime = 60 13272 user.FsConfig.S3Config.DownloadPartSize = 6 13273 user.FsConfig.S3Config.DownloadConcurrency = 3 13274 user.FsConfig.S3Config.ForcePathStyle = true 13275 user.FsConfig.S3Config.ACL = "public-read" 13276 user.Description = "s3 tèst user" 13277 form := make(url.Values) 13278 form.Set(csrfFormToken, csrfToken) 13279 form.Set("username", user.Username) 13280 form.Set("password", redactedSecret) 13281 form.Set("home_dir", user.HomeDir) 13282 form.Set("uid", "0") 13283 form.Set("gid", strconv.FormatInt(int64(user.GID), 10)) 13284 form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10)) 13285 form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10)) 13286 form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10)) 13287 form.Set("upload_bandwidth", "0") 13288 form.Set("download_bandwidth", "0") 13289 form.Set("permissions", "*") 13290 form.Set("status", strconv.Itoa(user.Status)) 13291 form.Set("expiration_date", "2020-01-01 00:00:00") 13292 form.Set("allowed_ip", "") 13293 form.Set("denied_ip", "") 13294 form.Set("fs_provider", "1") 13295 form.Set("s3_bucket", user.FsConfig.S3Config.Bucket) 13296 form.Set("s3_region", user.FsConfig.S3Config.Region) 13297 form.Set("s3_access_key", user.FsConfig.S3Config.AccessKey) 13298 form.Set("s3_access_secret", user.FsConfig.S3Config.AccessSecret.GetPayload()) 13299 form.Set("s3_storage_class", user.FsConfig.S3Config.StorageClass) 13300 form.Set("s3_acl", user.FsConfig.S3Config.ACL) 13301 form.Set("s3_endpoint", user.FsConfig.S3Config.Endpoint) 13302 form.Set("s3_key_prefix", user.FsConfig.S3Config.KeyPrefix) 13303 form.Set("pattern_path0", "/dir1") 13304 form.Set("patterns0", "*.jpg,*.png") 13305 form.Set("pattern_type0", "allowed") 13306 form.Set("pattern_path1", "/dir2") 13307 form.Set("patterns1", "*.zip") 13308 form.Set("pattern_type1", "denied") 13309 form.Set("max_upload_file_size", "0") 13310 form.Set("s3_force_path_style", "checked") 13311 form.Set("description", user.Description) 13312 form.Add("hooks", "pre_login_disabled") 13313 form.Add("allow_api_key_auth", "1") 13314 // test invalid s3_upload_part_size 13315 form.Set("s3_upload_part_size", "a") 13316 b, contentType, _ := getMultipartFormData(form, "", "") 13317 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13318 setJWTCookieForReq(req, webToken) 13319 req.Header.Set("Content-Type", contentType) 13320 rr = executeRequest(req) 13321 checkResponseCode(t, http.StatusOK, rr) 13322 // test invalid s3_upload_concurrency 13323 form.Set("s3_upload_part_size", strconv.FormatInt(user.FsConfig.S3Config.UploadPartSize, 10)) 13324 form.Set("s3_upload_concurrency", "a") 13325 b, contentType, _ = getMultipartFormData(form, "", "") 13326 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13327 setJWTCookieForReq(req, webToken) 13328 req.Header.Set("Content-Type", contentType) 13329 rr = executeRequest(req) 13330 checkResponseCode(t, http.StatusOK, rr) 13331 // test invalid s3_download_part_size 13332 form.Set("s3_upload_concurrency", strconv.Itoa(user.FsConfig.S3Config.UploadConcurrency)) 13333 form.Set("s3_download_part_size", "a") 13334 b, contentType, _ = getMultipartFormData(form, "", "") 13335 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13336 setJWTCookieForReq(req, webToken) 13337 req.Header.Set("Content-Type", contentType) 13338 rr = executeRequest(req) 13339 checkResponseCode(t, http.StatusOK, rr) 13340 // test invalid s3_download_concurrency 13341 form.Set("s3_download_part_size", strconv.FormatInt(user.FsConfig.S3Config.DownloadPartSize, 10)) 13342 form.Set("s3_download_concurrency", "a") 13343 b, contentType, _ = getMultipartFormData(form, "", "") 13344 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13345 setJWTCookieForReq(req, webToken) 13346 req.Header.Set("Content-Type", contentType) 13347 rr = executeRequest(req) 13348 checkResponseCode(t, http.StatusOK, rr) 13349 // test invalid s3_download_part_max_time 13350 form.Set("s3_download_concurrency", strconv.Itoa(user.FsConfig.S3Config.DownloadConcurrency)) 13351 form.Set("s3_download_part_max_time", "a") 13352 b, contentType, _ = getMultipartFormData(form, "", "") 13353 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13354 setJWTCookieForReq(req, webToken) 13355 req.Header.Set("Content-Type", contentType) 13356 rr = executeRequest(req) 13357 checkResponseCode(t, http.StatusOK, rr) 13358 // now add the user 13359 form.Set("s3_download_part_max_time", strconv.Itoa(user.FsConfig.S3Config.DownloadPartMaxTime)) 13360 b, contentType, _ = getMultipartFormData(form, "", "") 13361 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13362 setJWTCookieForReq(req, webToken) 13363 req.Header.Set("Content-Type", contentType) 13364 rr = executeRequest(req) 13365 checkResponseCode(t, http.StatusSeeOther, rr) 13366 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13367 setBearerForReq(req, apiToken) 13368 rr = executeRequest(req) 13369 checkResponseCode(t, http.StatusOK, rr) 13370 var updateUser dataprovider.User 13371 err = render.DecodeJSON(rr.Body, &updateUser) 13372 assert.NoError(t, err) 13373 assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate) 13374 assert.Equal(t, updateUser.FsConfig.S3Config.Bucket, user.FsConfig.S3Config.Bucket) 13375 assert.Equal(t, updateUser.FsConfig.S3Config.Region, user.FsConfig.S3Config.Region) 13376 assert.Equal(t, updateUser.FsConfig.S3Config.AccessKey, user.FsConfig.S3Config.AccessKey) 13377 assert.Equal(t, updateUser.FsConfig.S3Config.StorageClass, user.FsConfig.S3Config.StorageClass) 13378 assert.Equal(t, updateUser.FsConfig.S3Config.ACL, user.FsConfig.S3Config.ACL) 13379 assert.Equal(t, updateUser.FsConfig.S3Config.Endpoint, user.FsConfig.S3Config.Endpoint) 13380 assert.Equal(t, updateUser.FsConfig.S3Config.KeyPrefix, user.FsConfig.S3Config.KeyPrefix) 13381 assert.Equal(t, updateUser.FsConfig.S3Config.UploadPartSize, user.FsConfig.S3Config.UploadPartSize) 13382 assert.Equal(t, updateUser.FsConfig.S3Config.UploadConcurrency, user.FsConfig.S3Config.UploadConcurrency) 13383 assert.Equal(t, updateUser.FsConfig.S3Config.DownloadPartMaxTime, user.FsConfig.S3Config.DownloadPartMaxTime) 13384 assert.Equal(t, updateUser.FsConfig.S3Config.DownloadPartSize, user.FsConfig.S3Config.DownloadPartSize) 13385 assert.Equal(t, updateUser.FsConfig.S3Config.DownloadConcurrency, user.FsConfig.S3Config.DownloadConcurrency) 13386 assert.True(t, updateUser.FsConfig.S3Config.ForcePathStyle) 13387 assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) 13388 assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.S3Config.AccessSecret.GetStatus()) 13389 assert.NotEmpty(t, updateUser.FsConfig.S3Config.AccessSecret.GetPayload()) 13390 assert.Empty(t, updateUser.FsConfig.S3Config.AccessSecret.GetKey()) 13391 assert.Empty(t, updateUser.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 13392 assert.Equal(t, user.Description, updateUser.Description) 13393 assert.True(t, updateUser.Filters.Hooks.PreLoginDisabled) 13394 assert.False(t, updateUser.Filters.Hooks.ExternalAuthDisabled) 13395 assert.False(t, updateUser.Filters.Hooks.CheckPasswordDisabled) 13396 assert.False(t, updateUser.Filters.DisableFsChecks) 13397 assert.True(t, updateUser.Filters.AllowAPIKeyAuth) 13398 // now check that a redacted password is not saved 13399 form.Set("s3_access_secret", redactedSecret) 13400 b, contentType, _ = getMultipartFormData(form, "", "") 13401 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13402 setJWTCookieForReq(req, webToken) 13403 req.Header.Set("Content-Type", contentType) 13404 rr = executeRequest(req) 13405 checkResponseCode(t, http.StatusSeeOther, rr) 13406 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13407 setBearerForReq(req, apiToken) 13408 rr = executeRequest(req) 13409 checkResponseCode(t, http.StatusOK, rr) 13410 13411 var lastUpdatedUser dataprovider.User 13412 err = render.DecodeJSON(rr.Body, &lastUpdatedUser) 13413 assert.NoError(t, err) 13414 assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetStatus()) 13415 assert.Equal(t, updateUser.FsConfig.S3Config.AccessSecret.GetPayload(), lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetPayload()) 13416 assert.Empty(t, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetKey()) 13417 assert.Empty(t, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetAdditionalData()) 13418 // now clear credentials 13419 form.Set("s3_access_key", "") 13420 form.Set("s3_access_secret", "") 13421 b, contentType, _ = getMultipartFormData(form, "", "") 13422 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13423 setJWTCookieForReq(req, webToken) 13424 req.Header.Set("Content-Type", contentType) 13425 rr = executeRequest(req) 13426 checkResponseCode(t, http.StatusSeeOther, rr) 13427 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13428 setBearerForReq(req, apiToken) 13429 rr = executeRequest(req) 13430 checkResponseCode(t, http.StatusOK, rr) 13431 var userGet dataprovider.User 13432 err = render.DecodeJSON(rr.Body, &userGet) 13433 assert.NoError(t, err) 13434 assert.Nil(t, userGet.FsConfig.S3Config.AccessSecret) 13435 13436 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 13437 setBearerForReq(req, apiToken) 13438 rr = executeRequest(req) 13439 checkResponseCode(t, http.StatusOK, rr) 13440} 13441 13442func TestWebUserGCSMock(t *testing.T) { 13443 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13444 assert.NoError(t, err) 13445 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13446 assert.NoError(t, err) 13447 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 13448 assert.NoError(t, err) 13449 user := getTestUser() 13450 userAsJSON := getUserAsJSON(t, user) 13451 req, err := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 13452 assert.NoError(t, err) 13453 setBearerForReq(req, apiToken) 13454 rr := executeRequest(req) 13455 checkResponseCode(t, http.StatusCreated, rr) 13456 err = render.DecodeJSON(rr.Body, &user) 13457 assert.NoError(t, err) 13458 credentialsFilePath := filepath.Join(os.TempDir(), "gcs.json") 13459 err = createTestFile(credentialsFilePath, 0) 13460 assert.NoError(t, err) 13461 user.FsConfig.Provider = sdk.GCSFilesystemProvider 13462 user.FsConfig.GCSConfig.Bucket = "test" 13463 user.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/" 13464 user.FsConfig.GCSConfig.StorageClass = "standard" 13465 user.FsConfig.GCSConfig.ACL = "publicReadWrite" 13466 form := make(url.Values) 13467 form.Set(csrfFormToken, csrfToken) 13468 form.Set("username", user.Username) 13469 form.Set("password", redactedSecret) 13470 form.Set("home_dir", user.HomeDir) 13471 form.Set("uid", "0") 13472 form.Set("gid", strconv.FormatInt(int64(user.GID), 10)) 13473 form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10)) 13474 form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10)) 13475 form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10)) 13476 form.Set("upload_bandwidth", "0") 13477 form.Set("download_bandwidth", "0") 13478 form.Set("permissions", "*") 13479 form.Set("status", strconv.Itoa(user.Status)) 13480 form.Set("expiration_date", "2020-01-01 00:00:00") 13481 form.Set("allowed_ip", "") 13482 form.Set("denied_ip", "") 13483 form.Set("fs_provider", "2") 13484 form.Set("gcs_bucket", user.FsConfig.GCSConfig.Bucket) 13485 form.Set("gcs_storage_class", user.FsConfig.GCSConfig.StorageClass) 13486 form.Set("gcs_acl", user.FsConfig.GCSConfig.ACL) 13487 form.Set("gcs_key_prefix", user.FsConfig.GCSConfig.KeyPrefix) 13488 form.Set("pattern_path0", "/dir1") 13489 form.Set("patterns0", "*.jpg,*.png") 13490 form.Set("pattern_type0", "allowed") 13491 form.Set("max_upload_file_size", "0") 13492 b, contentType, _ := getMultipartFormData(form, "", "") 13493 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13494 setJWTCookieForReq(req, webToken) 13495 req.Header.Set("Content-Type", contentType) 13496 rr = executeRequest(req) 13497 checkResponseCode(t, http.StatusOK, rr) 13498 b, contentType, _ = getMultipartFormData(form, "gcs_credential_file", credentialsFilePath) 13499 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13500 setJWTCookieForReq(req, webToken) 13501 req.Header.Set("Content-Type", contentType) 13502 rr = executeRequest(req) 13503 checkResponseCode(t, http.StatusOK, rr) 13504 err = createTestFile(credentialsFilePath, 4096) 13505 assert.NoError(t, err) 13506 b, contentType, _ = getMultipartFormData(form, "gcs_credential_file", credentialsFilePath) 13507 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13508 setJWTCookieForReq(req, webToken) 13509 req.Header.Set("Content-Type", contentType) 13510 rr = executeRequest(req) 13511 checkResponseCode(t, http.StatusSeeOther, rr) 13512 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13513 setBearerForReq(req, apiToken) 13514 rr = executeRequest(req) 13515 checkResponseCode(t, http.StatusOK, rr) 13516 var updateUser dataprovider.User 13517 err = render.DecodeJSON(rr.Body, &updateUser) 13518 assert.NoError(t, err) 13519 assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate) 13520 assert.Equal(t, user.FsConfig.Provider, updateUser.FsConfig.Provider) 13521 assert.Equal(t, user.FsConfig.GCSConfig.Bucket, updateUser.FsConfig.GCSConfig.Bucket) 13522 assert.Equal(t, user.FsConfig.GCSConfig.StorageClass, updateUser.FsConfig.GCSConfig.StorageClass) 13523 assert.Equal(t, user.FsConfig.GCSConfig.ACL, updateUser.FsConfig.GCSConfig.ACL) 13524 assert.Equal(t, user.FsConfig.GCSConfig.KeyPrefix, updateUser.FsConfig.GCSConfig.KeyPrefix) 13525 if assert.Len(t, updateUser.Filters.FilePatterns, 1) { 13526 assert.Equal(t, "/dir1", updateUser.Filters.FilePatterns[0].Path) 13527 assert.Len(t, updateUser.Filters.FilePatterns[0].AllowedPatterns, 2) 13528 assert.Contains(t, updateUser.Filters.FilePatterns[0].AllowedPatterns, "*.png") 13529 assert.Contains(t, updateUser.Filters.FilePatterns[0].AllowedPatterns, "*.jpg") 13530 } 13531 form.Set("gcs_auto_credentials", "on") 13532 b, contentType, _ = getMultipartFormData(form, "", "") 13533 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13534 setJWTCookieForReq(req, webToken) 13535 req.Header.Set("Content-Type", contentType) 13536 rr = executeRequest(req) 13537 checkResponseCode(t, http.StatusSeeOther, rr) 13538 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13539 setBearerForReq(req, apiToken) 13540 rr = executeRequest(req) 13541 checkResponseCode(t, http.StatusOK, rr) 13542 updateUser = dataprovider.User{} 13543 err = render.DecodeJSON(rr.Body, &updateUser) 13544 assert.NoError(t, err) 13545 assert.Equal(t, 1, updateUser.FsConfig.GCSConfig.AutomaticCredentials) 13546 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 13547 setBearerForReq(req, apiToken) 13548 rr = executeRequest(req) 13549 checkResponseCode(t, http.StatusOK, rr) 13550 err = os.Remove(credentialsFilePath) 13551 assert.NoError(t, err) 13552} 13553 13554func TestWebUserAzureBlobMock(t *testing.T) { 13555 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13556 assert.NoError(t, err) 13557 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13558 assert.NoError(t, err) 13559 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 13560 assert.NoError(t, err) 13561 user := getTestUser() 13562 userAsJSON := getUserAsJSON(t, user) 13563 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 13564 setBearerForReq(req, apiToken) 13565 rr := executeRequest(req) 13566 checkResponseCode(t, http.StatusCreated, rr) 13567 err = render.DecodeJSON(rr.Body, &user) 13568 assert.NoError(t, err) 13569 user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider 13570 user.FsConfig.AzBlobConfig.Container = "container" 13571 user.FsConfig.AzBlobConfig.AccountName = "aname" 13572 user.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("access-skey") 13573 user.FsConfig.AzBlobConfig.Endpoint = "http://127.0.0.1:9000/path?b=c" 13574 user.FsConfig.AzBlobConfig.KeyPrefix = "somedir/subdir/" 13575 user.FsConfig.AzBlobConfig.UploadPartSize = 5 13576 user.FsConfig.AzBlobConfig.UploadConcurrency = 4 13577 user.FsConfig.AzBlobConfig.UseEmulator = true 13578 form := make(url.Values) 13579 form.Set(csrfFormToken, csrfToken) 13580 form.Set("username", user.Username) 13581 form.Set("password", redactedSecret) 13582 form.Set("home_dir", user.HomeDir) 13583 form.Set("uid", "0") 13584 form.Set("gid", strconv.FormatInt(int64(user.GID), 10)) 13585 form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10)) 13586 form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10)) 13587 form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10)) 13588 form.Set("upload_bandwidth", "0") 13589 form.Set("download_bandwidth", "0") 13590 form.Set("permissions", "*") 13591 form.Set("status", strconv.Itoa(user.Status)) 13592 form.Set("expiration_date", "2020-01-01 00:00:00") 13593 form.Set("allowed_ip", "") 13594 form.Set("denied_ip", "") 13595 form.Set("fs_provider", "3") 13596 form.Set("az_container", user.FsConfig.AzBlobConfig.Container) 13597 form.Set("az_account_name", user.FsConfig.AzBlobConfig.AccountName) 13598 form.Set("az_account_key", user.FsConfig.AzBlobConfig.AccountKey.GetPayload()) 13599 form.Set("az_endpoint", user.FsConfig.AzBlobConfig.Endpoint) 13600 form.Set("az_key_prefix", user.FsConfig.AzBlobConfig.KeyPrefix) 13601 form.Set("az_use_emulator", "checked") 13602 form.Set("pattern_path0", "/dir1") 13603 form.Set("patterns0", "*.jpg,*.png") 13604 form.Set("pattern_type0", "allowed") 13605 form.Set("pattern_path1", "/dir2") 13606 form.Set("patterns1", "*.zip") 13607 form.Set("pattern_type1", "denied") 13608 form.Set("max_upload_file_size", "0") 13609 // test invalid az_upload_part_size 13610 form.Set("az_upload_part_size", "a") 13611 b, contentType, _ := getMultipartFormData(form, "", "") 13612 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13613 setJWTCookieForReq(req, webToken) 13614 req.Header.Set("Content-Type", contentType) 13615 rr = executeRequest(req) 13616 checkResponseCode(t, http.StatusOK, rr) 13617 // test invalid az_upload_concurrency 13618 form.Set("az_upload_part_size", strconv.FormatInt(user.FsConfig.AzBlobConfig.UploadPartSize, 10)) 13619 form.Set("az_upload_concurrency", "a") 13620 b, contentType, _ = getMultipartFormData(form, "", "") 13621 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13622 setJWTCookieForReq(req, webToken) 13623 req.Header.Set("Content-Type", contentType) 13624 rr = executeRequest(req) 13625 checkResponseCode(t, http.StatusOK, rr) 13626 // now add the user 13627 form.Set("az_upload_concurrency", strconv.Itoa(user.FsConfig.AzBlobConfig.UploadConcurrency)) 13628 b, contentType, _ = getMultipartFormData(form, "", "") 13629 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13630 setJWTCookieForReq(req, webToken) 13631 req.Header.Set("Content-Type", contentType) 13632 rr = executeRequest(req) 13633 checkResponseCode(t, http.StatusSeeOther, rr) 13634 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13635 setBearerForReq(req, apiToken) 13636 rr = executeRequest(req) 13637 checkResponseCode(t, http.StatusOK, rr) 13638 var updateUser dataprovider.User 13639 err = render.DecodeJSON(rr.Body, &updateUser) 13640 assert.NoError(t, err) 13641 assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate) 13642 assert.Equal(t, updateUser.FsConfig.AzBlobConfig.Container, user.FsConfig.AzBlobConfig.Container) 13643 assert.Equal(t, updateUser.FsConfig.AzBlobConfig.AccountName, user.FsConfig.AzBlobConfig.AccountName) 13644 assert.Equal(t, updateUser.FsConfig.AzBlobConfig.Endpoint, user.FsConfig.AzBlobConfig.Endpoint) 13645 assert.Equal(t, updateUser.FsConfig.AzBlobConfig.KeyPrefix, user.FsConfig.AzBlobConfig.KeyPrefix) 13646 assert.Equal(t, updateUser.FsConfig.AzBlobConfig.UploadPartSize, user.FsConfig.AzBlobConfig.UploadPartSize) 13647 assert.Equal(t, updateUser.FsConfig.AzBlobConfig.UploadConcurrency, user.FsConfig.AzBlobConfig.UploadConcurrency) 13648 assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) 13649 assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.AzBlobConfig.AccountKey.GetStatus()) 13650 assert.NotEmpty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetPayload()) 13651 assert.Empty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetKey()) 13652 assert.Empty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) 13653 // now check that a redacted password is not saved 13654 form.Set("az_account_key", redactedSecret+" ") 13655 b, contentType, _ = getMultipartFormData(form, "", "") 13656 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13657 setJWTCookieForReq(req, webToken) 13658 req.Header.Set("Content-Type", contentType) 13659 rr = executeRequest(req) 13660 checkResponseCode(t, http.StatusSeeOther, rr) 13661 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13662 setBearerForReq(req, apiToken) 13663 rr = executeRequest(req) 13664 checkResponseCode(t, http.StatusOK, rr) 13665 var lastUpdatedUser dataprovider.User 13666 err = render.DecodeJSON(rr.Body, &lastUpdatedUser) 13667 assert.NoError(t, err) 13668 assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetStatus()) 13669 assert.Equal(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetPayload(), lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetPayload()) 13670 assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetKey()) 13671 assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) 13672 // test SAS url 13673 user.FsConfig.AzBlobConfig.SASURL = kms.NewPlainSecret("sasurl") 13674 form.Set("az_account_name", "") 13675 form.Set("az_account_key", "") 13676 form.Set("az_container", "") 13677 form.Set("az_sas_url", user.FsConfig.AzBlobConfig.SASURL.GetPayload()) 13678 b, contentType, _ = getMultipartFormData(form, "", "") 13679 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13680 setJWTCookieForReq(req, webToken) 13681 req.Header.Set("Content-Type", contentType) 13682 rr = executeRequest(req) 13683 checkResponseCode(t, http.StatusSeeOther, rr) 13684 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13685 setBearerForReq(req, apiToken) 13686 rr = executeRequest(req) 13687 checkResponseCode(t, http.StatusOK, rr) 13688 updateUser = dataprovider.User{} 13689 err = render.DecodeJSON(rr.Body, &updateUser) 13690 assert.NoError(t, err) 13691 assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.AzBlobConfig.SASURL.GetStatus()) 13692 assert.NotEmpty(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetPayload()) 13693 assert.Empty(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetKey()) 13694 assert.Empty(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetAdditionalData()) 13695 // now check that a redacted sas url is not saved 13696 form.Set("az_sas_url", redactedSecret) 13697 b, contentType, _ = getMultipartFormData(form, "", "") 13698 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13699 setJWTCookieForReq(req, webToken) 13700 req.Header.Set("Content-Type", contentType) 13701 rr = executeRequest(req) 13702 checkResponseCode(t, http.StatusSeeOther, rr) 13703 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13704 setBearerForReq(req, apiToken) 13705 rr = executeRequest(req) 13706 checkResponseCode(t, http.StatusOK, rr) 13707 lastUpdatedUser = dataprovider.User{} 13708 err = render.DecodeJSON(rr.Body, &lastUpdatedUser) 13709 assert.NoError(t, err) 13710 assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetStatus()) 13711 assert.Equal(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetPayload(), lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetPayload()) 13712 assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetKey()) 13713 assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetAdditionalData()) 13714 13715 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 13716 setBearerForReq(req, apiToken) 13717 rr = executeRequest(req) 13718 checkResponseCode(t, http.StatusOK, rr) 13719} 13720 13721func TestWebUserCryptMock(t *testing.T) { 13722 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13723 assert.NoError(t, err) 13724 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13725 assert.NoError(t, err) 13726 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 13727 assert.NoError(t, err) 13728 user := getTestUser() 13729 userAsJSON := getUserAsJSON(t, user) 13730 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 13731 setBearerForReq(req, apiToken) 13732 rr := executeRequest(req) 13733 checkResponseCode(t, http.StatusCreated, rr) 13734 err = render.DecodeJSON(rr.Body, &user) 13735 assert.NoError(t, err) 13736 user.FsConfig.Provider = sdk.CryptedFilesystemProvider 13737 user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("crypted passphrase") 13738 form := make(url.Values) 13739 form.Set(csrfFormToken, csrfToken) 13740 form.Set("username", user.Username) 13741 form.Set("password", redactedSecret) 13742 form.Set("home_dir", user.HomeDir) 13743 form.Set("uid", "0") 13744 form.Set("gid", strconv.FormatInt(int64(user.GID), 10)) 13745 form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10)) 13746 form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10)) 13747 form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10)) 13748 form.Set("upload_bandwidth", "0") 13749 form.Set("download_bandwidth", "0") 13750 form.Set("permissions", "*") 13751 form.Set("status", strconv.Itoa(user.Status)) 13752 form.Set("expiration_date", "2020-01-01 00:00:00") 13753 form.Set("allowed_ip", "") 13754 form.Set("denied_ip", "") 13755 form.Set("fs_provider", "4") 13756 form.Set("crypt_passphrase", "") 13757 form.Set("pattern_path0", "/dir1") 13758 form.Set("patterns0", "*.jpg,*.png") 13759 form.Set("pattern_type0", "allowed") 13760 form.Set("pattern_path1", "/dir2") 13761 form.Set("patterns1", "*.zip") 13762 form.Set("pattern_type1", "denied") 13763 form.Set("max_upload_file_size", "0") 13764 // passphrase cannot be empty 13765 b, contentType, _ := getMultipartFormData(form, "", "") 13766 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13767 setJWTCookieForReq(req, webToken) 13768 req.Header.Set("Content-Type", contentType) 13769 rr = executeRequest(req) 13770 checkResponseCode(t, http.StatusOK, rr) 13771 form.Set("crypt_passphrase", user.FsConfig.CryptConfig.Passphrase.GetPayload()) 13772 b, contentType, _ = getMultipartFormData(form, "", "") 13773 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13774 setJWTCookieForReq(req, webToken) 13775 req.Header.Set("Content-Type", contentType) 13776 rr = executeRequest(req) 13777 checkResponseCode(t, http.StatusSeeOther, rr) 13778 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13779 setBearerForReq(req, apiToken) 13780 rr = executeRequest(req) 13781 checkResponseCode(t, http.StatusOK, rr) 13782 var updateUser dataprovider.User 13783 err = render.DecodeJSON(rr.Body, &updateUser) 13784 assert.NoError(t, err) 13785 assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate) 13786 assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) 13787 assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.CryptConfig.Passphrase.GetStatus()) 13788 assert.NotEmpty(t, updateUser.FsConfig.CryptConfig.Passphrase.GetPayload()) 13789 assert.Empty(t, updateUser.FsConfig.CryptConfig.Passphrase.GetKey()) 13790 assert.Empty(t, updateUser.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 13791 // now check that a redacted password is not saved 13792 form.Set("crypt_passphrase", redactedSecret+" ") 13793 b, contentType, _ = getMultipartFormData(form, "", "") 13794 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13795 setJWTCookieForReq(req, webToken) 13796 req.Header.Set("Content-Type", contentType) 13797 rr = executeRequest(req) 13798 checkResponseCode(t, http.StatusSeeOther, rr) 13799 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13800 setBearerForReq(req, apiToken) 13801 rr = executeRequest(req) 13802 checkResponseCode(t, http.StatusOK, rr) 13803 var lastUpdatedUser dataprovider.User 13804 err = render.DecodeJSON(rr.Body, &lastUpdatedUser) 13805 assert.NoError(t, err) 13806 assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetStatus()) 13807 assert.Equal(t, updateUser.FsConfig.CryptConfig.Passphrase.GetPayload(), lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetPayload()) 13808 assert.Empty(t, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetKey()) 13809 assert.Empty(t, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) 13810 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 13811 setBearerForReq(req, apiToken) 13812 rr = executeRequest(req) 13813 checkResponseCode(t, http.StatusOK, rr) 13814} 13815 13816func TestWebUserSFTPFsMock(t *testing.T) { 13817 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13818 assert.NoError(t, err) 13819 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13820 assert.NoError(t, err) 13821 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 13822 assert.NoError(t, err) 13823 user := getTestUser() 13824 userAsJSON := getUserAsJSON(t, user) 13825 req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON)) 13826 setBearerForReq(req, apiToken) 13827 rr := executeRequest(req) 13828 checkResponseCode(t, http.StatusCreated, rr) 13829 err = render.DecodeJSON(rr.Body, &user) 13830 assert.NoError(t, err) 13831 user.FsConfig.Provider = sdk.SFTPFilesystemProvider 13832 user.FsConfig.SFTPConfig.Endpoint = "127.0.0.1:22" 13833 user.FsConfig.SFTPConfig.Username = "sftpuser" 13834 user.FsConfig.SFTPConfig.Password = kms.NewPlainSecret("pwd") 13835 user.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey) 13836 user.FsConfig.SFTPConfig.Fingerprints = []string{sftpPkeyFingerprint} 13837 user.FsConfig.SFTPConfig.Prefix = "/home/sftpuser" 13838 user.FsConfig.SFTPConfig.DisableCouncurrentReads = true 13839 user.FsConfig.SFTPConfig.BufferSize = 5 13840 form := make(url.Values) 13841 form.Set(csrfFormToken, csrfToken) 13842 form.Set("username", user.Username) 13843 form.Set("password", redactedSecret) 13844 form.Set("home_dir", user.HomeDir) 13845 form.Set("uid", "0") 13846 form.Set("gid", strconv.FormatInt(int64(user.GID), 10)) 13847 form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10)) 13848 form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10)) 13849 form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10)) 13850 form.Set("upload_bandwidth", "0") 13851 form.Set("download_bandwidth", "0") 13852 form.Set("permissions", "*") 13853 form.Set("status", strconv.Itoa(user.Status)) 13854 form.Set("expiration_date", "2020-01-01 00:00:00") 13855 form.Set("allowed_ip", "") 13856 form.Set("denied_ip", "") 13857 form.Set("fs_provider", "5") 13858 form.Set("crypt_passphrase", "") 13859 form.Set("pattern_path0", "/dir1") 13860 form.Set("patterns0", "*.jpg,*.png") 13861 form.Set("pattern_type0", "allowed") 13862 form.Set("pattern_path1", "/dir2") 13863 form.Set("patterns1", "*.zip") 13864 form.Set("pattern_type1", "denied") 13865 form.Set("max_upload_file_size", "0") 13866 // empty sftpconfig 13867 b, contentType, _ := getMultipartFormData(form, "", "") 13868 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13869 setJWTCookieForReq(req, webToken) 13870 req.Header.Set("Content-Type", contentType) 13871 rr = executeRequest(req) 13872 checkResponseCode(t, http.StatusOK, rr) 13873 form.Set("sftp_endpoint", user.FsConfig.SFTPConfig.Endpoint) 13874 form.Set("sftp_username", user.FsConfig.SFTPConfig.Username) 13875 form.Set("sftp_password", user.FsConfig.SFTPConfig.Password.GetPayload()) 13876 form.Set("sftp_private_key", user.FsConfig.SFTPConfig.PrivateKey.GetPayload()) 13877 form.Set("sftp_fingerprints", user.FsConfig.SFTPConfig.Fingerprints[0]) 13878 form.Set("sftp_prefix", user.FsConfig.SFTPConfig.Prefix) 13879 form.Set("sftp_disable_concurrent_reads", "true") 13880 form.Set("sftp_buffer_size", strconv.FormatInt(user.FsConfig.SFTPConfig.BufferSize, 10)) 13881 b, contentType, _ = getMultipartFormData(form, "", "") 13882 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13883 setJWTCookieForReq(req, webToken) 13884 req.Header.Set("Content-Type", contentType) 13885 rr = executeRequest(req) 13886 checkResponseCode(t, http.StatusSeeOther, rr) 13887 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13888 setBearerForReq(req, apiToken) 13889 rr = executeRequest(req) 13890 checkResponseCode(t, http.StatusOK, rr) 13891 var updateUser dataprovider.User 13892 err = render.DecodeJSON(rr.Body, &updateUser) 13893 assert.NoError(t, err) 13894 assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate) 13895 assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) 13896 assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.SFTPConfig.Password.GetStatus()) 13897 assert.NotEmpty(t, updateUser.FsConfig.SFTPConfig.Password.GetPayload()) 13898 assert.Empty(t, updateUser.FsConfig.SFTPConfig.Password.GetKey()) 13899 assert.Empty(t, updateUser.FsConfig.SFTPConfig.Password.GetAdditionalData()) 13900 assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.SFTPConfig.PrivateKey.GetStatus()) 13901 assert.NotEmpty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetPayload()) 13902 assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetKey()) 13903 assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) 13904 assert.Equal(t, updateUser.FsConfig.SFTPConfig.Prefix, user.FsConfig.SFTPConfig.Prefix) 13905 assert.Equal(t, updateUser.FsConfig.SFTPConfig.Username, user.FsConfig.SFTPConfig.Username) 13906 assert.Equal(t, updateUser.FsConfig.SFTPConfig.Endpoint, user.FsConfig.SFTPConfig.Endpoint) 13907 assert.True(t, updateUser.FsConfig.SFTPConfig.DisableCouncurrentReads) 13908 assert.Len(t, updateUser.FsConfig.SFTPConfig.Fingerprints, 1) 13909 assert.Equal(t, user.FsConfig.SFTPConfig.BufferSize, updateUser.FsConfig.SFTPConfig.BufferSize) 13910 assert.Contains(t, updateUser.FsConfig.SFTPConfig.Fingerprints, sftpPkeyFingerprint) 13911 // now check that a redacted credentials are not saved 13912 form.Set("sftp_password", redactedSecret+" ") 13913 form.Set("sftp_private_key", redactedSecret) 13914 b, contentType, _ = getMultipartFormData(form, "", "") 13915 req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) 13916 setJWTCookieForReq(req, webToken) 13917 req.Header.Set("Content-Type", contentType) 13918 rr = executeRequest(req) 13919 checkResponseCode(t, http.StatusSeeOther, rr) 13920 req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil) 13921 setBearerForReq(req, apiToken) 13922 rr = executeRequest(req) 13923 checkResponseCode(t, http.StatusOK, rr) 13924 var lastUpdatedUser dataprovider.User 13925 err = render.DecodeJSON(rr.Body, &lastUpdatedUser) 13926 assert.NoError(t, err) 13927 assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetStatus()) 13928 assert.Equal(t, updateUser.FsConfig.SFTPConfig.Password.GetPayload(), lastUpdatedUser.FsConfig.SFTPConfig.Password.GetPayload()) 13929 assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetKey()) 13930 assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetAdditionalData()) 13931 assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetStatus()) 13932 assert.Equal(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetPayload(), lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetPayload()) 13933 assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetKey()) 13934 assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) 13935 req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) 13936 setBearerForReq(req, apiToken) 13937 rr = executeRequest(req) 13938 checkResponseCode(t, http.StatusOK, rr) 13939} 13940 13941func TestAddWebFoldersMock(t *testing.T) { 13942 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13943 assert.NoError(t, err) 13944 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 13945 assert.NoError(t, err) 13946 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 13947 assert.NoError(t, err) 13948 mappedPath := filepath.Clean(os.TempDir()) 13949 folderName := filepath.Base(mappedPath) 13950 folderDesc := "a simple desc" 13951 form := make(url.Values) 13952 form.Set("mapped_path", mappedPath) 13953 form.Set("name", folderName) 13954 form.Set("description", folderDesc) 13955 b, contentType, err := getMultipartFormData(form, "", "") 13956 assert.NoError(t, err) 13957 req, err := http.NewRequest(http.MethodPost, webFolderPath, &b) 13958 assert.NoError(t, err) 13959 req.Header.Set("Content-Type", contentType) 13960 setJWTCookieForReq(req, webToken) 13961 rr := executeRequest(req) 13962 checkResponseCode(t, http.StatusForbidden, rr) 13963 assert.Contains(t, rr.Body.String(), "unable to verify form token") 13964 13965 form.Set(csrfFormToken, csrfToken) 13966 b, contentType, err = getMultipartFormData(form, "", "") 13967 assert.NoError(t, err) 13968 req, err = http.NewRequest(http.MethodPost, webFolderPath, &b) 13969 assert.NoError(t, err) 13970 req.Header.Set("Content-Type", contentType) 13971 setJWTCookieForReq(req, webToken) 13972 rr = executeRequest(req) 13973 checkResponseCode(t, http.StatusSeeOther, rr) 13974 // adding the same folder will fail since the name must be unique 13975 b, contentType, err = getMultipartFormData(form, "", "") 13976 assert.NoError(t, err) 13977 req, err = http.NewRequest(http.MethodPost, webFolderPath, &b) 13978 assert.NoError(t, err) 13979 setJWTCookieForReq(req, webToken) 13980 req.Header.Set("Content-Type", contentType) 13981 rr = executeRequest(req) 13982 checkResponseCode(t, http.StatusOK, rr) 13983 // invalid form 13984 req, err = http.NewRequest(http.MethodPost, webFolderPath, strings.NewReader(form.Encode())) 13985 assert.NoError(t, err) 13986 setJWTCookieForReq(req, webToken) 13987 req.Header.Set("Content-Type", "text/plain; boundary=") 13988 rr = executeRequest(req) 13989 checkResponseCode(t, http.StatusOK, rr) 13990 13991 // now render the add folder page 13992 req, err = http.NewRequest(http.MethodGet, webFolderPath, nil) 13993 assert.NoError(t, err) 13994 setJWTCookieForReq(req, webToken) 13995 rr = executeRequest(req) 13996 checkResponseCode(t, http.StatusOK, rr) 13997 13998 var folder vfs.BaseVirtualFolder 13999 req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil) 14000 setBearerForReq(req, apiToken) 14001 rr = executeRequest(req) 14002 checkResponseCode(t, http.StatusOK, rr) 14003 err = render.DecodeJSON(rr.Body, &folder) 14004 assert.NoError(t, err) 14005 assert.Equal(t, mappedPath, folder.MappedPath) 14006 assert.Equal(t, folderName, folder.Name) 14007 assert.Equal(t, folderDesc, folder.Description) 14008 // cleanup 14009 req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil) 14010 setBearerForReq(req, apiToken) 14011 rr = executeRequest(req) 14012 checkResponseCode(t, http.StatusOK, rr) 14013} 14014 14015func TestS3WebFolderMock(t *testing.T) { 14016 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 14017 assert.NoError(t, err) 14018 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 14019 assert.NoError(t, err) 14020 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 14021 assert.NoError(t, err) 14022 mappedPath := filepath.Clean(os.TempDir()) 14023 folderName := filepath.Base(mappedPath) 14024 folderDesc := "a simple desc" 14025 S3Bucket := "test" 14026 S3Region := "eu-west-1" 14027 S3AccessKey := "access-key" 14028 S3AccessSecret := kms.NewPlainSecret("folder-access-secret") 14029 S3Endpoint := "http://127.0.0.1:9000/path?b=c" 14030 S3StorageClass := "Standard" 14031 S3ACL := "public-read-write" 14032 S3KeyPrefix := "somedir/subdir/" 14033 S3UploadPartSize := 5 14034 S3UploadConcurrency := 4 14035 S3MaxPartDownloadTime := 120 14036 S3DownloadPartSize := 6 14037 S3DownloadConcurrency := 3 14038 form := make(url.Values) 14039 form.Set("mapped_path", mappedPath) 14040 form.Set("name", folderName) 14041 form.Set("description", folderDesc) 14042 form.Set("fs_provider", "1") 14043 form.Set("s3_bucket", S3Bucket) 14044 form.Set("s3_region", S3Region) 14045 form.Set("s3_access_key", S3AccessKey) 14046 form.Set("s3_access_secret", S3AccessSecret.GetPayload()) 14047 form.Set("s3_storage_class", S3StorageClass) 14048 form.Set("s3_acl", S3ACL) 14049 form.Set("s3_endpoint", S3Endpoint) 14050 form.Set("s3_key_prefix", S3KeyPrefix) 14051 form.Set("s3_upload_part_size", strconv.Itoa(S3UploadPartSize)) 14052 form.Set("s3_download_part_max_time", strconv.Itoa(S3MaxPartDownloadTime)) 14053 form.Set("s3_download_part_size", strconv.Itoa(S3DownloadPartSize)) 14054 form.Set("s3_download_concurrency", strconv.Itoa(S3DownloadConcurrency)) 14055 form.Set("s3_upload_concurrency", "a") 14056 form.Set(csrfFormToken, csrfToken) 14057 b, contentType, err := getMultipartFormData(form, "", "") 14058 assert.NoError(t, err) 14059 req, err := http.NewRequest(http.MethodPost, webFolderPath, &b) 14060 assert.NoError(t, err) 14061 setJWTCookieForReq(req, webToken) 14062 req.Header.Set("Content-Type", contentType) 14063 rr := executeRequest(req) 14064 checkResponseCode(t, http.StatusOK, rr) 14065 14066 form.Set("s3_upload_concurrency", strconv.Itoa(S3UploadConcurrency)) 14067 b, contentType, err = getMultipartFormData(form, "", "") 14068 assert.NoError(t, err) 14069 req, err = http.NewRequest(http.MethodPost, webFolderPath, &b) 14070 assert.NoError(t, err) 14071 setJWTCookieForReq(req, webToken) 14072 req.Header.Set("Content-Type", contentType) 14073 rr = executeRequest(req) 14074 checkResponseCode(t, http.StatusSeeOther, rr) 14075 14076 var folder vfs.BaseVirtualFolder 14077 req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil) 14078 setBearerForReq(req, apiToken) 14079 rr = executeRequest(req) 14080 checkResponseCode(t, http.StatusOK, rr) 14081 err = render.DecodeJSON(rr.Body, &folder) 14082 assert.NoError(t, err) 14083 assert.Equal(t, mappedPath, folder.MappedPath) 14084 assert.Equal(t, folderName, folder.Name) 14085 assert.Equal(t, folderDesc, folder.Description) 14086 assert.Equal(t, sdk.S3FilesystemProvider, folder.FsConfig.Provider) 14087 assert.Equal(t, S3Bucket, folder.FsConfig.S3Config.Bucket) 14088 assert.Equal(t, S3Region, folder.FsConfig.S3Config.Region) 14089 assert.Equal(t, S3AccessKey, folder.FsConfig.S3Config.AccessKey) 14090 assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload()) 14091 assert.Equal(t, S3Endpoint, folder.FsConfig.S3Config.Endpoint) 14092 assert.Equal(t, S3StorageClass, folder.FsConfig.S3Config.StorageClass) 14093 assert.Equal(t, S3ACL, folder.FsConfig.S3Config.ACL) 14094 assert.Equal(t, S3KeyPrefix, folder.FsConfig.S3Config.KeyPrefix) 14095 assert.Equal(t, S3UploadConcurrency, folder.FsConfig.S3Config.UploadConcurrency) 14096 assert.Equal(t, int64(S3UploadPartSize), folder.FsConfig.S3Config.UploadPartSize) 14097 assert.Equal(t, S3MaxPartDownloadTime, folder.FsConfig.S3Config.DownloadPartMaxTime) 14098 assert.Equal(t, S3DownloadConcurrency, folder.FsConfig.S3Config.DownloadConcurrency) 14099 assert.Equal(t, int64(S3DownloadPartSize), folder.FsConfig.S3Config.DownloadPartSize) 14100 assert.False(t, folder.FsConfig.S3Config.ForcePathStyle) 14101 // update 14102 S3UploadConcurrency = 10 14103 form.Set("s3_upload_concurrency", "b") 14104 b, contentType, err = getMultipartFormData(form, "", "") 14105 assert.NoError(t, err) 14106 req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b) 14107 assert.NoError(t, err) 14108 setJWTCookieForReq(req, webToken) 14109 req.Header.Set("Content-Type", contentType) 14110 rr = executeRequest(req) 14111 checkResponseCode(t, http.StatusOK, rr) 14112 14113 form.Set("s3_upload_concurrency", strconv.Itoa(S3UploadConcurrency)) 14114 b, contentType, err = getMultipartFormData(form, "", "") 14115 assert.NoError(t, err) 14116 req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b) 14117 assert.NoError(t, err) 14118 setJWTCookieForReq(req, webToken) 14119 req.Header.Set("Content-Type", contentType) 14120 rr = executeRequest(req) 14121 checkResponseCode(t, http.StatusSeeOther, rr) 14122 14123 folder = vfs.BaseVirtualFolder{} 14124 req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil) 14125 setBearerForReq(req, apiToken) 14126 rr = executeRequest(req) 14127 checkResponseCode(t, http.StatusOK, rr) 14128 err = render.DecodeJSON(rr.Body, &folder) 14129 assert.NoError(t, err) 14130 assert.Equal(t, mappedPath, folder.MappedPath) 14131 assert.Equal(t, folderName, folder.Name) 14132 assert.Equal(t, folderDesc, folder.Description) 14133 assert.Equal(t, sdk.S3FilesystemProvider, folder.FsConfig.Provider) 14134 assert.Equal(t, S3Bucket, folder.FsConfig.S3Config.Bucket) 14135 assert.Equal(t, S3Region, folder.FsConfig.S3Config.Region) 14136 assert.Equal(t, S3AccessKey, folder.FsConfig.S3Config.AccessKey) 14137 assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload()) 14138 assert.Equal(t, S3Endpoint, folder.FsConfig.S3Config.Endpoint) 14139 assert.Equal(t, S3StorageClass, folder.FsConfig.S3Config.StorageClass) 14140 assert.Equal(t, S3KeyPrefix, folder.FsConfig.S3Config.KeyPrefix) 14141 assert.Equal(t, S3UploadConcurrency, folder.FsConfig.S3Config.UploadConcurrency) 14142 assert.Equal(t, int64(S3UploadPartSize), folder.FsConfig.S3Config.UploadPartSize) 14143 14144 // cleanup 14145 req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil) 14146 setBearerForReq(req, apiToken) 14147 rr = executeRequest(req) 14148 checkResponseCode(t, http.StatusOK, rr) 14149} 14150 14151func TestUpdateWebFolderMock(t *testing.T) { 14152 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 14153 assert.NoError(t, err) 14154 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 14155 assert.NoError(t, err) 14156 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 14157 assert.NoError(t, err) 14158 folderName := "vfolderupdate" 14159 folderDesc := "updated desc" 14160 folder := vfs.BaseVirtualFolder{ 14161 Name: folderName, 14162 MappedPath: filepath.Join(os.TempDir(), "folderupdate"), 14163 Description: "dsc", 14164 } 14165 _, _, err = httpdtest.AddFolder(folder, http.StatusCreated) 14166 newMappedPath := folder.MappedPath + "1" 14167 assert.NoError(t, err) 14168 form := make(url.Values) 14169 form.Set("mapped_path", newMappedPath) 14170 form.Set("name", folderName) 14171 form.Set("description", folderDesc) 14172 form.Set(csrfFormToken, "") 14173 b, contentType, err := getMultipartFormData(form, "", "") 14174 assert.NoError(t, err) 14175 req, err := http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b) 14176 assert.NoError(t, err) 14177 setJWTCookieForReq(req, webToken) 14178 req.Header.Set("Content-Type", contentType) 14179 rr := executeRequest(req) 14180 checkResponseCode(t, http.StatusForbidden, rr) 14181 assert.Contains(t, rr.Body.String(), "unable to verify form token") 14182 14183 form.Set(csrfFormToken, csrfToken) 14184 b, contentType, err = getMultipartFormData(form, "", "") 14185 assert.NoError(t, err) 14186 req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b) 14187 assert.NoError(t, err) 14188 setJWTCookieForReq(req, webToken) 14189 req.Header.Set("Content-Type", contentType) 14190 rr = executeRequest(req) 14191 checkResponseCode(t, http.StatusSeeOther, rr) 14192 14193 req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil) 14194 setBearerForReq(req, apiToken) 14195 rr = executeRequest(req) 14196 checkResponseCode(t, http.StatusOK, rr) 14197 err = render.DecodeJSON(rr.Body, &folder) 14198 assert.NoError(t, err) 14199 assert.Equal(t, newMappedPath, folder.MappedPath) 14200 assert.Equal(t, folderName, folder.Name) 14201 assert.Equal(t, folderDesc, folder.Description) 14202 14203 // parse form error 14204 b, contentType, err = getMultipartFormData(form, "", "") 14205 assert.NoError(t, err) 14206 req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName)+"??a=a%B3%A2%G3", &b) 14207 assert.NoError(t, err) 14208 setJWTCookieForReq(req, webToken) 14209 req.Header.Set("Content-Type", contentType) 14210 rr = executeRequest(req) 14211 checkResponseCode(t, http.StatusOK, rr) 14212 assert.Contains(t, rr.Body.String(), "invalid URL escape") 14213 14214 b, contentType, err = getMultipartFormData(form, "", "") 14215 assert.NoError(t, err) 14216 req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName+"1"), &b) 14217 assert.NoError(t, err) 14218 setJWTCookieForReq(req, webToken) 14219 req.Header.Set("Content-Type", contentType) 14220 rr = executeRequest(req) 14221 checkResponseCode(t, http.StatusNotFound, rr) 14222 14223 form.Set("mapped_path", "arelative/path") 14224 b, contentType, err = getMultipartFormData(form, "", "") 14225 assert.NoError(t, err) 14226 req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b) 14227 assert.NoError(t, err) 14228 setJWTCookieForReq(req, webToken) 14229 req.Header.Set("Content-Type", contentType) 14230 rr = executeRequest(req) 14231 checkResponseCode(t, http.StatusOK, rr) 14232 14233 // render update folder page 14234 req, err = http.NewRequest(http.MethodGet, path.Join(webFolderPath, folderName), nil) 14235 assert.NoError(t, err) 14236 setJWTCookieForReq(req, webToken) 14237 rr = executeRequest(req) 14238 checkResponseCode(t, http.StatusOK, rr) 14239 14240 req, err = http.NewRequest(http.MethodGet, path.Join(webFolderPath, folderName+"1"), nil) 14241 assert.NoError(t, err) 14242 setJWTCookieForReq(req, webToken) 14243 rr = executeRequest(req) 14244 checkResponseCode(t, http.StatusNotFound, rr) 14245 14246 req, _ = http.NewRequest(http.MethodDelete, path.Join(webFolderPath, folderName), nil) 14247 setJWTCookieForReq(req, webToken) 14248 rr = executeRequest(req) 14249 checkResponseCode(t, http.StatusForbidden, rr) 14250 assert.Contains(t, rr.Body.String(), "Invalid token") 14251 14252 req, _ = http.NewRequest(http.MethodDelete, path.Join(webFolderPath, folderName), nil) 14253 setJWTCookieForReq(req, apiToken) // api token is not accepted 14254 setCSRFHeaderForReq(req, csrfToken) 14255 rr = executeRequest(req) 14256 checkResponseCode(t, http.StatusFound, rr) 14257 assert.Equal(t, webLoginPath, rr.Header().Get("Location")) 14258 14259 req, _ = http.NewRequest(http.MethodDelete, path.Join(webFolderPath, folderName), nil) 14260 setJWTCookieForReq(req, webToken) 14261 setCSRFHeaderForReq(req, csrfToken) 14262 rr = executeRequest(req) 14263 checkResponseCode(t, http.StatusOK, rr) 14264} 14265 14266func TestWebFoldersMock(t *testing.T) { 14267 webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 14268 assert.NoError(t, err) 14269 apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 14270 assert.NoError(t, err) 14271 mappedPath1 := filepath.Join(os.TempDir(), "vfolder1") 14272 mappedPath2 := filepath.Join(os.TempDir(), "vfolder2") 14273 folderName1 := filepath.Base(mappedPath1) 14274 folderName2 := filepath.Base(mappedPath2) 14275 folderDesc1 := "vfolder1 desc" 14276 folderDesc2 := "vfolder2 desc" 14277 folders := []vfs.BaseVirtualFolder{ 14278 { 14279 Name: folderName1, 14280 MappedPath: mappedPath1, 14281 Description: folderDesc1, 14282 }, 14283 { 14284 Name: folderName2, 14285 MappedPath: mappedPath2, 14286 Description: folderDesc2, 14287 }, 14288 } 14289 for _, folder := range folders { 14290 folderAsJSON, err := json.Marshal(folder) 14291 assert.NoError(t, err) 14292 req, err := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON)) 14293 assert.NoError(t, err) 14294 setBearerForReq(req, apiToken) 14295 rr := executeRequest(req) 14296 checkResponseCode(t, http.StatusCreated, rr) 14297 } 14298 14299 req, err := http.NewRequest(http.MethodGet, folderPath, nil) 14300 assert.NoError(t, err) 14301 setBearerForReq(req, apiToken) 14302 rr := executeRequest(req) 14303 checkResponseCode(t, http.StatusOK, rr) 14304 var foldersGet []vfs.BaseVirtualFolder 14305 err = render.DecodeJSON(rr.Body, &foldersGet) 14306 assert.NoError(t, err) 14307 numFound := 0 14308 for _, f := range foldersGet { 14309 if f.Name == folderName1 { 14310 assert.Equal(t, mappedPath1, f.MappedPath) 14311 assert.Equal(t, folderDesc1, f.Description) 14312 numFound++ 14313 } 14314 if f.Name == folderName2 { 14315 assert.Equal(t, mappedPath2, f.MappedPath) 14316 assert.Equal(t, folderDesc2, f.Description) 14317 numFound++ 14318 } 14319 } 14320 assert.Equal(t, 2, numFound) 14321 14322 req, err = http.NewRequest(http.MethodGet, webFoldersPath, nil) 14323 assert.NoError(t, err) 14324 setJWTCookieForReq(req, webToken) 14325 rr = executeRequest(req) 14326 checkResponseCode(t, http.StatusOK, rr) 14327 req, err = http.NewRequest(http.MethodGet, webFoldersPath+"?qlimit=a", nil) 14328 assert.NoError(t, err) 14329 setJWTCookieForReq(req, webToken) 14330 rr = executeRequest(req) 14331 checkResponseCode(t, http.StatusOK, rr) 14332 req, err = http.NewRequest(http.MethodGet, webFoldersPath+"?qlimit=1", nil) 14333 assert.NoError(t, err) 14334 setJWTCookieForReq(req, webToken) 14335 rr = executeRequest(req) 14336 checkResponseCode(t, http.StatusOK, rr) 14337 14338 for _, folder := range folders { 14339 req, _ := http.NewRequest(http.MethodDelete, path.Join(folderPath, folder.Name), nil) 14340 setBearerForReq(req, apiToken) 14341 rr := executeRequest(req) 14342 checkResponseCode(t, http.StatusOK, rr) 14343 } 14344} 14345 14346func TestAdminForgotPassword(t *testing.T) { 14347 smtpCfg := smtp.Config{ 14348 Host: "127.0.0.1", 14349 Port: 3525, 14350 TemplatesPath: "templates", 14351 } 14352 err := smtpCfg.Initialize("..") 14353 require.NoError(t, err) 14354 14355 a := getTestAdmin() 14356 a.Username = altAdminUsername 14357 a.Password = altAdminPassword 14358 admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated) 14359 assert.NoError(t, err) 14360 14361 req, err := http.NewRequest(http.MethodGet, webAdminForgotPwdPath, nil) 14362 assert.NoError(t, err) 14363 rr := executeRequest(req) 14364 checkResponseCode(t, http.StatusOK, rr) 14365 14366 req, err = http.NewRequest(http.MethodGet, webAdminResetPwdPath, nil) 14367 assert.NoError(t, err) 14368 rr = executeRequest(req) 14369 checkResponseCode(t, http.StatusOK, rr) 14370 14371 req, err = http.NewRequest(http.MethodGet, webLoginPath, nil) 14372 assert.NoError(t, err) 14373 rr = executeRequest(req) 14374 checkResponseCode(t, http.StatusOK, rr) 14375 14376 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 14377 assert.NoError(t, err) 14378 14379 form := make(url.Values) 14380 form.Set("username", "") 14381 // no csrf token 14382 req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14383 assert.NoError(t, err) 14384 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14385 rr = executeRequest(req) 14386 assert.Equal(t, http.StatusForbidden, rr.Code) 14387 // empty username 14388 form.Set(csrfFormToken, csrfToken) 14389 req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14390 assert.NoError(t, err) 14391 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14392 rr = executeRequest(req) 14393 assert.Equal(t, http.StatusOK, rr.Code) 14394 assert.Contains(t, rr.Body.String(), "Username is mandatory") 14395 14396 lastResetCode = "" 14397 form.Set("username", altAdminUsername) 14398 req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14399 assert.NoError(t, err) 14400 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14401 rr = executeRequest(req) 14402 assert.Equal(t, http.StatusFound, rr.Code) 14403 assert.GreaterOrEqual(t, len(lastResetCode), 20) 14404 14405 form = make(url.Values) 14406 req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14407 assert.NoError(t, err) 14408 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14409 rr = executeRequest(req) 14410 assert.Equal(t, http.StatusForbidden, rr.Code) 14411 // no password 14412 form.Set(csrfFormToken, csrfToken) 14413 req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14414 assert.NoError(t, err) 14415 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14416 rr = executeRequest(req) 14417 assert.Equal(t, http.StatusOK, rr.Code) 14418 assert.Contains(t, rr.Body.String(), "Please set a password") 14419 // no code 14420 form.Set("password", defaultPassword) 14421 req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14422 assert.NoError(t, err) 14423 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14424 rr = executeRequest(req) 14425 assert.Equal(t, http.StatusOK, rr.Code) 14426 assert.Contains(t, rr.Body.String(), "Please set a confirmation code") 14427 // ok 14428 form.Set("code", lastResetCode) 14429 req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14430 assert.NoError(t, err) 14431 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14432 rr = executeRequest(req) 14433 assert.Equal(t, http.StatusFound, rr.Code) 14434 14435 form.Set("username", altAdminUsername) 14436 req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14437 assert.NoError(t, err) 14438 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14439 rr = executeRequest(req) 14440 assert.Equal(t, http.StatusFound, rr.Code) 14441 assert.GreaterOrEqual(t, len(lastResetCode), 20) 14442 14443 // not working smtp server 14444 smtpCfg = smtp.Config{ 14445 Host: "127.0.0.1", 14446 Port: 3526, 14447 TemplatesPath: "templates", 14448 } 14449 err = smtpCfg.Initialize("..") 14450 require.NoError(t, err) 14451 14452 form = make(url.Values) 14453 form.Set("username", altAdminUsername) 14454 form.Set(csrfFormToken, csrfToken) 14455 req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14456 assert.NoError(t, err) 14457 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14458 rr = executeRequest(req) 14459 assert.Equal(t, http.StatusOK, rr.Code) 14460 assert.Contains(t, rr.Body.String(), "Unable to send confirmation code via email") 14461 14462 smtpCfg = smtp.Config{} 14463 err = smtpCfg.Initialize("..") 14464 require.NoError(t, err) 14465 14466 form.Set("username", altAdminUsername) 14467 form.Set(csrfFormToken, csrfToken) 14468 req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14469 assert.NoError(t, err) 14470 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14471 rr = executeRequest(req) 14472 assert.Equal(t, http.StatusOK, rr.Code) 14473 assert.Contains(t, rr.Body.String(), "Unable to render password reset template") 14474 14475 req, err = http.NewRequest(http.MethodGet, webAdminForgotPwdPath, nil) 14476 assert.NoError(t, err) 14477 rr = executeRequest(req) 14478 checkResponseCode(t, http.StatusNotFound, rr) 14479 14480 req, err = http.NewRequest(http.MethodGet, webAdminResetPwdPath, nil) 14481 assert.NoError(t, err) 14482 rr = executeRequest(req) 14483 checkResponseCode(t, http.StatusNotFound, rr) 14484 14485 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 14486 assert.NoError(t, err) 14487} 14488 14489func TestUserForgotPassword(t *testing.T) { 14490 smtpCfg := smtp.Config{ 14491 Host: "127.0.0.1", 14492 Port: 3525, 14493 TemplatesPath: "templates", 14494 } 14495 err := smtpCfg.Initialize("..") 14496 require.NoError(t, err) 14497 14498 u := getTestUser() 14499 u.Email = "user@test.com" 14500 u.Filters.WebClient = []string{sdk.WebClientPasswordResetDisabled} 14501 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 14502 assert.NoError(t, err) 14503 14504 req, err := http.NewRequest(http.MethodGet, webClientForgotPwdPath, nil) 14505 assert.NoError(t, err) 14506 rr := executeRequest(req) 14507 checkResponseCode(t, http.StatusOK, rr) 14508 14509 req, err = http.NewRequest(http.MethodGet, webClientResetPwdPath, nil) 14510 assert.NoError(t, err) 14511 rr = executeRequest(req) 14512 checkResponseCode(t, http.StatusOK, rr) 14513 14514 req, err = http.NewRequest(http.MethodGet, webClientLoginPath, nil) 14515 assert.NoError(t, err) 14516 rr = executeRequest(req) 14517 checkResponseCode(t, http.StatusOK, rr) 14518 14519 form := make(url.Values) 14520 form.Set("username", "") 14521 // no csrf token 14522 req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14523 assert.NoError(t, err) 14524 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14525 rr = executeRequest(req) 14526 assert.Equal(t, http.StatusForbidden, rr.Code) 14527 // empty username 14528 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 14529 assert.NoError(t, err) 14530 form.Set(csrfFormToken, csrfToken) 14531 req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14532 assert.NoError(t, err) 14533 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14534 rr = executeRequest(req) 14535 assert.Equal(t, http.StatusOK, rr.Code) 14536 assert.Contains(t, rr.Body.String(), "Username is mandatory") 14537 // user cannot reset the password 14538 form.Set("username", user.Username) 14539 req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14540 assert.NoError(t, err) 14541 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14542 rr = executeRequest(req) 14543 assert.Equal(t, http.StatusOK, rr.Code) 14544 assert.Contains(t, rr.Body.String(), "You are not allowed to reset your password") 14545 user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled} 14546 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 14547 assert.NoError(t, err) 14548 14549 lastResetCode = "" 14550 req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14551 assert.NoError(t, err) 14552 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14553 rr = executeRequest(req) 14554 assert.Equal(t, http.StatusFound, rr.Code) 14555 assert.GreaterOrEqual(t, len(lastResetCode), 20) 14556 // no csrf token 14557 form = make(url.Values) 14558 req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14559 assert.NoError(t, err) 14560 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14561 rr = executeRequest(req) 14562 assert.Equal(t, http.StatusForbidden, rr.Code) 14563 // no password 14564 form.Set(csrfFormToken, csrfToken) 14565 req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14566 assert.NoError(t, err) 14567 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14568 rr = executeRequest(req) 14569 assert.Equal(t, http.StatusOK, rr.Code) 14570 assert.Contains(t, rr.Body.String(), "Please set a password") 14571 // no code 14572 form.Set("password", altAdminPassword) 14573 req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14574 assert.NoError(t, err) 14575 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14576 rr = executeRequest(req) 14577 assert.Equal(t, http.StatusOK, rr.Code) 14578 assert.Contains(t, rr.Body.String(), "Please set a confirmation code") 14579 // ok 14580 form.Set("code", lastResetCode) 14581 req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14582 assert.NoError(t, err) 14583 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14584 rr = executeRequest(req) 14585 assert.Equal(t, http.StatusFound, rr.Code) 14586 14587 form = make(url.Values) 14588 form.Set(csrfFormToken, csrfToken) 14589 form.Set("username", user.Username) 14590 lastResetCode = "" 14591 req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14592 assert.NoError(t, err) 14593 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14594 rr = executeRequest(req) 14595 assert.Equal(t, http.StatusFound, rr.Code) 14596 assert.GreaterOrEqual(t, len(lastResetCode), 20) 14597 14598 smtpCfg = smtp.Config{} 14599 err = smtpCfg.Initialize("..") 14600 require.NoError(t, err) 14601 14602 req, err = http.NewRequest(http.MethodGet, webClientForgotPwdPath, nil) 14603 assert.NoError(t, err) 14604 rr = executeRequest(req) 14605 checkResponseCode(t, http.StatusNotFound, rr) 14606 14607 req, err = http.NewRequest(http.MethodGet, webClientResetPwdPath, nil) 14608 assert.NoError(t, err) 14609 rr = executeRequest(req) 14610 checkResponseCode(t, http.StatusNotFound, rr) 14611 14612 _, err = httpdtest.RemoveUser(user, http.StatusOK) 14613 assert.NoError(t, err) 14614 err = os.RemoveAll(user.GetHomeDir()) 14615 assert.NoError(t, err) 14616 // user does not exist anymore 14617 form = make(url.Values) 14618 form.Set(csrfFormToken, csrfToken) 14619 form.Set("code", lastResetCode) 14620 form.Set("password", "pwd") 14621 req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode()))) 14622 assert.NoError(t, err) 14623 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 14624 rr = executeRequest(req) 14625 assert.Equal(t, http.StatusOK, rr.Code) 14626 assert.Contains(t, rr.Body.String(), "Unable to associate the confirmation code with an existing user") 14627} 14628 14629func TestAPIForgotPassword(t *testing.T) { 14630 smtpCfg := smtp.Config{ 14631 Host: "127.0.0.1", 14632 Port: 3525, 14633 TemplatesPath: "templates", 14634 } 14635 err := smtpCfg.Initialize("..") 14636 require.NoError(t, err) 14637 14638 a := getTestAdmin() 14639 a.Username = altAdminUsername 14640 a.Password = altAdminPassword 14641 a.Email = "" 14642 admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated) 14643 assert.NoError(t, err) 14644 // no email, forgot pwd will not work 14645 lastResetCode = "" 14646 req, err := http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/forgot-password"), nil) 14647 assert.NoError(t, err) 14648 rr := executeRequest(req) 14649 checkResponseCode(t, http.StatusBadRequest, rr) 14650 assert.Contains(t, rr.Body.String(), "Your account does not have an email address") 14651 14652 admin.Email = "admin@test.com" 14653 admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) 14654 assert.NoError(t, err) 14655 14656 req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/forgot-password"), nil) 14657 assert.NoError(t, err) 14658 rr = executeRequest(req) 14659 checkResponseCode(t, http.StatusOK, rr) 14660 assert.GreaterOrEqual(t, len(lastResetCode), 20) 14661 14662 // invalid JSON 14663 req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/reset-password"), bytes.NewBuffer([]byte(`{`))) 14664 assert.NoError(t, err) 14665 rr = executeRequest(req) 14666 checkResponseCode(t, http.StatusBadRequest, rr) 14667 14668 resetReq := make(map[string]string) 14669 resetReq["code"] = lastResetCode 14670 resetReq["password"] = defaultPassword 14671 asJSON, err := json.Marshal(resetReq) 14672 assert.NoError(t, err) 14673 14674 // a user cannot use an admin code 14675 req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer(asJSON)) 14676 assert.NoError(t, err) 14677 rr = executeRequest(req) 14678 checkResponseCode(t, http.StatusBadRequest, rr) 14679 assert.Contains(t, rr.Body.String(), "Invalid confirmation code") 14680 14681 req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/reset-password"), bytes.NewBuffer(asJSON)) 14682 assert.NoError(t, err) 14683 rr = executeRequest(req) 14684 checkResponseCode(t, http.StatusOK, rr) 14685 14686 // the same code cannot be reused 14687 req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/reset-password"), bytes.NewBuffer(asJSON)) 14688 assert.NoError(t, err) 14689 rr = executeRequest(req) 14690 checkResponseCode(t, http.StatusBadRequest, rr) 14691 assert.Contains(t, rr.Body.String(), "Confirmation code not found") 14692 14693 admin, err = dataprovider.AdminExists(altAdminUsername) 14694 assert.NoError(t, err) 14695 14696 match, err := admin.CheckPassword(defaultPassword) 14697 assert.NoError(t, err) 14698 assert.True(t, match) 14699 lastResetCode = "" 14700 // now the same for a user 14701 u := getTestUser() 14702 user, _, err := httpdtest.AddUser(u, http.StatusCreated) 14703 assert.NoError(t, err) 14704 req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/forgot-password"), nil) 14705 assert.NoError(t, err) 14706 rr = executeRequest(req) 14707 checkResponseCode(t, http.StatusBadRequest, rr) 14708 assert.Contains(t, rr.Body.String(), "Your account does not have an email address") 14709 14710 user.Email = "user@test.com" 14711 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 14712 assert.NoError(t, err) 14713 req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/forgot-password"), nil) 14714 assert.NoError(t, err) 14715 rr = executeRequest(req) 14716 checkResponseCode(t, http.StatusOK, rr) 14717 assert.GreaterOrEqual(t, len(lastResetCode), 20) 14718 14719 // invalid JSON 14720 req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer([]byte(`{`))) 14721 assert.NoError(t, err) 14722 rr = executeRequest(req) 14723 checkResponseCode(t, http.StatusBadRequest, rr) 14724 // remove the reset password permission 14725 user.Filters.WebClient = []string{sdk.WebClientPasswordResetDisabled} 14726 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 14727 assert.NoError(t, err) 14728 14729 resetReq["code"] = lastResetCode 14730 resetReq["password"] = altAdminPassword 14731 asJSON, err = json.Marshal(resetReq) 14732 assert.NoError(t, err) 14733 req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer(asJSON)) 14734 assert.NoError(t, err) 14735 rr = executeRequest(req) 14736 checkResponseCode(t, http.StatusBadRequest, rr) 14737 assert.Contains(t, rr.Body.String(), "You are not allowed to reset your password") 14738 14739 user.Filters.WebClient = []string{sdk.WebClientSharesDisabled} 14740 _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") 14741 assert.NoError(t, err) 14742 req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer(asJSON)) 14743 assert.NoError(t, err) 14744 rr = executeRequest(req) 14745 checkResponseCode(t, http.StatusOK, rr) 14746 // the same code cannot be reused 14747 req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer(asJSON)) 14748 assert.NoError(t, err) 14749 rr = executeRequest(req) 14750 checkResponseCode(t, http.StatusBadRequest, rr) 14751 assert.Contains(t, rr.Body.String(), "Confirmation code not found") 14752 14753 user, err = dataprovider.UserExists(defaultUsername) 14754 assert.NoError(t, err) 14755 err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(altAdminPassword)) 14756 assert.NoError(t, err) 14757 14758 lastResetCode = "" 14759 // a request for a missing admin/user will be silently ignored 14760 req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, "missing-admin", "/forgot-password"), nil) 14761 assert.NoError(t, err) 14762 rr = executeRequest(req) 14763 checkResponseCode(t, http.StatusOK, rr) 14764 assert.Empty(t, lastResetCode) 14765 14766 req, err = http.NewRequest(http.MethodPost, path.Join(userPath, "missing-user", "/forgot-password"), nil) 14767 assert.NoError(t, err) 14768 rr = executeRequest(req) 14769 checkResponseCode(t, http.StatusOK, rr) 14770 assert.Empty(t, lastResetCode) 14771 14772 lastResetCode = "" 14773 req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/forgot-password"), nil) 14774 assert.NoError(t, err) 14775 rr = executeRequest(req) 14776 checkResponseCode(t, http.StatusOK, rr) 14777 assert.GreaterOrEqual(t, len(lastResetCode), 20) 14778 14779 smtpCfg = smtp.Config{} 14780 err = smtpCfg.Initialize("..") 14781 require.NoError(t, err) 14782 14783 // without an smtp configuration reset password is not available 14784 req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/forgot-password"), nil) 14785 assert.NoError(t, err) 14786 rr = executeRequest(req) 14787 checkResponseCode(t, http.StatusBadRequest, rr) 14788 assert.Contains(t, rr.Body.String(), "No SMTP configuration") 14789 14790 req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/forgot-password"), nil) 14791 assert.NoError(t, err) 14792 rr = executeRequest(req) 14793 checkResponseCode(t, http.StatusBadRequest, rr) 14794 assert.Contains(t, rr.Body.String(), "No SMTP configuration") 14795 14796 _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) 14797 assert.NoError(t, err) 14798 // the admin does not exist anymore 14799 resetReq["code"] = lastResetCode 14800 resetReq["password"] = altAdminPassword 14801 asJSON, err = json.Marshal(resetReq) 14802 assert.NoError(t, err) 14803 req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/reset-password"), bytes.NewBuffer(asJSON)) 14804 assert.NoError(t, err) 14805 rr = executeRequest(req) 14806 checkResponseCode(t, http.StatusBadRequest, rr) 14807 assert.Contains(t, rr.Body.String(), "Unable to associate the confirmation code with an existing admin") 14808 14809 _, err = httpdtest.RemoveUser(user, http.StatusOK) 14810 assert.NoError(t, err) 14811 err = os.RemoveAll(user.GetHomeDir()) 14812 assert.NoError(t, err) 14813} 14814 14815func TestProviderClosedMock(t *testing.T) { 14816 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 14817 assert.NoError(t, err) 14818 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 14819 assert.NoError(t, err) 14820 dataprovider.Close() 14821 req, _ := http.NewRequest(http.MethodGet, webFoldersPath, nil) 14822 setJWTCookieForReq(req, token) 14823 rr := executeRequest(req) 14824 checkResponseCode(t, http.StatusInternalServerError, rr) 14825 req, _ = http.NewRequest(http.MethodGet, webUsersPath, nil) 14826 setJWTCookieForReq(req, token) 14827 rr = executeRequest(req) 14828 checkResponseCode(t, http.StatusInternalServerError, rr) 14829 req, _ = http.NewRequest(http.MethodGet, webUserPath+"/0", nil) 14830 setJWTCookieForReq(req, token) 14831 rr = executeRequest(req) 14832 checkResponseCode(t, http.StatusInternalServerError, rr) 14833 form := make(url.Values) 14834 form.Set(csrfFormToken, csrfToken) 14835 form.Set("username", "test") 14836 req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", strings.NewReader(form.Encode())) 14837 setJWTCookieForReq(req, token) 14838 rr = executeRequest(req) 14839 checkResponseCode(t, http.StatusInternalServerError, rr) 14840 req, _ = http.NewRequest(http.MethodGet, path.Join(webAdminPath, defaultTokenAuthUser), nil) 14841 setJWTCookieForReq(req, token) 14842 rr = executeRequest(req) 14843 checkResponseCode(t, http.StatusInternalServerError, rr) 14844 14845 req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, defaultTokenAuthUser), strings.NewReader(form.Encode())) 14846 setJWTCookieForReq(req, token) 14847 rr = executeRequest(req) 14848 checkResponseCode(t, http.StatusInternalServerError, rr) 14849 14850 req, _ = http.NewRequest(http.MethodGet, webAdminsPath, nil) 14851 setJWTCookieForReq(req, token) 14852 rr = executeRequest(req) 14853 checkResponseCode(t, http.StatusInternalServerError, rr) 14854 14855 req, _ = http.NewRequest(http.MethodGet, path.Join(webFolderPath, defaultTokenAuthUser), nil) 14856 setJWTCookieForReq(req, token) 14857 rr = executeRequest(req) 14858 checkResponseCode(t, http.StatusInternalServerError, rr) 14859 14860 req, _ = http.NewRequest(http.MethodPost, path.Join(webFolderPath, defaultTokenAuthUser), strings.NewReader(form.Encode())) 14861 setJWTCookieForReq(req, token) 14862 rr = executeRequest(req) 14863 checkResponseCode(t, http.StatusInternalServerError, rr) 14864 14865 err = config.LoadConfig(configDir, "") 14866 assert.NoError(t, err) 14867 providerConf := config.GetProviderConf() 14868 providerConf.CredentialsPath = credentialsPath 14869 err = os.RemoveAll(credentialsPath) 14870 assert.NoError(t, err) 14871 err = dataprovider.Initialize(providerConf, configDir, true) 14872 assert.NoError(t, err) 14873} 14874 14875func TestWebConnectionsMock(t *testing.T) { 14876 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 14877 assert.NoError(t, err) 14878 req, _ := http.NewRequest(http.MethodGet, webConnectionsPath, nil) 14879 setJWTCookieForReq(req, token) 14880 rr := executeRequest(req) 14881 checkResponseCode(t, http.StatusOK, rr) 14882 14883 req, _ = http.NewRequest(http.MethodDelete, path.Join(webConnectionsPath, "id"), nil) 14884 setJWTCookieForReq(req, token) 14885 rr = executeRequest(req) 14886 checkResponseCode(t, http.StatusForbidden, rr) 14887 assert.Contains(t, rr.Body.String(), "Invalid token") 14888 14889 req, _ = http.NewRequest(http.MethodDelete, path.Join(webConnectionsPath, "id"), nil) 14890 setJWTCookieForReq(req, token) 14891 setCSRFHeaderForReq(req, "csrfToken") 14892 rr = executeRequest(req) 14893 checkResponseCode(t, http.StatusForbidden, rr) 14894 assert.Contains(t, rr.Body.String(), "Invalid token") 14895 14896 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 14897 assert.NoError(t, err) 14898 req, _ = http.NewRequest(http.MethodDelete, path.Join(webConnectionsPath, "id"), nil) 14899 setJWTCookieForReq(req, token) 14900 setCSRFHeaderForReq(req, csrfToken) 14901 rr = executeRequest(req) 14902 checkResponseCode(t, http.StatusNotFound, rr) 14903} 14904 14905func TestGetWebStatusMock(t *testing.T) { 14906 token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) 14907 assert.NoError(t, err) 14908 req, _ := http.NewRequest(http.MethodGet, webStatusPath, nil) 14909 setJWTCookieForReq(req, token) 14910 rr := executeRequest(req) 14911 checkResponseCode(t, http.StatusOK, rr) 14912} 14913 14914func TestStaticFilesMock(t *testing.T) { 14915 req, err := http.NewRequest(http.MethodGet, "/static/favicon.ico", nil) 14916 assert.NoError(t, err) 14917 rr := executeRequest(req) 14918 checkResponseCode(t, http.StatusOK, rr) 14919 14920 req, err = http.NewRequest(http.MethodGet, "/openapi/openapi.yaml", nil) 14921 assert.NoError(t, err) 14922 rr = executeRequest(req) 14923 checkResponseCode(t, http.StatusOK, rr) 14924 14925 req, err = http.NewRequest(http.MethodGet, "/static", nil) 14926 assert.NoError(t, err) 14927 rr = executeRequest(req) 14928 checkResponseCode(t, http.StatusMovedPermanently, rr) 14929 location := rr.Header().Get("Location") 14930 assert.Equal(t, "/static/", location) 14931 req, err = http.NewRequest(http.MethodGet, location, nil) 14932 assert.NoError(t, err) 14933 rr = executeRequest(req) 14934 checkResponseCode(t, http.StatusOK, rr) 14935 14936 req, err = http.NewRequest(http.MethodGet, "/openapi", nil) 14937 assert.NoError(t, err) 14938 rr = executeRequest(req) 14939 checkResponseCode(t, http.StatusMovedPermanently, rr) 14940 location = rr.Header().Get("Location") 14941 assert.Equal(t, "/openapi/", location) 14942 req, err = http.NewRequest(http.MethodGet, location, nil) 14943 assert.NoError(t, err) 14944 rr = executeRequest(req) 14945 checkResponseCode(t, http.StatusOK, rr) 14946} 14947 14948func waitForUsersQuotaScan(t *testing.T, token string) { 14949 for { 14950 var scans []common.ActiveQuotaScan 14951 req, _ := http.NewRequest(http.MethodGet, quotaScanPath, nil) 14952 setBearerForReq(req, token) 14953 rr := executeRequest(req) 14954 checkResponseCode(t, http.StatusOK, rr) 14955 err := render.DecodeJSON(rr.Body, &scans) 14956 14957 if !assert.NoError(t, err, "Error getting active scans") { 14958 break 14959 } 14960 if len(scans) == 0 { 14961 break 14962 } 14963 time.Sleep(100 * time.Millisecond) 14964 } 14965} 14966 14967func waitForFoldersQuotaScanPath(t *testing.T, token string) { 14968 var scans []common.ActiveVirtualFolderQuotaScan 14969 for { 14970 req, _ := http.NewRequest(http.MethodGet, quotaScanVFolderPath, nil) 14971 setBearerForReq(req, token) 14972 rr := executeRequest(req) 14973 checkResponseCode(t, http.StatusOK, rr) 14974 err := render.DecodeJSON(rr.Body, &scans) 14975 if !assert.NoError(t, err, "Error getting active folders scans") { 14976 break 14977 } 14978 if len(scans) == 0 { 14979 break 14980 } 14981 time.Sleep(100 * time.Millisecond) 14982 } 14983} 14984 14985func waitTCPListening(address string) { 14986 for { 14987 conn, err := net.Dial("tcp", address) 14988 if err != nil { 14989 logger.WarnToConsole("tcp server %v not listening: %v", address, err) 14990 time.Sleep(100 * time.Millisecond) 14991 continue 14992 } 14993 logger.InfoToConsole("tcp server %v now listening", address) 14994 conn.Close() 14995 break 14996 } 14997} 14998 14999func startSMTPServer() { 15000 go func() { 15001 if err := smtpd.ListenAndServe(smtpServerAddr, func(remoteAddr net.Addr, from string, to []string, data []byte) error { 15002 re := regexp.MustCompile(`code is ".*?"`) 15003 code := strings.TrimPrefix(string(re.Find(data)), "code is ") 15004 lastResetCode = strings.ReplaceAll(code, "\"", "") 15005 return nil 15006 }, "SFTPGo test", "localhost"); err != nil { 15007 logger.ErrorToConsole("could not start SMTP server: %v", err) 15008 os.Exit(1) 15009 } 15010 }() 15011 waitTCPListening(smtpServerAddr) 15012} 15013 15014func getTestAdmin() dataprovider.Admin { 15015 return dataprovider.Admin{ 15016 Username: defaultTokenAuthUser, 15017 Password: defaultTokenAuthPass, 15018 Status: 1, 15019 Permissions: []string{dataprovider.PermAdminAny}, 15020 Email: "admin@example.com", 15021 Description: "test admin", 15022 } 15023} 15024 15025func getTestUser() dataprovider.User { 15026 user := dataprovider.User{ 15027 BaseUser: sdk.BaseUser{ 15028 Username: defaultUsername, 15029 Password: defaultPassword, 15030 HomeDir: filepath.Join(homeBasePath, defaultUsername), 15031 Status: 1, 15032 Description: "test user", 15033 }, 15034 } 15035 user.Permissions = make(map[string][]string) 15036 user.Permissions["/"] = defaultPerms 15037 return user 15038} 15039 15040func getTestSFTPUser() dataprovider.User { 15041 u := getTestUser() 15042 u.Username = u.Username + "_sftp" 15043 u.FsConfig.Provider = sdk.SFTPFilesystemProvider 15044 u.FsConfig.SFTPConfig.Endpoint = sftpServerAddr 15045 u.FsConfig.SFTPConfig.Username = defaultUsername 15046 u.FsConfig.SFTPConfig.Password = kms.NewPlainSecret(defaultPassword) 15047 return u 15048} 15049 15050func getUserAsJSON(t *testing.T, user dataprovider.User) []byte { 15051 json, err := json.Marshal(user) 15052 assert.NoError(t, err) 15053 return json 15054} 15055 15056func getCSRFToken(url string) (string, error) { 15057 req, err := http.NewRequest(http.MethodGet, url, nil) 15058 if err != nil { 15059 return "", err 15060 } 15061 resp, err := httpclient.GetHTTPClient().Do(req) 15062 if err != nil { 15063 return "", err 15064 } 15065 15066 defer resp.Body.Close() 15067 15068 doc, err := html.Parse(resp.Body) 15069 if err != nil { 15070 return "", err 15071 } 15072 15073 var csrfToken string 15074 var f func(*html.Node) 15075 15076 f = func(n *html.Node) { 15077 if n.Type == html.ElementNode && n.Data == "input" { 15078 var name, value string 15079 for _, attr := range n.Attr { 15080 if attr.Key == "value" { 15081 value = attr.Val 15082 } 15083 if attr.Key == "name" { 15084 name = attr.Val 15085 } 15086 } 15087 if name == csrfFormToken { 15088 csrfToken = value 15089 return 15090 } 15091 } 15092 15093 for c := n.FirstChild; c != nil; c = c.NextSibling { 15094 f(c) 15095 } 15096 } 15097 15098 f(doc) 15099 15100 return csrfToken, nil 15101} 15102 15103func getLoginForm(username, password, csrfToken string) url.Values { 15104 form := make(url.Values) 15105 form.Set("username", username) 15106 form.Set("password", password) 15107 form.Set(csrfFormToken, csrfToken) 15108 return form 15109} 15110 15111func setCSRFHeaderForReq(req *http.Request, csrfToken string) { 15112 req.Header.Set("X-CSRF-TOKEN", csrfToken) 15113} 15114 15115func setBearerForReq(req *http.Request, jwtToken string) { 15116 req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", jwtToken)) 15117} 15118 15119func setAPIKeyForReq(req *http.Request, apiKey, username string) { 15120 if username != "" { 15121 apiKey += "." + username 15122 } 15123 req.Header.Set("X-SFTPGO-API-KEY", apiKey) 15124} 15125 15126func setJWTCookieForReq(req *http.Request, jwtToken string) { 15127 req.Header.Set("Cookie", fmt.Sprintf("jwt=%v", jwtToken)) 15128} 15129 15130func getJWTAPITokenFromTestServer(username, password string) (string, error) { 15131 req, _ := http.NewRequest(http.MethodGet, tokenPath, nil) 15132 req.SetBasicAuth(username, password) 15133 rr := executeRequest(req) 15134 if rr.Code != http.StatusOK { 15135 return "", fmt.Errorf("unexpected status code %v", rr.Code) 15136 } 15137 responseHolder := make(map[string]interface{}) 15138 err := render.DecodeJSON(rr.Body, &responseHolder) 15139 if err != nil { 15140 return "", err 15141 } 15142 return responseHolder["access_token"].(string), nil 15143} 15144 15145func getJWTAPIUserTokenFromTestServer(username, password string) (string, error) { 15146 req, _ := http.NewRequest(http.MethodGet, userTokenPath, nil) 15147 req.SetBasicAuth(username, password) 15148 rr := executeRequest(req) 15149 if rr.Code != http.StatusOK { 15150 return "", fmt.Errorf("unexpected status code %v", rr.Code) 15151 } 15152 responseHolder := make(map[string]interface{}) 15153 err := render.DecodeJSON(rr.Body, &responseHolder) 15154 if err != nil { 15155 return "", err 15156 } 15157 return responseHolder["access_token"].(string), nil 15158} 15159 15160func getJWTWebToken(username, password string) (string, error) { 15161 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 15162 if err != nil { 15163 return "", err 15164 } 15165 form := getLoginForm(username, password, csrfToken) 15166 req, _ := http.NewRequest(http.MethodPost, httpBaseURL+webLoginPath, 15167 bytes.NewBuffer([]byte(form.Encode()))) 15168 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 15169 client := &http.Client{ 15170 Timeout: 10 * time.Second, 15171 CheckRedirect: func(req *http.Request, via []*http.Request) error { 15172 return http.ErrUseLastResponse 15173 }, 15174 } 15175 resp, err := client.Do(req) 15176 if err != nil { 15177 return "", err 15178 } 15179 defer resp.Body.Close() 15180 15181 if resp.StatusCode != http.StatusFound { 15182 return "", fmt.Errorf("unexpected status code %v", resp.StatusCode) 15183 } 15184 cookie := resp.Header.Get("Set-Cookie") 15185 if strings.HasPrefix(cookie, "jwt=") { 15186 return cookie[4:], nil 15187 } 15188 return "", errors.New("no cookie found") 15189} 15190 15191func getJWTWebClientTokenFromTestServerWithAddr(username, password, remoteAddr string) (string, error) { 15192 csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath) 15193 if err != nil { 15194 return "", err 15195 } 15196 form := getLoginForm(username, password, csrfToken) 15197 req, _ := http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 15198 req.RemoteAddr = remoteAddr 15199 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 15200 rr := executeRequest(req) 15201 if rr.Code != http.StatusFound { 15202 return "", fmt.Errorf("unexpected status code %v", rr) 15203 } 15204 return getCookieFromResponse(rr) 15205} 15206 15207func getCookieFromResponse(rr *httptest.ResponseRecorder) (string, error) { 15208 cookie := strings.Split(rr.Header().Get("Set-Cookie"), ";") 15209 if strings.HasPrefix(cookie[0], "jwt=") { 15210 return cookie[0][4:], nil 15211 } 15212 return "", errors.New("no cookie found") 15213} 15214 15215func getJWTWebClientTokenFromTestServer(username, password string) (string, error) { 15216 return getJWTWebClientTokenFromTestServerWithAddr(username, password, "") 15217} 15218 15219func getJWTWebTokenFromTestServer(username, password string) (string, error) { 15220 csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) 15221 if err != nil { 15222 return "", err 15223 } 15224 form := getLoginForm(username, password, csrfToken) 15225 req, _ := http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode()))) 15226 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 15227 rr := executeRequest(req) 15228 if rr.Code != http.StatusFound { 15229 return "", fmt.Errorf("unexpected status code %v", rr) 15230 } 15231 return getCookieFromResponse(rr) 15232} 15233 15234func executeRequest(req *http.Request) *httptest.ResponseRecorder { 15235 rr := httptest.NewRecorder() 15236 testServer.Config.Handler.ServeHTTP(rr, req) 15237 return rr 15238} 15239 15240func checkResponseCode(t *testing.T, expected int, rr *httptest.ResponseRecorder) { 15241 assert.Equal(t, expected, rr.Code, rr.Body.String()) 15242} 15243 15244func createTestFile(path string, size int64) error { 15245 baseDir := filepath.Dir(path) 15246 if _, err := os.Stat(baseDir); os.IsNotExist(err) { 15247 err = os.MkdirAll(baseDir, os.ModePerm) 15248 if err != nil { 15249 return err 15250 } 15251 } 15252 content := make([]byte, size) 15253 if size > 0 { 15254 _, err := rand.Read(content) 15255 if err != nil { 15256 return err 15257 } 15258 } 15259 return os.WriteFile(path, content, os.ModePerm) 15260} 15261 15262func getExitCodeScriptContent(exitCode int) []byte { 15263 content := []byte("#!/bin/sh\n\n") 15264 content = append(content, []byte(fmt.Sprintf("exit %v", exitCode))...) 15265 return content 15266} 15267 15268func getMultipartFormData(values url.Values, fileFieldName, filePath string) (bytes.Buffer, string, error) { 15269 var b bytes.Buffer 15270 w := multipart.NewWriter(&b) 15271 for k, v := range values { 15272 for _, s := range v { 15273 if err := w.WriteField(k, s); err != nil { 15274 return b, "", err 15275 } 15276 } 15277 } 15278 if len(fileFieldName) > 0 && len(filePath) > 0 { 15279 fw, err := w.CreateFormFile(fileFieldName, filepath.Base(filePath)) 15280 if err != nil { 15281 return b, "", err 15282 } 15283 f, err := os.Open(filePath) 15284 if err != nil { 15285 return b, "", err 15286 } 15287 defer f.Close() 15288 if _, err = io.Copy(fw, f); err != nil { 15289 return b, "", err 15290 } 15291 } 15292 err := w.Close() 15293 return b, w.FormDataContentType(), err 15294} 15295 15296func generateTOTPPasscode(secret string) (string, error) { 15297 return totp.GenerateCodeCustom(secret, time.Now(), totp.ValidateOpts{ 15298 Period: 30, 15299 Skew: 1, 15300 Digits: otp.DigitsSix, 15301 Algorithm: otp.AlgorithmSHA1, 15302 }) 15303} 15304 15305func BenchmarkSecretDecryption(b *testing.B) { 15306 s := kms.NewPlainSecret("test data") 15307 s.SetAdditionalData("username") 15308 err := s.Encrypt() 15309 require.NoError(b, err) 15310 for i := 0; i < b.N; i++ { 15311 err = s.Clone().Decrypt() 15312 require.NoError(b, err) 15313 } 15314} 15315