feat(username|email): pass1: normalize auth.user data

username: now optional, if defined 2..64 chars
    password: now optional (no mode __NO_PASSWORD...__)
    oidc: now optional

    important: if need Nextcloud, username must be defined
This commit is contained in:
Edouard Vanbelle
2026-06-02 21:21:24 +02:00
parent 37b1c2703b
commit d57a50d056
17 changed files with 418 additions and 247 deletions
+5 -5
View File
@@ -156,7 +156,7 @@ impl TokenServicePort for JwtTokenService {
// Log information for debugging
tracing::debug!(
"Generating token for user: {}, id: {}, role: {}",
user.username(),
user.display_for_audit(),
user.id(),
user.role()
);
@@ -166,7 +166,7 @@ impl TokenServicePort for JwtTokenService {
exp: now + self.access_token_expiry,
iat: now,
jti: Uuid::new_v4().to_string(),
username: user.username().to_string(),
username: user.username().unwrap_or("").to_string(),
email: user.email().to_string(),
role: format!("{}", user.role()),
};
@@ -267,9 +267,9 @@ mod tests {
fn create_test_user() -> User {
User::from_data(
Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap(),
"testuser".to_string(),
Some("testuser".to_string()),
"test@example.com".to_string(),
"hashed_password".to_string(),
Some("hashed_password".to_string()),
UserRole::User,
1024 * 1024 * 1024, // 1GB
0,
@@ -297,7 +297,7 @@ mod tests {
.validate_token(&token)
.expect("Should validate token");
assert_eq!(claims.sub, user.id().to_string());
assert_eq!(claims.username, user.username());
assert_eq!(Some(claims.username.as_str()), user.username());
assert_eq!(claims.email, user.email());
}
+5 -5
View File
@@ -959,7 +959,7 @@ impl AuthorizationEngine for PgAclEngine {
)
SELECT ag.resource_type, ag.resource_id, rp.first_shared_at,
ag.subject_type, ag.subject_id,
COALESCE(u.username, sg.name::text, sh.item_name, fi.name, fld.name, ag.subject_id::text) AS subject_display,
COALESCE(u.username, u.email, sg.name::text, sh.item_name, fi.name, fld.name, ag.subject_id::text) AS subject_display,
ag.id AS grant_id, ag.granted_at, ag.expires_at, ag.permission,
rp.sort_str, rp.sort_int,
(sh.password_hash IS NOT NULL) AS has_password
@@ -983,7 +983,7 @@ impl AuthorizationEngine for PgAclEngine {
WHEN ag.subject_type = 'token' AND sh.password_hash IS NOT NULL THEN 2
ELSE 3
END ASC,
LOWER(COALESCE(u.username, sg.name::text, sh.item_name, ag.subject_id::text)) ASC,
LOWER(COALESCE(u.username, u.email, sg.name::text, sh.item_name, ag.subject_id::text)) ASC,
ag.granted_at"#
)
}
@@ -1023,7 +1023,7 @@ impl AuthorizationEngine for PgAclEngine {
ag.resource_id,
ag.subject_type,
ag.subject_id,
MAX(COALESCE(u.username, sg.name::text, sh.item_name, ag.subject_id::text)) AS subject_display,
MAX(COALESCE(u.username, u.email, sg.name::text, sh.item_name, ag.subject_id::text)) AS subject_display,
BOOL_OR(sh.password_hash IS NOT NULL) AS has_password,
MAX(CASE
WHEN ag.subject_type = 'group' THEN 0
@@ -1108,7 +1108,7 @@ impl AuthorizationEngine for PgAclEngine {
ag.resource_id,
ag.subject_type,
ag.subject_id,
MAX(COALESCE(u.username, sh.item_name, ag.subject_id::text)) AS subject_display,
MAX(COALESCE(u.username, u.email, sh.item_name, ag.subject_id::text)) AS subject_display,
BOOL_OR(sh.password_hash IS NOT NULL) AS has_password,
CASE
WHEN BOOL_OR(ag.permission = 'delete')
@@ -1196,7 +1196,7 @@ impl AuthorizationEngine for PgAclEngine {
)
SELECT ag.resource_type, ag.resource_id, rp.first_shared_at,
ag.subject_type, ag.subject_id,
COALESCE(u.username, sh.item_name, fi.name, fld.name, ag.subject_id::text) AS subject_display,
COALESCE(u.username, u.email, sh.item_name, fi.name, fld.name, ag.subject_id::text) AS subject_display,
ag.id AS grant_id, ag.granted_at, ag.expires_at, ag.permission,
NULL::text AS sort_str, NULL::bigint AS sort_int,
(sh.password_hash IS NOT NULL) AS has_password