enforce CSRF token usage by the same IP for which it was issued

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2022-03-26 08:41:50 +01:00
parent 853086b942
commit aaf940edab
No known key found for this signature in database
GPG key ID: 2F1FB59433D5A8CB
8 changed files with 457 additions and 186 deletions

View file

@ -49,16 +49,19 @@ type jwtTokenClaims struct {
Username string
Permissions []string
Signature string
Audience string
Audience []string
APIKeyID string
MustSetTwoFactorAuth bool
RequiredTwoFactorProtocols []string
}
func (c *jwtTokenClaims) hasUserAudience() bool {
if c.Audience == tokenAudienceWebClient || c.Audience == tokenAudienceAPIUser {
return true
for _, audience := range c.Audience {
if audience == tokenAudienceWebClient || audience == tokenAudienceAPIUser {
return true
}
}
return false
}
@ -97,9 +100,7 @@ func (c *jwtTokenClaims) Decode(token map[string]interface{}) {
switch v := audience.(type) {
case []string:
if len(v) > 0 {
c.Audience = v[0]
}
c.Audience = v
}
if val, ok := token[claimAPIKey]; ok {
@ -163,10 +164,10 @@ func (c *jwtTokenClaims) createToken(tokenAuth *jwtauth.JWTAuth, audience tokenA
claims := c.asMap()
now := time.Now().UTC()
claims[jwt.JwtIDKey] = fmt.Sprintf("%s%s", xid.New().String(), ip)
claims[jwt.JwtIDKey] = xid.New().String()
claims[jwt.NotBeforeKey] = now.Add(-30 * time.Second)
claims[jwt.ExpirationKey] = now.Add(tokenDuration)
claims[jwt.AudienceKey] = audience
claims[jwt.AudienceKey] = []string{audience, ip}
return tokenAuth.Encode(claims)
}
@ -299,14 +300,14 @@ func getAdminFromToken(r *http.Request) *dataprovider.Admin {
return admin
}
func createCSRFToken() string {
func createCSRFToken(ip string) string {
claims := make(map[string]interface{})
now := time.Now().UTC()
claims[jwt.JwtIDKey] = xid.New().String()
claims[jwt.NotBeforeKey] = now.Add(-30 * time.Second)
claims[jwt.ExpirationKey] = now.Add(csrfTokenDuration)
claims[jwt.AudienceKey] = tokenAudienceCSRF
claims[jwt.AudienceKey] = []string{tokenAudienceCSRF, ip}
_, tokenString, err := csrfTokenAuth.Encode(claims)
if err != nil {
@ -316,7 +317,7 @@ func createCSRFToken() string {
return tokenString
}
func verifyCSRFToken(tokenString string) error {
func verifyCSRFToken(tokenString, ip string) error {
token, err := jwtauth.VerifyToken(csrfTokenAuth, tokenString)
if err != nil || token == nil {
logger.Debug(logSender, "", "error validating CSRF token %#v: %v", tokenString, err)
@ -328,5 +329,10 @@ func verifyCSRFToken(tokenString string) error {
return errors.New("the form token is not valid")
}
if !util.IsStringInSlice(ip, token.Audience()) {
logger.Debug(logSender, "", "error validating CSRF token IP audience")
return errors.New("the form token is not valid")
}
return nil
}

File diff suppressed because it is too large Load diff

View file

@ -633,7 +633,7 @@ func TestUpdateWebAdminInvalidClaims(t *testing.T) {
assert.NoError(t, err)
form := make(url.Values)
form.Set(csrfFormToken, createCSRFToken())
form.Set(csrfFormToken, createCSRFToken(""))
form.Set("status", "1")
req, _ := http.NewRequest(http.MethodPost, path.Join(webAdminPath, "admin"), bytes.NewBuffer([]byte(form.Encode())))
rctx := chi.NewRouteContext()
@ -688,7 +688,7 @@ func TestRetentionInvalidTokenClaims(t *testing.T) {
func TestCSRFToken(t *testing.T) {
// invalid token
err := verifyCSRFToken("token")
err := verifyCSRFToken("token", "")
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "unable to verify form token")
}
@ -699,15 +699,29 @@ func TestCSRFToken(t *testing.T) {
claims[jwt.JwtIDKey] = xid.New().String()
claims[jwt.NotBeforeKey] = now.Add(-30 * time.Second)
claims[jwt.ExpirationKey] = now.Add(tokenDuration)
claims[jwt.AudienceKey] = tokenAudienceAPI
claims[jwt.AudienceKey] = []string{tokenAudienceAPI}
_, tokenString, err := csrfTokenAuth.Encode(claims)
assert.NoError(t, err)
err = verifyCSRFToken(tokenString)
err = verifyCSRFToken(tokenString, "")
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "form token is not valid")
}
// bad IP
tokenString = createCSRFToken("127.1.1.1")
err = verifyCSRFToken(tokenString, "127.1.1.2")
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "form token is not valid")
}
claims[jwt.JwtIDKey] = xid.New().String()
claims[jwt.NotBeforeKey] = now.Add(-30 * time.Second)
claims[jwt.ExpirationKey] = now.Add(tokenDuration)
claims[jwt.AudienceKey] = []string{tokenAudienceAPI}
_, tokenString, err = csrfTokenAuth.Encode(claims)
assert.NoError(t, err)
r := GetHTTPRouter(Binding{
Address: "",
Port: 8080,
@ -722,6 +736,15 @@ func TestCSRFToken(t *testing.T) {
assert.Equal(t, http.StatusForbidden, rr.Code)
assert.Contains(t, rr.Body.String(), "Invalid token")
// invalid audience
req.Header.Set(csrfHeaderToken, tokenString)
rr = httptest.NewRecorder()
fn.ServeHTTP(rr, req)
assert.Equal(t, http.StatusForbidden, rr.Code)
assert.Contains(t, rr.Body.String(), "the token is not valid")
// invalid IP
tokenString = createCSRFToken("172.16.1.2")
req.Header.Set(csrfHeaderToken, tokenString)
rr = httptest.NewRecorder()
fn.ServeHTTP(rr, req)
@ -729,7 +752,7 @@ func TestCSRFToken(t *testing.T) {
assert.Contains(t, rr.Body.String(), "the token is not valid")
csrfTokenAuth = jwtauth.New("PS256", util.GenerateRandomBytes(32), nil)
tokenString = createCSRFToken()
tokenString = createCSRFToken("")
assert.Empty(t, tokenString)
csrfTokenAuth = jwtauth.New(jwa.HS256.String(), util.GenerateRandomBytes(32), nil)
@ -765,7 +788,7 @@ func TestCreateTokenError(t *testing.T) {
form := make(url.Values)
form.Set("username", admin.Username)
form.Set("password", admin.Password)
form.Set(csrfFormToken, createCSRFToken())
form.Set(csrfFormToken, createCSRFToken("127.0.0.1"))
req, _ = http.NewRequest(http.MethodPost, webAdminLoginPath, bytes.NewBuffer([]byte(form.Encode())))
req.RemoteAddr = "127.0.0.1:1234"
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
@ -905,7 +928,7 @@ func TestCreateTokenError(t *testing.T) {
form = make(url.Values)
form.Set("username", user.Username)
form.Set("password", "clientpwd")
form.Set(csrfFormToken, createCSRFToken())
form.Set(csrfFormToken, createCSRFToken("127.0.0.1"))
req, _ = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
req.RemoteAddr = "127.0.0.1:4567"
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
@ -1086,7 +1109,7 @@ func TestCookieExpiration(t *testing.T) {
claims[claimPermissionsKey] = admin.Permissions
claims[jwt.SubjectKey] = admin.GetSignature()
claims[jwt.ExpirationKey] = time.Now().Add(1 * time.Minute)
claims[jwt.AudienceKey] = tokenAudienceAPI
claims[jwt.AudienceKey] = []string{tokenAudienceAPI}
token, _, err = server.tokenAuth.Encode(claims)
assert.NoError(t, err)
req, _ = http.NewRequest(http.MethodGet, tokenPath, nil)
@ -1121,7 +1144,7 @@ func TestCookieExpiration(t *testing.T) {
claims[claimPermissionsKey] = admin.Permissions
claims[jwt.SubjectKey] = admin.GetSignature()
claims[jwt.ExpirationKey] = time.Now().Add(1 * time.Minute)
claims[jwt.AudienceKey] = tokenAudienceAPI
claims[jwt.AudienceKey] = []string{tokenAudienceAPI}
token, _, err = server.tokenAuth.Encode(claims)
assert.NoError(t, err)
req, _ = http.NewRequest(http.MethodGet, tokenPath, nil)
@ -1159,7 +1182,7 @@ func TestCookieExpiration(t *testing.T) {
claims[claimPermissionsKey] = user.Filters.WebClient
claims[jwt.SubjectKey] = user.GetSignature()
claims[jwt.ExpirationKey] = time.Now().Add(1 * time.Minute)
claims[jwt.AudienceKey] = tokenAudienceWebClient
claims[jwt.AudienceKey] = []string{tokenAudienceWebClient}
token, _, err = server.tokenAuth.Encode(claims)
assert.NoError(t, err)
@ -1191,7 +1214,7 @@ func TestCookieExpiration(t *testing.T) {
claims[claimPermissionsKey] = user.Filters.WebClient
claims[jwt.SubjectKey] = user.GetSignature()
claims[jwt.ExpirationKey] = time.Now().Add(1 * time.Minute)
claims[jwt.AudienceKey] = tokenAudienceWebClient
claims[jwt.AudienceKey] = []string{tokenAudienceWebClient}
token, _, err = server.tokenAuth.Encode(claims)
assert.NoError(t, err)
@ -1520,7 +1543,7 @@ func TestProxyHeaders(t *testing.T) {
form := make(url.Values)
form.Set("username", username)
form.Set("password", password)
form.Set(csrfFormToken, createCSRFToken())
form.Set(csrfFormToken, createCSRFToken(testIP))
req, err = http.NewRequest(http.MethodPost, webAdminLoginPath, bytes.NewBuffer([]byte(form.Encode())))
assert.NoError(t, err)
req.RemoteAddr = testIP
@ -1530,6 +1553,7 @@ func TestProxyHeaders(t *testing.T) {
assert.Equal(t, http.StatusOK, rr.Code, rr.Body.String())
assert.Contains(t, rr.Body.String(), "login from IP 10.29.1.9 not allowed")
form.Set(csrfFormToken, createCSRFToken(validForwardedFor))
req, err = http.NewRequest(http.MethodPost, webAdminLoginPath, bytes.NewBuffer([]byte(form.Encode())))
assert.NoError(t, err)
req.RemoteAddr = testIP
@ -2069,7 +2093,7 @@ func TestInvalidClaims(t *testing.T) {
token, err := c.createTokenResponse(server.tokenAuth, tokenAudienceWebClient, "")
assert.NoError(t, err)
form := make(url.Values)
form.Set(csrfFormToken, createCSRFToken())
form.Set(csrfFormToken, createCSRFToken(""))
form.Set("public_keys", "")
req, _ := http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
@ -2089,7 +2113,7 @@ func TestInvalidClaims(t *testing.T) {
token, err = c.createTokenResponse(server.tokenAuth, tokenAudienceWebAdmin, "")
assert.NoError(t, err)
form = make(url.Values)
form.Set(csrfFormToken, createCSRFToken())
form.Set(csrfFormToken, createCSRFToken(""))
form.Set("allow_api_key_auth", "")
req, _ = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode())))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
@ -2400,7 +2424,7 @@ func TestWebAdminSetupWithInstallCode(t *testing.T) {
}
form := make(url.Values)
csrfToken := createCSRFToken()
csrfToken := createCSRFToken("")
form.Set("_form_token", csrfToken)
form.Set("install_code", "12345")
form.Set("username", defaultAdminUsername)

View file

@ -77,7 +77,7 @@ func validateJWTToken(w http.ResponseWriter, r *http.Request, audience tokenAudi
return errInvalidToken
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if ipAddr != "" && !strings.Contains(token.JwtID(), ipAddr) {
if !util.IsStringInSlice(ipAddr, token.Audience()) {
logger.Debug(logSender, "", "the token with id %#v is not valid for the ip address %#v", token.JwtID(), ipAddr)
doRedirect("Your token is not valid", nil)
return errInvalidToken
@ -278,7 +278,13 @@ func verifyCSRFHeader(next http.Handler) http.Handler {
}
if !util.IsStringInSlice(tokenAudienceCSRF, token.Audience()) {
logger.Debug(logSender, "", "error validating CSRF header audience")
logger.Debug(logSender, "", "error validating CSRF header token audience")
sendAPIResponse(w, r, errors.New("the token is not valid"), "", http.StatusForbidden)
return
}
if !util.IsStringInSlice(util.GetIPFromRemoteAddress(r.RemoteAddr), token.Audience()) {
logger.Debug(logSender, "", "error validating CSRF header IP audience")
sendAPIResponse(w, r, errors.New("the token is not valid"), "", http.StatusForbidden)
return
}

View file

@ -81,7 +81,10 @@ func setIDTokenClaims(idToken *oidc.IDToken, claims []byte) {
}
func TestOIDCInitialization(t *testing.T) {
config := OIDC{
config := OIDC{}
err := config.initialize()
assert.NoError(t, err)
config = OIDC{
ClientID: "sftpgo-client",
ClientSecret: "jRsmE0SWnuZjP7djBqNq0mrf8QN77j2c",
ConfigURL: fmt.Sprintf("http://%v/", oidcMockAddr),
@ -89,7 +92,7 @@ func TestOIDCInitialization(t *testing.T) {
UsernameField: "preferred_username",
RoleField: "sftpgo_role",
}
err := config.initialize()
err = config.initialize()
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "oidc: unable to initialize provider")
}

View file

@ -133,12 +133,12 @@ func (s *httpdServer) refreshCookie(next http.Handler) http.Handler {
})
}
func (s *httpdServer) renderClientLoginPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderClientLoginPage(w http.ResponseWriter, error, ip string) {
data := loginPage{
CurrentURL: webClientLoginPath,
Version: version.Get().Version,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
ExtraCSS: s.binding.ExtraCSS,
}
@ -170,7 +170,7 @@ func (s *httpdServer) handleWebClientChangePwdPost(w http.ResponseWriter, r *htt
s.renderClientChangePasswordPage(w, r, err.Error())
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
s.renderClientForbiddenPage(w, r, err.Error())
return
}
@ -189,48 +189,48 @@ func (s *httpdServer) handleClientWebLogin(w http.ResponseWriter, r *http.Reques
http.Redirect(w, r, webAdminSetupPath, http.StatusFound)
return
}
s.renderClientLoginPage(w, getFlashMessage(w, r))
s.renderClientLoginPage(w, getFlashMessage(w, r), util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func (s *httpdServer) handleWebClientLoginPost(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := r.ParseForm(); err != nil {
s.renderClientLoginPage(w, err.Error())
s.renderClientLoginPage(w, err.Error(), ipAddr)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
protocol := common.ProtocolHTTP
username := r.Form.Get("username")
password := r.Form.Get("password")
if username == "" || password == "" {
updateLoginMetrics(&dataprovider.User{BaseUser: sdk.BaseUser{Username: username}},
dataprovider.LoginMethodPassword, ipAddr, common.ErrNoCredentials)
s.renderClientLoginPage(w, "Invalid credentials")
s.renderClientLoginPage(w, "Invalid credentials", ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
updateLoginMetrics(&dataprovider.User{BaseUser: sdk.BaseUser{Username: username}},
dataprovider.LoginMethodPassword, ipAddr, err)
s.renderClientLoginPage(w, err.Error())
s.renderClientLoginPage(w, err.Error(), ipAddr)
return
}
if err := common.Config.ExecutePostConnectHook(ipAddr, protocol); err != nil {
s.renderClientLoginPage(w, fmt.Sprintf("access denied by post connect hook: %v", err))
s.renderClientLoginPage(w, fmt.Sprintf("access denied by post connect hook: %v", err), ipAddr)
return
}
user, err := dataprovider.CheckUserAndPass(username, password, ipAddr, protocol)
if err != nil {
updateLoginMetrics(&user, dataprovider.LoginMethodPassword, ipAddr, err)
s.renderClientLoginPage(w, dataprovider.ErrInvalidCredentials.Error())
s.renderClientLoginPage(w, dataprovider.ErrInvalidCredentials.Error(), ipAddr)
return
}
connectionID := fmt.Sprintf("%v_%v", protocol, xid.New().String())
if err := checkHTTPClientUser(&user, r, connectionID); err != nil {
updateLoginMetrics(&user, dataprovider.LoginMethodPassword, ipAddr, err)
s.renderClientLoginPage(w, err.Error())
s.renderClientLoginPage(w, err.Error(), ipAddr)
return
}
@ -239,7 +239,7 @@ func (s *httpdServer) handleWebClientLoginPost(w http.ResponseWriter, r *http.Re
if err != nil {
logger.Warn(logSender, connectionID, "unable to check fs root: %v", err)
updateLoginMetrics(&user, dataprovider.LoginMethodPassword, ipAddr, common.ErrInternalFailure)
s.renderClientLoginPage(w, err.Error())
s.renderClientLoginPage(w, err.Error(), ipAddr)
return
}
s.loginUser(w, r, &user, connectionID, ipAddr, false, s.renderClientLoginPage)
@ -247,27 +247,29 @@ func (s *httpdServer) handleWebClientLoginPost(w http.ResponseWriter, r *http.Re
func (s *httpdServer) handleWebClientPasswordResetPost(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
err := r.ParseForm()
if err != nil {
s.renderClientResetPwdPage(w, err.Error())
s.renderClientResetPwdPage(w, err.Error(), ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderClientForbiddenPage(w, r, err.Error())
return
}
_, user, err := handleResetPassword(r, r.Form.Get("code"), r.Form.Get("password"), false)
if err != nil {
if e, ok := err.(*util.ValidationError); ok {
s.renderClientResetPwdPage(w, e.GetErrorString())
s.renderClientResetPwdPage(w, e.GetErrorString(), ipAddr)
return
}
s.renderClientResetPwdPage(w, err.Error())
s.renderClientResetPwdPage(w, err.Error(), ipAddr)
return
}
connectionID := fmt.Sprintf("%v_%v", getProtocolFromRequest(r), xid.New().String())
if err := checkHTTPClientUser(user, r, connectionID); err != nil {
s.renderClientResetPwdPage(w, fmt.Sprintf("Password reset successfully but unable to login: %v", err.Error()))
s.renderClientResetPwdPage(w, fmt.Sprintf("Password reset successfully but unable to login: %v", err.Error()), ipAddr)
return
}
@ -275,10 +277,9 @@ func (s *httpdServer) handleWebClientPasswordResetPost(w http.ResponseWriter, r
err = user.CheckFsRoot(connectionID)
if err != nil {
logger.Warn(logSender, connectionID, "unable to check fs root: %v", err)
s.renderClientResetPwdPage(w, fmt.Sprintf("Password reset successfully but unable to login: %v", err.Error()))
s.renderClientResetPwdPage(w, fmt.Sprintf("Password reset successfully but unable to login: %v", err.Error()), ipAddr)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
s.loginUser(w, r, user, connectionID, ipAddr, false, s.renderClientResetPwdPage)
}
@ -289,27 +290,28 @@ func (s *httpdServer) handleWebClientTwoFactorRecoveryPost(w http.ResponseWriter
s.renderNotFoundPage(w, r, nil)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := r.ParseForm(); err != nil {
s.renderClientTwoFactorRecoveryPage(w, err.Error())
s.renderClientTwoFactorRecoveryPage(w, err.Error(), ipAddr)
return
}
username := claims.Username
recoveryCode := r.Form.Get("recovery_code")
if username == "" || recoveryCode == "" {
s.renderClientTwoFactorRecoveryPage(w, "Invalid credentials")
s.renderClientTwoFactorRecoveryPage(w, "Invalid credentials", ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
s.renderClientTwoFactorRecoveryPage(w, err.Error())
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderClientTwoFactorRecoveryPage(w, err.Error(), ipAddr)
return
}
user, err := dataprovider.UserExists(username)
if err != nil {
s.renderClientTwoFactorRecoveryPage(w, "Invalid credentials")
s.renderClientTwoFactorRecoveryPage(w, "Invalid credentials", ipAddr)
return
}
if !user.Filters.TOTPConfig.Enabled || !util.IsStringInSlice(common.ProtocolHTTP, user.Filters.TOTPConfig.Protocols) {
s.renderClientTwoFactorPage(w, "Two factory authentication is not enabled")
s.renderClientTwoFactorPage(w, "Two factory authentication is not enabled", ipAddr)
return
}
for idx, code := range user.Filters.RecoveryCodes {
@ -319,23 +321,23 @@ func (s *httpdServer) handleWebClientTwoFactorRecoveryPost(w http.ResponseWriter
}
if code.Secret.GetPayload() == recoveryCode {
if code.Used {
s.renderClientTwoFactorRecoveryPage(w, "This recovery code was already used")
s.renderClientTwoFactorRecoveryPage(w, "This recovery code was already used", ipAddr)
return
}
user.Filters.RecoveryCodes[idx].Used = true
err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr))
err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, ipAddr)
if err != nil {
logger.Warn(logSender, "", "unable to set the recovery code %#v as used: %v", recoveryCode, err)
s.renderClientInternalServerErrorPage(w, r, errors.New("unable to set the recovery code as used"))
return
}
connectionID := fmt.Sprintf("%v_%v", getProtocolFromRequest(r), xid.New().String())
s.loginUser(w, r, &user, connectionID, util.GetIPFromRemoteAddress(r.RemoteAddr), true,
s.loginUser(w, r, &user, connectionID, ipAddr, true,
s.renderClientTwoFactorRecoveryPage)
return
}
}
s.renderClientTwoFactorRecoveryPage(w, "Invalid recovery code")
s.renderClientTwoFactorRecoveryPage(w, "Invalid recovery code", ipAddr)
}
func (s *httpdServer) handleWebClientTwoFactorPost(w http.ResponseWriter, r *http.Request) {
@ -345,27 +347,28 @@ func (s *httpdServer) handleWebClientTwoFactorPost(w http.ResponseWriter, r *htt
s.renderNotFoundPage(w, r, nil)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := r.ParseForm(); err != nil {
s.renderClientTwoFactorPage(w, err.Error())
s.renderClientTwoFactorPage(w, err.Error(), ipAddr)
return
}
username := claims.Username
passcode := r.Form.Get("passcode")
if username == "" || passcode == "" {
s.renderClientTwoFactorPage(w, "Invalid credentials")
s.renderClientTwoFactorPage(w, "Invalid credentials", ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
s.renderClientTwoFactorPage(w, err.Error())
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderClientTwoFactorPage(w, err.Error(), ipAddr)
return
}
user, err := dataprovider.UserExists(username)
if err != nil {
s.renderClientTwoFactorPage(w, "Invalid credentials")
s.renderClientTwoFactorPage(w, "Invalid credentials", ipAddr)
return
}
if !user.Filters.TOTPConfig.Enabled || !util.IsStringInSlice(common.ProtocolHTTP, user.Filters.TOTPConfig.Protocols) {
s.renderClientTwoFactorPage(w, "Two factory authentication is not enabled")
s.renderClientTwoFactorPage(w, "Two factory authentication is not enabled", ipAddr)
return
}
err = user.Filters.TOTPConfig.Secret.Decrypt()
@ -376,44 +379,45 @@ func (s *httpdServer) handleWebClientTwoFactorPost(w http.ResponseWriter, r *htt
match, err := mfa.ValidateTOTPPasscode(user.Filters.TOTPConfig.ConfigName, passcode,
user.Filters.TOTPConfig.Secret.GetPayload())
if !match || err != nil {
s.renderClientTwoFactorPage(w, "Invalid authentication code")
s.renderClientTwoFactorPage(w, "Invalid authentication code", ipAddr)
return
}
connectionID := fmt.Sprintf("%v_%v", getProtocolFromRequest(r), xid.New().String())
s.loginUser(w, r, &user, connectionID, util.GetIPFromRemoteAddress(r.RemoteAddr), true, s.renderClientTwoFactorPage)
s.loginUser(w, r, &user, connectionID, ipAddr, true, s.renderClientTwoFactorPage)
}
func (s *httpdServer) handleWebAdminTwoFactorRecoveryPost(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
claims, err := getTokenClaims(r)
if err != nil {
s.renderNotFoundPage(w, r, nil)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := r.ParseForm(); err != nil {
s.renderTwoFactorRecoveryPage(w, err.Error())
s.renderTwoFactorRecoveryPage(w, err.Error(), ipAddr)
return
}
username := claims.Username
recoveryCode := r.Form.Get("recovery_code")
if username == "" || recoveryCode == "" {
s.renderTwoFactorRecoveryPage(w, "Invalid credentials")
s.renderTwoFactorRecoveryPage(w, "Invalid credentials", ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
s.renderTwoFactorRecoveryPage(w, err.Error())
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderTwoFactorRecoveryPage(w, err.Error(), ipAddr)
return
}
admin, err := dataprovider.AdminExists(username)
if err != nil {
s.renderTwoFactorRecoveryPage(w, "Invalid credentials")
s.renderTwoFactorRecoveryPage(w, "Invalid credentials", ipAddr)
return
}
if !admin.Filters.TOTPConfig.Enabled {
s.renderTwoFactorRecoveryPage(w, "Two factory authentication is not enabled")
s.renderTwoFactorRecoveryPage(w, "Two factory authentication is not enabled", ipAddr)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
for idx, code := range admin.Filters.RecoveryCodes {
if err := code.Secret.Decrypt(); err != nil {
s.renderInternalServerErrorPage(w, r, fmt.Errorf("unable to decrypt recovery code: %w", err))
@ -421,7 +425,7 @@ func (s *httpdServer) handleWebAdminTwoFactorRecoveryPost(w http.ResponseWriter,
}
if code.Secret.GetPayload() == recoveryCode {
if code.Used {
s.renderTwoFactorRecoveryPage(w, "This recovery code was already used")
s.renderTwoFactorRecoveryPage(w, "This recovery code was already used", ipAddr)
return
}
admin.Filters.RecoveryCodes[idx].Used = true
@ -435,7 +439,7 @@ func (s *httpdServer) handleWebAdminTwoFactorRecoveryPost(w http.ResponseWriter,
return
}
}
s.renderTwoFactorRecoveryPage(w, "Invalid recovery code")
s.renderTwoFactorRecoveryPage(w, "Invalid recovery code", ipAddr)
}
func (s *httpdServer) handleWebAdminTwoFactorPost(w http.ResponseWriter, r *http.Request) {
@ -445,27 +449,28 @@ func (s *httpdServer) handleWebAdminTwoFactorPost(w http.ResponseWriter, r *http
s.renderNotFoundPage(w, r, nil)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := r.ParseForm(); err != nil {
s.renderTwoFactorPage(w, err.Error())
s.renderTwoFactorPage(w, err.Error(), ipAddr)
return
}
username := claims.Username
passcode := r.Form.Get("passcode")
if username == "" || passcode == "" {
s.renderTwoFactorPage(w, "Invalid credentials")
s.renderTwoFactorPage(w, "Invalid credentials", ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
s.renderTwoFactorPage(w, err.Error())
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderTwoFactorPage(w, err.Error(), ipAddr)
return
}
admin, err := dataprovider.AdminExists(username)
if err != nil {
s.renderTwoFactorPage(w, "Invalid credentials")
s.renderTwoFactorPage(w, "Invalid credentials", ipAddr)
return
}
if !admin.Filters.TOTPConfig.Enabled {
s.renderTwoFactorPage(w, "Two factory authentication is not enabled")
s.renderTwoFactorPage(w, "Two factory authentication is not enabled", ipAddr)
return
}
err = admin.Filters.TOTPConfig.Secret.Decrypt()
@ -476,43 +481,44 @@ func (s *httpdServer) handleWebAdminTwoFactorPost(w http.ResponseWriter, r *http
match, err := mfa.ValidateTOTPPasscode(admin.Filters.TOTPConfig.ConfigName, passcode,
admin.Filters.TOTPConfig.Secret.GetPayload())
if !match || err != nil {
s.renderTwoFactorPage(w, "Invalid authentication code")
s.renderTwoFactorPage(w, "Invalid authentication code", ipAddr)
return
}
s.loginAdmin(w, r, &admin, true, s.renderTwoFactorPage, util.GetIPFromRemoteAddress(r.RemoteAddr))
s.loginAdmin(w, r, &admin, true, s.renderTwoFactorPage, ipAddr)
}
func (s *httpdServer) handleWebAdminLoginPost(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := r.ParseForm(); err != nil {
s.renderAdminLoginPage(w, err.Error())
s.renderAdminLoginPage(w, err.Error(), ipAddr)
return
}
username := r.Form.Get("username")
password := r.Form.Get("password")
if username == "" || password == "" {
s.renderAdminLoginPage(w, "Invalid credentials")
s.renderAdminLoginPage(w, "Invalid credentials", ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
s.renderAdminLoginPage(w, err.Error())
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderAdminLoginPage(w, err.Error(), ipAddr)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
admin, err := dataprovider.CheckAdminAndPass(username, password, ipAddr)
if err != nil {
s.renderAdminLoginPage(w, err.Error())
s.renderAdminLoginPage(w, err.Error(), ipAddr)
return
}
s.loginAdmin(w, r, &admin, false, s.renderAdminLoginPage, ipAddr)
}
func (s *httpdServer) renderAdminLoginPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderAdminLoginPage(w http.ResponseWriter, error, ip string) {
data := loginPage{
CurrentURL: webAdminLoginPath,
Version: version.Get().Version,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
ExtraCSS: s.binding.ExtraCSS,
}
@ -534,7 +540,7 @@ func (s *httpdServer) handleWebAdminLogin(w http.ResponseWriter, r *http.Request
http.Redirect(w, r, webAdminSetupPath, http.StatusFound)
return
}
s.renderAdminLoginPage(w, getFlashMessage(w, r))
s.renderAdminLoginPage(w, getFlashMessage(w, r), util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func (s *httpdServer) handleWebAdminLogout(w http.ResponseWriter, r *http.Request) {
@ -553,7 +559,7 @@ func (s *httpdServer) handleWebAdminChangePwdPost(w http.ResponseWriter, r *http
s.renderChangePasswordPage(w, r, err.Error())
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -568,26 +574,28 @@ func (s *httpdServer) handleWebAdminChangePwdPost(w http.ResponseWriter, r *http
func (s *httpdServer) handleWebAdminPasswordResetPost(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
err := r.ParseForm()
if err != nil {
s.renderResetPwdPage(w, err.Error())
s.renderResetPwdPage(w, err.Error(), ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
admin, _, err := handleResetPassword(r, r.Form.Get("code"), r.Form.Get("password"), true)
if err != nil {
if e, ok := err.(*util.ValidationError); ok {
s.renderResetPwdPage(w, e.GetErrorString())
s.renderResetPwdPage(w, e.GetErrorString(), ipAddr)
return
}
s.renderResetPwdPage(w, err.Error())
s.renderResetPwdPage(w, err.Error(), ipAddr)
return
}
s.loginAdmin(w, r, admin, false, s.renderResetPwdPage, util.GetIPFromRemoteAddress(r.RemoteAddr))
s.loginAdmin(w, r, admin, false, s.renderResetPwdPage, ipAddr)
}
func (s *httpdServer) handleWebAdminSetupPost(w http.ResponseWriter, r *http.Request) {
@ -601,7 +609,8 @@ func (s *httpdServer) handleWebAdminSetupPost(w http.ResponseWriter, r *http.Req
s.renderAdminSetupPage(w, r, "", err.Error())
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -631,7 +640,6 @@ func (s *httpdServer) handleWebAdminSetupPost(w http.ResponseWriter, r *http.Req
Status: 1,
Permissions: []string{dataprovider.PermAdminAny},
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
err = dataprovider.AddAdmin(&admin, username, ipAddr)
if err != nil {
s.renderAdminSetupPage(w, r, username, err.Error())
@ -642,7 +650,7 @@ func (s *httpdServer) handleWebAdminSetupPost(w http.ResponseWriter, r *http.Req
func (s *httpdServer) loginUser(
w http.ResponseWriter, r *http.Request, user *dataprovider.User, connectionID, ipAddr string,
isSecondFactorAuth bool, errorFunc func(w http.ResponseWriter, error string),
isSecondFactorAuth bool, errorFunc func(w http.ResponseWriter, error, ip string),
) {
c := jwtTokenClaims{
Username: user.Username,
@ -662,7 +670,7 @@ func (s *httpdServer) loginUser(
if err != nil {
logger.Warn(logSender, connectionID, "unable to set user login cookie %v", err)
updateLoginMetrics(user, dataprovider.LoginMethodPassword, ipAddr, common.ErrInternalFailure)
errorFunc(w, err.Error())
errorFunc(w, err.Error(), ipAddr)
return
}
if isSecondFactorAuth {
@ -679,7 +687,8 @@ func (s *httpdServer) loginUser(
func (s *httpdServer) loginAdmin(
w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin,
isSecondFactorAuth bool, errorFunc func(w http.ResponseWriter, error string), ip string,
isSecondFactorAuth bool, errorFunc func(w http.ResponseWriter, error, ip string),
ipAddr string,
) {
c := jwtTokenClaims{
Username: admin.Username,
@ -692,14 +701,14 @@ func (s *httpdServer) loginAdmin(
audience = tokenAudienceWebAdminPartial
}
err := c.createAndSetCookie(w, r, s.tokenAuth, audience, ip)
err := c.createAndSetCookie(w, r, s.tokenAuth, audience, ipAddr)
if err != nil {
logger.Warn(logSender, "", "unable to set admin login cookie %v", err)
if errorFunc == nil {
s.renderAdminSetupPage(w, r, admin.Username, err.Error())
return
}
errorFunc(w, err.Error())
errorFunc(w, err.Error(), ipAddr)
return
}
if isSecondFactorAuth {

View file

@ -376,7 +376,7 @@ func loadAdminTemplates(templatesPath string) {
func (s *httpdServer) getBasePageData(title, currentURL string, r *http.Request) basePage {
var csrfToken string
if currentURL != "" {
csrfToken = createCSRFToken()
csrfToken = createCSRFToken(util.GetIPFromRemoteAddress(r.RemoteAddr))
}
return basePage{
Title: title,
@ -458,11 +458,11 @@ func (s *httpdServer) renderNotFoundPage(w http.ResponseWriter, r *http.Request,
s.renderMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
}
func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, error, ip string) {
data := forgotPwdPage{
CurrentURL: webAdminForgotPwdPath,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
Title: pageForgotPwdTitle,
ExtraCSS: s.binding.ExtraCSS,
@ -470,11 +470,11 @@ func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, error string) {
renderAdminTemplate(w, templateForgotPassword, data)
}
func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, error, ip string) {
data := resetPwdPage{
CurrentURL: webAdminResetPwdPath,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
Title: pageResetPwdTitle,
ExtraCSS: s.binding.ExtraCSS,
@ -482,12 +482,12 @@ func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, error string) {
renderAdminTemplate(w, templateResetPassword, data)
}
func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, error, ip string) {
data := twoFactorPage{
CurrentURL: webAdminTwoFactorPath,
Version: version.Get().Version,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
RecoveryURL: webAdminTwoFactorRecoveryPath,
ExtraCSS: s.binding.ExtraCSS,
@ -495,12 +495,12 @@ func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, error string) {
renderAdminTemplate(w, templateTwoFactor, data)
}
func (s *httpdServer) renderTwoFactorRecoveryPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderTwoFactorRecoveryPage(w http.ResponseWriter, error, ip string) {
data := twoFactorPage{
CurrentURL: webAdminTwoFactorRecoveryPath,
Version: version.Get().Version,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
ExtraCSS: s.binding.ExtraCSS,
}
@ -1376,27 +1376,29 @@ func (s *httpdServer) handleWebAdminForgotPwd(w http.ResponseWriter, r *http.Req
s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
return
}
s.renderForgotPwdPage(w, "")
s.renderForgotPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func (s *httpdServer) handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
err := r.ParseForm()
if err != nil {
s.renderForgotPwdPage(w, err.Error())
s.renderForgotPwdPage(w, err.Error(), ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
err = handleForgotPassword(r, r.Form.Get("username"), true)
if err != nil {
if e, ok := err.(*util.ValidationError); ok {
s.renderForgotPwdPage(w, e.GetErrorString())
s.renderForgotPwdPage(w, e.GetErrorString(), ipAddr)
return
}
s.renderForgotPwdPage(w, err.Error())
s.renderForgotPwdPage(w, err.Error(), ipAddr)
return
}
http.Redirect(w, r, webAdminResetPwdPath, http.StatusFound)
@ -1408,17 +1410,17 @@ func (s *httpdServer) handleWebAdminPasswordReset(w http.ResponseWriter, r *http
s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
return
}
s.renderResetPwdPage(w, "")
s.renderResetPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func (s *httpdServer) handleWebAdminTwoFactor(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
s.renderTwoFactorPage(w, "")
s.renderTwoFactorPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func (s *httpdServer) handleWebAdminTwoFactorRecovery(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
s.renderTwoFactorRecoveryPage(w, "")
s.renderTwoFactorRecoveryPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func (s *httpdServer) handleWebAdminMFA(w http.ResponseWriter, r *http.Request) {
@ -1443,7 +1445,8 @@ func (s *httpdServer) handleWebAdminProfilePost(w http.ResponseWriter, r *http.R
s.renderProfilePage(w, r, err.Error())
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -1460,7 +1463,7 @@ func (s *httpdServer) handleWebAdminProfilePost(w http.ResponseWriter, r *http.R
admin.Filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
admin.Email = r.Form.Get("email")
admin.Description = r.Form.Get("description")
err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr))
err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, ipAddr)
if err != nil {
s.renderProfilePage(w, r, err.Error())
return
@ -1487,7 +1490,9 @@ func (s *httpdServer) handleWebRestore(w http.ResponseWriter, r *http.Request) {
return
}
defer r.MultipartForm.RemoveAll() //nolint:errcheck
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -1517,7 +1522,7 @@ func (s *httpdServer) handleWebRestore(w http.ResponseWriter, r *http.Request) {
return
}
if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, ipAddr); err != nil {
s.renderMaintenancePage(w, r, err.Error())
return
}
@ -1594,11 +1599,12 @@ func (s *httpdServer) handleWebAddAdminPost(w http.ResponseWriter, r *http.Reque
s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
err = dataprovider.AddAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.Method))
err = dataprovider.AddAdmin(&admin, claims.Username, ipAddr)
if err != nil {
s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
return
@ -1624,7 +1630,8 @@ func (s *httpdServer) handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Re
s.renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -1650,7 +1657,7 @@ func (s *httpdServer) handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Re
return
}
}
err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, ipAddr)
if err != nil {
s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), false)
return
@ -1733,7 +1740,8 @@ func (s *httpdServer) handleWebTemplateFolderPost(w http.ResponseWriter, r *http
}
defer r.MultipartForm.RemoveAll() //nolint:errcheck
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -1772,7 +1780,7 @@ func (s *httpdServer) handleWebTemplateFolderPost(w http.ResponseWriter, r *http
render.JSON(w, r, dump)
return
}
if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, ipAddr); err != nil {
s.renderMessagePage(w, r, "Unable to save folders", "Cannot save the defined folders:",
getRespStatus(err), err, "")
return
@ -1819,7 +1827,8 @@ func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.R
s.renderMessagePage(w, r, "Error parsing user fields", "", http.StatusBadRequest, err, "")
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -1854,7 +1863,7 @@ func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.R
render.JSON(w, r, dump)
return
}
if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, ipAddr); err != nil {
s.renderMessagePage(w, r, "Unable to save users", "Cannot save the defined users:",
getRespStatus(err), err, "")
return
@ -1898,11 +1907,12 @@ func (s *httpdServer) handleWebAddUserPost(w http.ResponseWriter, r *http.Reques
s.renderUserPage(w, r, &user, userPageModeAdd, err.Error())
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
err = dataprovider.AddUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
err = dataprovider.AddUser(&user, claims.Username, ipAddr)
if err == nil {
http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
} else {
@ -1931,7 +1941,8 @@ func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Req
s.renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -1947,7 +1958,7 @@ func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Req
user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase,
user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey)
err = dataprovider.UpdateUser(&updatedUser, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
err = dataprovider.UpdateUser(&updatedUser, claims.Username, ipAddr)
if err == nil {
if len(r.Form.Get("disconnect")) > 0 {
disconnectUser(user.Username)
@ -1992,7 +2003,8 @@ func (s *httpdServer) handleWebAddFolderPost(w http.ResponseWriter, r *http.Requ
}
defer r.MultipartForm.RemoveAll() //nolint:errcheck
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -2051,7 +2063,8 @@ func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.R
}
defer r.MultipartForm.RemoveAll() //nolint:errcheck
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderForbiddenPage(w, r, err.Error())
return
}
@ -2072,7 +2085,7 @@ func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.R
folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase,
folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey)
err = dataprovider.UpdateFolder(updatedFolder, folder.Users, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
err = dataprovider.UpdateFolder(updatedFolder, folder.Users, claims.Username, ipAddr)
if err != nil {
s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
return

View file

@ -314,7 +314,7 @@ func loadClientTemplates(templatesPath string) {
func (s *httpdServer) getBaseClientPageData(title, currentURL string, r *http.Request) baseClientPage {
var csrfToken string
if currentURL != "" {
csrfToken = createCSRFToken()
csrfToken = createCSRFToken(util.GetIPFromRemoteAddress(r.RemoteAddr))
}
v := version.Get()
@ -341,11 +341,11 @@ func (s *httpdServer) getBaseClientPageData(title, currentURL string, r *http.Re
}
}
func (s *httpdServer) renderClientForgotPwdPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderClientForgotPwdPage(w http.ResponseWriter, error, ip string) {
data := forgotPwdPage{
CurrentURL: webClientForgotPwdPath,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
Title: pageClientForgotPwdTitle,
ExtraCSS: s.binding.ExtraCSS,
@ -353,11 +353,11 @@ func (s *httpdServer) renderClientForgotPwdPage(w http.ResponseWriter, error str
renderClientTemplate(w, templateForgotPassword, data)
}
func (s *httpdServer) renderClientResetPwdPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderClientResetPwdPage(w http.ResponseWriter, error, ip string) {
data := resetPwdPage{
CurrentURL: webClientResetPwdPath,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
Title: pageClientResetPwdTitle,
ExtraCSS: s.binding.ExtraCSS,
@ -405,12 +405,12 @@ func (s *httpdServer) renderClientNotFoundPage(w http.ResponseWriter, r *http.Re
s.renderClientMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
}
func (s *httpdServer) renderClientTwoFactorPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderClientTwoFactorPage(w http.ResponseWriter, error, ip string) {
data := twoFactorPage{
CurrentURL: webClientTwoFactorPath,
Version: version.Get().Version,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
RecoveryURL: webClientTwoFactorRecoveryPath,
ExtraCSS: s.binding.ExtraCSS,
@ -418,12 +418,12 @@ func (s *httpdServer) renderClientTwoFactorPage(w http.ResponseWriter, error str
renderClientTemplate(w, templateTwoFactor, data)
}
func (s *httpdServer) renderClientTwoFactorRecoveryPage(w http.ResponseWriter, error string) {
func (s *httpdServer) renderClientTwoFactorRecoveryPage(w http.ResponseWriter, error, ip string) {
data := twoFactorPage{
CurrentURL: webClientTwoFactorRecoveryPath,
Version: version.Get().Version,
Error: error,
CSRFToken: createCSRFToken(),
CSRFToken: createCSRFToken(ip),
StaticURL: webStaticFilesPath,
ExtraCSS: s.binding.ExtraCSS,
}
@ -972,7 +972,8 @@ func (s *httpdServer) handleClientAddSharePost(w http.ResponseWriter, r *http.Re
s.renderAddUpdateSharePage(w, r, share, err.Error(), true)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderClientForbiddenPage(w, r, err.Error())
return
}
@ -986,7 +987,7 @@ func (s *httpdServer) handleClientAddSharePost(w http.ResponseWriter, r *http.Re
return
}
}
err = dataprovider.AddShare(share, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
err = dataprovider.AddShare(share, claims.Username, ipAddr)
if err == nil {
http.Redirect(w, r, webClientSharesPath, http.StatusSeeOther)
} else {
@ -1015,7 +1016,8 @@ func (s *httpdServer) handleClientUpdateSharePost(w http.ResponseWriter, r *http
s.renderAddUpdateSharePage(w, r, updatedShare, err.Error(), false)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderClientForbiddenPage(w, r, err.Error())
return
}
@ -1030,7 +1032,7 @@ func (s *httpdServer) handleClientUpdateSharePost(w http.ResponseWriter, r *http
return
}
}
err = dataprovider.UpdateShare(updatedShare, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
err = dataprovider.UpdateShare(updatedShare, claims.Username, ipAddr)
if err == nil {
http.Redirect(w, r, webClientSharesPath, http.StatusSeeOther)
} else {
@ -1090,7 +1092,8 @@ func (s *httpdServer) handleWebClientProfilePost(w http.ResponseWriter, r *http.
s.renderClientProfilePage(w, r, err.Error())
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderClientForbiddenPage(w, r, err.Error())
return
}
@ -1118,7 +1121,7 @@ func (s *httpdServer) handleWebClientProfilePost(w http.ResponseWriter, r *http.
user.Email = r.Form.Get("email")
user.Description = r.Form.Get("description")
}
err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr))
err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, ipAddr)
if err != nil {
s.renderClientProfilePage(w, r, err.Error())
return
@ -1134,12 +1137,12 @@ func (s *httpdServer) handleWebClientMFA(w http.ResponseWriter, r *http.Request)
func (s *httpdServer) handleWebClientTwoFactor(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
s.renderClientTwoFactorPage(w, "")
s.renderClientTwoFactorPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func (s *httpdServer) handleWebClientTwoFactorRecovery(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
s.renderClientTwoFactorRecoveryPage(w, "")
s.renderClientTwoFactorRecoveryPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func getShareFromPostFields(r *http.Request) (*dataprovider.Share, error) {
@ -1181,17 +1184,19 @@ func (s *httpdServer) handleWebClientForgotPwd(w http.ResponseWriter, r *http.Re
s.renderClientNotFoundPage(w, r, errors.New("this page does not exist"))
return
}
s.renderClientForgotPwdPage(w, "")
s.renderClientForgotPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func (s *httpdServer) handleWebClientForgotPwdPost(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
err := r.ParseForm()
if err != nil {
s.renderClientForgotPwdPage(w, err.Error())
s.renderClientForgotPwdPage(w, err.Error(), ipAddr)
return
}
if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderClientForbiddenPage(w, r, err.Error())
return
}
@ -1199,10 +1204,10 @@ func (s *httpdServer) handleWebClientForgotPwdPost(w http.ResponseWriter, r *htt
err = handleForgotPassword(r, username, false)
if err != nil {
if e, ok := err.(*util.ValidationError); ok {
s.renderClientForgotPwdPage(w, e.GetErrorString())
s.renderClientForgotPwdPage(w, e.GetErrorString(), ipAddr)
return
}
s.renderClientForgotPwdPage(w, err.Error())
s.renderClientForgotPwdPage(w, err.Error(), ipAddr)
return
}
http.Redirect(w, r, webClientResetPwdPath, http.StatusFound)
@ -1214,7 +1219,7 @@ func (s *httpdServer) handleWebClientPasswordReset(w http.ResponseWriter, r *htt
s.renderClientNotFoundPage(w, r, errors.New("this page does not exist"))
return
}
s.renderClientResetPwdPage(w, "")
s.renderClientResetPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
}
func (s *httpdServer) handleClientViewPDF(w http.ResponseWriter, r *http.Request) {