fix: allow legacy enterprise registration payloads
This commit is contained in:
+62
-1
@@ -156,6 +156,14 @@ func replyCreateUser(s *Session, msg *ClientComMessage, rec *auth.Rec) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
challengeID, _ := cr.Params["challenge_id"].(string)
|
challengeID, _ := cr.Params["challenge_id"].(string)
|
||||||
|
if strings.TrimSpace(challengeID) == "" && phoneRegistration && isLegacyRegistrationSMSCode(cr.Response) {
|
||||||
|
if err := attachLegacyRegistrationSMSChallenge(s.tenantID, cr, phone, time.Now().UTC().Round(time.Millisecond)); err != nil {
|
||||||
|
s.queueOut(decodeStoreError(types.ErrCredentials, msg.Id, msg.Timestamp,
|
||||||
|
map[string]any{"creds": []string{"tel"}}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
challengeID, _ = cr.Params["challenge_id"].(string)
|
||||||
|
}
|
||||||
if phone == "" || strings.TrimSpace(challengeID) == "" || strings.TrimSpace(cr.Response) == "" ||
|
if phone == "" || strings.TrimSpace(challengeID) == "" || strings.TrimSpace(cr.Response) == "" ||
|
||||||
(registrationPhone != "" && registrationPhone != phone) {
|
(registrationPhone != "" && registrationPhone != phone) {
|
||||||
s.queueOut(decodeStoreError(types.ErrCredentials, msg.Id, msg.Timestamp,
|
s.queueOut(decodeStoreError(types.ErrCredentials, msg.Id, msg.Timestamp,
|
||||||
@@ -400,7 +408,15 @@ var (
|
|||||||
|
|
||||||
func validateAccountRegistrationTenant(s *Session, msg *ClientComMessage) error {
|
func validateAccountRegistrationTenant(s *Session, msg *ClientComMessage) error {
|
||||||
if msg == nil || msg.Acc == nil || msg.Acc.RegistrationType == nil {
|
if msg == nil || msg.Acc == nil || msg.Acc.RegistrationType == nil {
|
||||||
return errRegistrationTypeRequired
|
if msg != nil && msg.Acc != nil && s != nil && !strings.EqualFold(s.tenantCode, imDefaultTenantCode) {
|
||||||
|
registrationType := registrationTypeEnterprise
|
||||||
|
msg.Acc.RegistrationType = ®istrationType
|
||||||
|
if strings.TrimSpace(msg.Acc.TenantCode) == "" {
|
||||||
|
msg.Acc.TenantCode = s.tenantCode
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return errRegistrationTypeRequired
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tenantCode := strings.TrimSpace(msg.Acc.TenantCode)
|
tenantCode := strings.TrimSpace(msg.Acc.TenantCode)
|
||||||
switch *msg.Acc.RegistrationType {
|
switch *msg.Acc.RegistrationType {
|
||||||
@@ -427,6 +443,51 @@ func validateAccountRegistrationTenant(s *Session, msg *ClientComMessage) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isLegacyRegistrationSMSCode(value string) bool {
|
||||||
|
if len(value) != imVerificationCodeLength {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range value {
|
||||||
|
if value[i] < '0' || value[i] > '9' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func attachLegacyRegistrationSMSChallenge(tenantID types.TenantID, cr *MsgCredClient, phone string, now time.Time) error {
|
||||||
|
if store.Verifications == nil {
|
||||||
|
return types.ErrInternal
|
||||||
|
}
|
||||||
|
phoneHash := hashIMSecret(tenantID, "register", phone, "phone")
|
||||||
|
vc, err := store.Verifications.GetActive(tenantID, "register", phoneHash, now)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if vc.CodeHash != hashIMSecret(tenantID, vc.Scene, vc.ChallengeID, vc.PhoneHash, strings.TrimSpace(cr.Response)) {
|
||||||
|
nextState := types.VerificationStatePending
|
||||||
|
if vc.Attempts+1 >= vc.MaxAttempts {
|
||||||
|
nextState = types.VerificationStateLocked
|
||||||
|
}
|
||||||
|
_ = store.Verifications.Fail(tenantID, vc.ChallengeID, nextState)
|
||||||
|
return types.ErrInvalidResponse
|
||||||
|
}
|
||||||
|
token, err := randomIMToken(32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tokenHash := hashIMSecret(tenantID, vc.Scene, vc.ChallengeID, vc.PhoneHash, token)
|
||||||
|
if err = store.Verifications.MarkVerified(tenantID, vc.ChallengeID, tokenHash, now); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cr.Params == nil {
|
||||||
|
cr.Params = map[string]any{}
|
||||||
|
}
|
||||||
|
cr.Params["challenge_id"] = vc.ChallengeID
|
||||||
|
cr.Response = token
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func registrationTenantErrorParams(err error) map[string]any {
|
func registrationTenantErrorParams(err error) map[string]any {
|
||||||
params := map[string]any{"what": "registration_type", "reason": "REGISTRATION_TYPE_INVALID"}
|
params := map[string]any{"what": "registration_type", "reason": "REGISTRATION_TYPE_INVALID"}
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -83,6 +84,70 @@ func TestRegistrationSecretForAccount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateAccountRegistrationTenantDefaultsEnterpriseFromSession(t *testing.T) {
|
||||||
|
msg := &ClientComMessage{Acc: &MsgClientAcc{}}
|
||||||
|
s := &Session{tenantCode: "system"}
|
||||||
|
|
||||||
|
if err := validateAccountRegistrationTenant(s, msg); err != nil {
|
||||||
|
t.Fatalf("validateAccountRegistrationTenant returned %v", err)
|
||||||
|
}
|
||||||
|
if msg.Acc.RegistrationType == nil || *msg.Acc.RegistrationType != registrationTypeEnterprise {
|
||||||
|
t.Fatalf("registration type was not defaulted to enterprise: %#v", msg.Acc.RegistrationType)
|
||||||
|
}
|
||||||
|
if msg.Acc.TenantCode != "system" {
|
||||||
|
t.Fatalf("tenant code default = %q, want system", msg.Acc.TenantCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateAccountRegistrationTenantStillRequiresPersonalType(t *testing.T) {
|
||||||
|
err := validateAccountRegistrationTenant(&Session{tenantCode: imDefaultTenantCode}, &ClientComMessage{Acc: &MsgClientAcc{}})
|
||||||
|
if err != errRegistrationTypeRequired {
|
||||||
|
t.Fatalf("got %v, want registration type required", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttachLegacyRegistrationSMSChallenge(t *testing.T) {
|
||||||
|
oldVerifications := store.Verifications
|
||||||
|
defer func() {
|
||||||
|
store.Verifications = oldVerifications
|
||||||
|
}()
|
||||||
|
|
||||||
|
tenantID := types.TenantID(7)
|
||||||
|
phone := "+8618612345678"
|
||||||
|
code := "123456"
|
||||||
|
phoneHash := hashIMSecret(tenantID, "register", phone, "phone")
|
||||||
|
challengeID := "challenge-legacy"
|
||||||
|
store.Verifications = &testVerificationStore{active: &types.VerificationCode{
|
||||||
|
TenantID: tenantID,
|
||||||
|
ChallengeID: challengeID,
|
||||||
|
Scene: "register",
|
||||||
|
PhoneHash: phoneHash,
|
||||||
|
CodeHash: hashIMSecret(tenantID, "register", challengeID, phoneHash, code),
|
||||||
|
State: types.VerificationStatePending,
|
||||||
|
MaxAttempts: 5,
|
||||||
|
ExpiresAt: time.Now().UTC().Add(time.Minute),
|
||||||
|
}}
|
||||||
|
|
||||||
|
cred := &MsgCredClient{Method: "tel", Value: phone, Response: code}
|
||||||
|
if err := attachLegacyRegistrationSMSChallenge(tenantID, cred, phone, time.Now().UTC()); err != nil {
|
||||||
|
t.Fatalf("attachLegacyRegistrationSMSChallenge returned %v", err)
|
||||||
|
}
|
||||||
|
if cred.Params["challenge_id"] != challengeID {
|
||||||
|
t.Fatalf("challenge id = %#v, want %q", cred.Params["challenge_id"], challengeID)
|
||||||
|
}
|
||||||
|
if cred.Response == code || strings.TrimSpace(cred.Response) == "" {
|
||||||
|
t.Fatalf("legacy code was not replaced by verification token: %q", cred.Response)
|
||||||
|
}
|
||||||
|
verifications := store.Verifications.(*testVerificationStore)
|
||||||
|
if !verifications.verified {
|
||||||
|
t.Fatal("verification challenge was not marked verified")
|
||||||
|
}
|
||||||
|
wantHash := hashIMSecret(tenantID, "register", challengeID, phoneHash, cred.Response)
|
||||||
|
if verifications.tokenHash != wantHash {
|
||||||
|
t.Fatalf("token hash mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRegistrationPublicWithUsername(t *testing.T) {
|
func TestRegistrationPublicWithUsername(t *testing.T) {
|
||||||
if got := registrationPublicWithUsername(nil, "alice").(map[string]any)["fn"]; got != "alice" {
|
if got := registrationPublicWithUsername(nil, "alice").(map[string]any)["fn"]; got != "alice" {
|
||||||
t.Fatalf("got fn=%v", got)
|
t.Fatalf("got fn=%v", got)
|
||||||
|
|||||||
Reference in New Issue
Block a user