Add option for trusted providers to associate with existing accounts. (fixes #252)
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
@@ -636,14 +636,14 @@ async fn decide_user_id(
|
|||||||
];
|
];
|
||||||
|
|
||||||
for choice in choices.into_iter().flatten() {
|
for choice in choices.into_iter().flatten() {
|
||||||
if let Some(user_id) = try_user_id(services, &choice, false).await {
|
if let Some(user_id) = try_user_id(services, provider, &choice, false).await {
|
||||||
return Ok(user_id);
|
return Ok(user_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let length = Some(15..23);
|
let length = Some(15..23);
|
||||||
let unique_id = truncate_deterministic(unique_id, length).to_lowercase();
|
let unique_id = truncate_deterministic(unique_id, length).to_lowercase();
|
||||||
if let Some(user_id) = try_user_id(services, &unique_id, true).await {
|
if let Some(user_id) = try_user_id(services, provider, &unique_id, true).await {
|
||||||
return Ok(user_id);
|
return Ok(user_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,8 +653,9 @@ async fn decide_user_id(
|
|||||||
#[tracing::instrument(level = "debug", skip_all, fields(username))]
|
#[tracing::instrument(level = "debug", skip_all, fields(username))]
|
||||||
async fn try_user_id(
|
async fn try_user_id(
|
||||||
services: &Services,
|
services: &Services,
|
||||||
|
provider: &Provider,
|
||||||
username: &str,
|
username: &str,
|
||||||
may_exist: bool,
|
unique_id: bool,
|
||||||
) -> Option<OwnedUserId> {
|
) -> Option<OwnedUserId> {
|
||||||
let server_name = services.globals.server_name();
|
let server_name = services.globals.server_name();
|
||||||
let user_id = parse_user_id(server_name, username)
|
let user_id = parse_user_id(server_name, username)
|
||||||
@@ -671,7 +672,15 @@ async fn try_user_id(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if services.users.exists(&user_id).await {
|
if services.users.exists(&user_id).await {
|
||||||
debug_warn!(?username, "Username exists.");
|
if provider.trusted {
|
||||||
|
info!(
|
||||||
|
?username,
|
||||||
|
provider = ?provider.brand,
|
||||||
|
"Authorizing trusted provider access to existing account."
|
||||||
|
);
|
||||||
|
|
||||||
|
return Some(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
if services
|
if services
|
||||||
.users
|
.users
|
||||||
@@ -680,11 +689,12 @@ async fn try_user_id(
|
|||||||
.ok()
|
.ok()
|
||||||
.is_none_or(|origin| origin != "sso")
|
.is_none_or(|origin| origin != "sso")
|
||||||
{
|
{
|
||||||
debug_warn!(?username, "Username has non-sso origin.");
|
debug_warn!(?username, "Existing username has non-sso origin.");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !may_exist {
|
if !unique_id {
|
||||||
|
debug_warn!(?username, "Username exists.");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2741,6 +2741,25 @@ pub struct IdentityProvider {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub userid_claims: BTreeSet<String>,
|
pub userid_claims: BTreeSet<String>,
|
||||||
|
|
||||||
|
/// Trusted providers can cause username conflicts (i.e. account hijacking)
|
||||||
|
/// but this is precisely how an existing matrix account can be associated
|
||||||
|
/// with a provider. When this option is set to true, the way we compute a
|
||||||
|
/// Matrix UserId from userinfo claims is inverted: we find the first
|
||||||
|
/// matching user and grant access to it. Whereas by default, when set to
|
||||||
|
/// false, we skip matching users and register the first available username;
|
||||||
|
/// falling-back to random characters to avoid conflicts.
|
||||||
|
///
|
||||||
|
/// Only set this option to true for providers you self-host and control.
|
||||||
|
/// Never set this option to true for the public providers such as GitHub,
|
||||||
|
/// GitLab, etc.
|
||||||
|
///
|
||||||
|
/// Note that associating an existing user with an untrusted provider is
|
||||||
|
/// still possible but only with the command '!admin query oauth associate'.
|
||||||
|
///
|
||||||
|
/// default: false
|
||||||
|
#[serde(default)]
|
||||||
|
pub trusted: bool,
|
||||||
|
|
||||||
/// Optional extra path components after the issuer_url leading to the
|
/// Optional extra path components after the issuer_url leading to the
|
||||||
/// location of the `.well-known` directory used for discovery. If the path
|
/// location of the `.well-known` directory used for discovery. If the path
|
||||||
/// starts with a slash it will be treated as absolute, meaning overwriting
|
/// starts with a slash it will be treated as absolute, meaning overwriting
|
||||||
|
|||||||
@@ -2343,6 +2343,23 @@
|
|||||||
#
|
#
|
||||||
#userid_claims = []
|
#userid_claims = []
|
||||||
|
|
||||||
|
# Trusted providers can cause username conflicts (i.e. account hijacking)
|
||||||
|
# but this is precisely how an existing matrix account can be associated
|
||||||
|
# with a provider. When this option is set to true, the way we compute a
|
||||||
|
# Matrix UserId from userinfo claims is inverted: we find the first
|
||||||
|
# matching user and grant access to it. Whereas by default, when set to
|
||||||
|
# false, we skip matching users and register the first available username;
|
||||||
|
# falling-back to random characters to avoid conflicts.
|
||||||
|
#
|
||||||
|
# Only set this option to true for providers you self-host and control.
|
||||||
|
# Never set this option to true for the public providers such as GitHub,
|
||||||
|
# GitLab, etc.
|
||||||
|
#
|
||||||
|
# Note that associating an existing user with an untrusted provider is
|
||||||
|
# still possible but only with the command '!admin query oauth associate'.
|
||||||
|
#
|
||||||
|
#trusted = false
|
||||||
|
|
||||||
# Optional extra path components after the issuer_url leading to the
|
# Optional extra path components after the issuer_url leading to the
|
||||||
# location of the `.well-known` directory used for discovery. If the path
|
# location of the `.well-known` directory used for discovery. If the path
|
||||||
# starts with a slash it will be treated as absolute, meaning overwriting
|
# starts with a slash it will be treated as absolute, meaning overwriting
|
||||||
|
|||||||
Reference in New Issue
Block a user