diff --git a/server/auth/basic/auth_basic.go b/server/auth/basic/auth_basic.go index ce5e6b3..4a7fe29 100644 --- a/server/auth/basic/auth_basic.go +++ b/server/auth/basic/auth_basic.go @@ -23,9 +23,10 @@ const ( defaultMinPasswordLength = 3 ) -// Token suitable as a login: starts and ends with a Unicode letter (class L) or number (class N), -// contains Unicode letters, numbers, dot and underscore. -var loginPattern = regexp.MustCompile(`^[\pL\pN][_.\pL\pN]*[\pL\pN]+$`) +// Token suitable as a login: either an E.164 phone number or a name which starts +// and ends with a Unicode letter (class L) or number (class N), and contains +// Unicode letters, numbers, dot and underscore. +var loginPattern = regexp.MustCompile(`^(\+[\pN]+|[\pL\pN][_.\pL\pN]*[\pL\pN]+)$`) // authenticator is the type to map authentication methods to. type authenticator struct { diff --git a/server/auth/basic/auth_basic_test.go b/server/auth/basic/auth_basic_test.go index cfdb1fa..d1d692c 100644 --- a/server/auth/basic/auth_basic_test.go +++ b/server/auth/basic/auth_basic_test.go @@ -53,3 +53,44 @@ func TestAuthenticateRejectsMissingTenant(t *testing.T) { t.Fatalf("got %v, want %v", err, types.ErrMalformed) } } + +func TestCheckLoginPolicyAcceptsE164Phone(t *testing.T) { + a := &authenticator{name: "basic", minLoginLength: defaultMinLoginLength, + minPasswordLength: defaultMinPasswordLength} + if err := a.checkLoginPolicy("+8615521120255"); err != nil { + t.Fatalf("E.164 phone login rejected: %v", err) + } +} + +func TestAddRecordAcceptsE164PhoneLogin(t *testing.T) { + ctrl := gomock.NewController(t) + users := mock_store.NewMockUsersPersistenceInterface(ctrl) + oldUsers := store.Users + store.Users = users + t.Cleanup(func() { + store.Users = oldUsers + ctrl.Finish() + }) + + users.EXPECT().AddAuthRecord(types.TenantID(7), types.Uid(42), auth.LevelAuth, + "basic", "+8615521120255", gomock.Any(), time.Time{}).Return(nil) + + a := &authenticator{name: "basic", addToTags: true, minLoginLength: defaultMinLoginLength, + minPasswordLength: 6} + rec, err := a.AddRecord(auth.AuthContext{TenantID: 7}, &auth.Rec{TenantID: 7, Uid: 42}, + []byte("+8615521120255:123456")) + if err != nil { + t.Fatal(err) + } + if rec == nil || rec.AuthLevel != auth.LevelAuth || len(rec.Tags) != 1 || rec.Tags[0] != "basic:+8615521120255" { + t.Fatalf("unexpected auth record: %#v", rec) + } +} + +func TestCheckLoginPolicyRejectsMalformedPhone(t *testing.T) { + a := &authenticator{name: "basic", minLoginLength: defaultMinLoginLength, + minPasswordLength: defaultMinPasswordLength} + if err := a.checkLoginPolicy("+86-15521120255"); err != types.ErrPolicy { + t.Fatalf("got %v, want %v", err, types.ErrPolicy) + } +}