mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-28 15:39:43 -06:00
Up to now the /me/changePassword endpoint return a 500 Status when issue a password change with the old password set to the wrong password. This changes the code to return 400 (Bad Request) with an additional message that the old password is wrong. This does not seem to weaken the security of /me/changePassword (i.e. for allowing easier brute-force attacks) as the endpoint is only available to already authenticated users (and only for changing their own passwords) See #4480
108 lines
3.2 KiB
Go
108 lines
3.2 KiB
Go
package svc
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/CiscoM31/godata"
|
|
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
|
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
|
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
|
revactx "github.com/cs3org/reva/v2/pkg/ctx"
|
|
"github.com/cs3org/reva/v2/pkg/events"
|
|
"github.com/go-chi/render"
|
|
libregraph "github.com/owncloud/libre-graph-api-go"
|
|
"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
|
|
)
|
|
|
|
// ChangeOwnPassword implements the Service interface. It allows the user to change
|
|
// its own password
|
|
func (g Graph) ChangeOwnPassword(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
u, ok := revactx.ContextGetUser(ctx)
|
|
if !ok {
|
|
g.logger.Error().Msg("user not in context")
|
|
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, "user not in context")
|
|
return
|
|
}
|
|
|
|
sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/")
|
|
_, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query())
|
|
if err != nil {
|
|
g.logger.Err(err).Interface("query", r.URL.Query()).Msg("query error")
|
|
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
cpw := libregraph.NewPasswordChange()
|
|
err = json.NewDecoder(r.Body).Decode(cpw)
|
|
if err != nil {
|
|
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
|
|
currentPw := cpw.GetCurrentPassword()
|
|
if currentPw == "" {
|
|
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "current password cannot be empty")
|
|
return
|
|
}
|
|
|
|
newPw := cpw.GetNewPassword()
|
|
if newPw == "" {
|
|
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "new password cannot be empty")
|
|
return
|
|
}
|
|
|
|
if newPw == currentPw {
|
|
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "new password must be differnt from current password")
|
|
return
|
|
}
|
|
|
|
authReq := &gateway.AuthenticateRequest{
|
|
Type: "basic",
|
|
ClientId: u.Username,
|
|
ClientSecret: currentPw,
|
|
}
|
|
authRes, err := g.gatewayClient.Authenticate(r.Context(), authReq)
|
|
if err != nil {
|
|
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
|
|
switch authRes.Status.Code {
|
|
case cs3rpc.Code_CODE_OK:
|
|
break
|
|
case cs3rpc.Code_CODE_UNAUTHENTICATED, cs3rpc.Code_CODE_PERMISSION_DENIED:
|
|
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "wrong current password")
|
|
return
|
|
default:
|
|
errorcode.InvalidRequest.Render(w, r, http.StatusInternalServerError, "password change failed")
|
|
return
|
|
}
|
|
|
|
newPwProfile := libregraph.NewPasswordProfile()
|
|
newPwProfile.SetPassword(newPw)
|
|
changes := libregraph.NewUser()
|
|
changes.SetPasswordProfile(*newPwProfile)
|
|
_, err = g.identityBackend.UpdateUser(ctx, u.Id.OpaqueId, *changes)
|
|
if err != nil {
|
|
errorcode.InvalidRequest.Render(w, r, http.StatusInternalServerError, "password change failed")
|
|
g.logger.Debug().Err(err).Str("userid", u.Id.OpaqueId).Msg("failed to update user password")
|
|
return
|
|
}
|
|
|
|
currentUser := ctxpkg.ContextMustGetUser(r.Context())
|
|
g.publishEvent(
|
|
events.UserFeatureChanged{
|
|
Executant: currentUser.Id,
|
|
UserID: u.Id.OpaqueId,
|
|
Features: []events.UserFeature{
|
|
{Name: "password", Value: "***"},
|
|
},
|
|
},
|
|
)
|
|
|
|
render.Status(r, http.StatusNoContent)
|
|
render.NoContent(w, r)
|
|
}
|