diff --git a/changelog/unreleased/fix-segfault.md b/changelog/unreleased/fix-segfault.md index ff25d58b9..2ba5e1362 100644 --- a/changelog/unreleased/fix-segfault.md +++ b/changelog/unreleased/fix-segfault.md @@ -1,4 +1,4 @@ -Bugfix: Prevent segfault when no password is set. +Bugfix: Prevent segfault when no password is set Passwords are stored in a dedicated child struct of an account. We fixed several segfault conditions where the methods would try to unset a password when that child struct was not existing. diff --git a/changelog/unreleased/tighten-screws.md b/changelog/unreleased/tighten-screws.md new file mode 100644 index 000000000..00d9185e9 --- /dev/null +++ b/changelog/unreleased/tighten-screws.md @@ -0,0 +1,5 @@ +Change: Tighten screws on usernames and email addresses + +In order to match accounts to the OIDC claims we currently rely on the email address or username to be present. We force both to match the [W3C recommended regex](https://www.w3.org/TR/2016/REC-html51-20161101/sec-forms.html#valid-e-mail-address) with usernames having to start with a character or `_`. This allows the username to be presented and used in ACLs when integrating the os with the glauth LDAP service of ocis. + +https://github.com/owncloud/ocis-accounts/pull/65 diff --git a/pkg/proto/v0/accounts.pb.micro_test.go b/pkg/proto/v0/accounts.pb.micro_test.go index 0251a4f65..fa9482095 100644 --- a/pkg/proto/v0/accounts.pb.micro_test.go +++ b/pkg/proto/v0/accounts.pb.micro_test.go @@ -405,7 +405,9 @@ func TestCreateAccountInvalidUserName(t *testing.T) { _, err := createAccount(t, userName) // Should give error - checkError(t, err) + if err == nil { + t.Fatalf("Expected an Error when creating user '%s' but got nil", userName) + } } // resp should have the same number of accounts diff --git a/pkg/service/v0/accounts.go b/pkg/service/v0/accounts.go index 116bc9164..5e36b2ec5 100644 --- a/pkg/service/v0/accounts.go +++ b/pkg/service/v0/accounts.go @@ -278,6 +278,12 @@ func (s Service) CreateAccount(c context.Context, in *proto.CreateAccountRequest if in.Account.Id == "" { in.Account.Id = uuid.Must(uuid.NewV4()).String() } + if !s.isValidUsername(in.Account.PreferredName) { + return merrors.BadRequest(s.id, "preferred_name '%s' must be at least the local part of an email", in.Account.PreferredName) + } + if !s.isValidEmail(in.Account.Mail) { + return merrors.BadRequest(s.id, "mail '%s' must be a valid email", in.Account.Mail) + } if id, err = cleanupID(in.Account.Id); err != nil { return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) @@ -317,6 +323,12 @@ func (s Service) UpdateAccount(c context.Context, in *proto.UpdateAccountRequest if in.Account.Id == "" { return merrors.BadRequest(s.id, "account id missing") } + if !s.isValidUsername(in.Account.PreferredName) { + return merrors.BadRequest(s.id, "preferred_name '%s' must be at least the local part of an email", in.Account.PreferredName) + } + if !s.isValidEmail(in.Account.Mail) { + return merrors.BadRequest(s.id, "mail '%s' must be a valid email", in.Account.Mail) + } if id, err = cleanupID(in.Account.Id); err != nil { return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) @@ -437,3 +449,25 @@ func (s Service) DeleteAccount(c context.Context, in *proto.DeleteAccountRequest s.log.Info().Str("id", id).Msg("deleted account") return } + +// We want to allow email addresses as usernames so they show up when using them in ACLs on storages that allow intergration with our glauth LDAP service +// so we are adding a few restrictions from https://stackoverflow.com/questions/6949667/what-are-the-real-rules-for-linux-usernames-on-centos-6-and-rhel-6 +// names should not start with numbers +var usernameRegex = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]*(@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)*$") + +func (s Service) isValidUsername(e string) bool { + if len(e) < 1 && len(e) > 254 { + return false + } + return usernameRegex.MatchString(e) +} + +// regex from https://www.w3.org/TR/2016/REC-html51-20161101/sec-forms.html#valid-e-mail-address +var emailRegex = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$") + +func (s Service) isValidEmail(e string) bool { + if len(e) < 3 && len(e) > 254 { + return false + } + return emailRegex.MatchString(e) +}