Commit 23b73199 authored by ale's avatar ale

Add a password validator to all password-changing API endpoints

parent 547904d1
......@@ -70,6 +70,7 @@ type AccountService struct {
ssoGroups []string
ssoAdminGroup string
passwordValidator ValidatorFunc
dataValidators map[string]ValidatorFunc
adminDataValidators map[string]ValidatorFunc
}
......@@ -97,6 +98,7 @@ func newAccountServiceWithSSO(backend Backend, config *Config, ssoValidator sso.
ResourceTypeEmail: validHostedEmail(validationConfig, domainBackend, backend),
ResourceTypeMailingList: validHostedMailingList(validationConfig, domainBackend, backend),
}
s.passwordValidator = validPassword(validationConfig)
return s
}
......@@ -241,11 +243,8 @@ type ChangeUserPasswordRequest struct {
Password string `json:"password"`
}
func (r *ChangeUserPasswordRequest) Validate() error {
if r.Password == "" {
return errors.New("empty 'password' attribute")
}
return nil
func (r *ChangeUserPasswordRequest) Validate(ctx context.Context, s *AccountService) error {
return s.passwordValidator(ctx, r.Password)
}
// ChangeUserPassword updates a user's password. It will also take
......@@ -256,7 +255,7 @@ func (s *AccountService) ChangeUserPassword(ctx context.Context, tx TX, req *Cha
return err
}
if err = req.Validate(); err != nil {
if err = req.Validate(ctx, s); err != nil {
return newRequestError(err)
}
......@@ -372,7 +371,7 @@ type CreateApplicationSpecificPasswordRequest struct {
Comment string `json:"comment"`
}
func (r *CreateApplicationSpecificPasswordRequest) Validate() error {
func (r *CreateApplicationSpecificPasswordRequest) Validate(_ context.Context, _ *AccountService) error {
if r.Service == "" {
return errors.New("empty 'service' attribute")
}
......@@ -391,7 +390,7 @@ func (s *AccountService) CreateApplicationSpecificPassword(ctx context.Context,
return nil, err
}
if err := req.Validate(); err != nil {
if err := req.Validate(ctx, s); err != nil {
return nil, newRequestError(err)
}
......@@ -471,11 +470,8 @@ type ChangeResourcePasswordRequest struct {
Password string `json:"password"`
}
func (r *ChangeResourcePasswordRequest) Validate() error {
if r.Password == "" {
return errors.New("empty 'password' attribute")
}
return nil
func (r *ChangeResourcePasswordRequest) Validate(ctx context.Context, s *AccountService) error {
return s.passwordValidator(ctx, r.Password)
}
// ChangeResourcePassword modifies the password associated with a
......@@ -487,7 +483,7 @@ func (s *AccountService) ChangeResourcePassword(ctx context.Context, tx TX, req
return err
}
if err = req.Validate(); err != nil {
if err = req.Validate(ctx, s); err != nil {
return newRequestError(err)
}
......@@ -555,7 +551,7 @@ type EnableOTPRequest struct {
TOTPSecret string `json:"totp_secret"`
}
func (r *EnableOTPRequest) Validate() error {
func (r *EnableOTPRequest) Validate(_ context.Context, _ *AccountService) error {
// TODO: the length here is bogus, replace with real value.
if r.TOTPSecret != "" && len(r.TOTPSecret) != 32 {
return errors.New("bad totp_secret value")
......@@ -578,7 +574,7 @@ func (s *AccountService) EnableOTP(ctx context.Context, tx TX, req *EnableOTPReq
return nil, err
}
if err = req.Validate(); err != nil {
if err = req.Validate(ctx, s); err != nil {
return nil, newRequestError(err)
}
......
......@@ -20,6 +20,8 @@ type domainBackend interface {
type validationConfig struct {
forbiddenUsernames stringSet
forbiddenPasswords stringSet
minPasswordLength int
}
// A stringSet is just a list of strings with a quick membership test.
......@@ -204,15 +206,21 @@ func isSubsite(value string) bool {
return strings.Contains(value, "/")
}
func relatedWebsites(ctx context.Context, be domainBackend, value string) []string {
var resourceIDs []string
func relatedWebsites(ctx context.Context, be domainBackend, value string) []FindResourceRequest {
var resourceIDs []FindResourceRequest
if isSubsite(value) {
_, path := splitSubsite(value)
for _, d := range be.GetAvailableDomains(ctx, ResourceTypeWebsite) {
resourceIDs = append(resourceIDs, fmt.Sprintf("%s/%s/%s", ResourceTypeWebsite, d, path))
resourceIDs = append(resourceIDs, FindResourceRequest{
Type: ResourceTypeWebsite,
Name: fmt.Sprintf("%s/%s", d, path),
})
}
} else {
resourceIDs = append(resourceIDs, fmt.Sprintf("%s/%s", ResourceTypeWebsite, value))
resourceIDs = append(resourceIDs, FindResourceRequest{
Type: ResourceTypeDomain,
Name: value,
})
}
return resourceIDs
}
......@@ -272,6 +280,13 @@ func validHostedMailingList(config *validationConfig, be domainBackend, cb Backe
)
}
func validPassword(config *validationConfig) ValidatorFunc {
return allOf(
minLength(config.minPasswordLength),
notInSet(config.forbiddenPasswords),
)
}
func allOf(funcs ...ValidatorFunc) ValidatorFunc {
return func(ctx context.Context, value string) error {
for _, f := range funcs {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment