Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(graphQL): add is_sso_user and forbid update name, password for s… #3733

Merged
merged 4 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ee/tabby-db/src/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ pub struct UserDAO {
pub id: i64,
pub email: String,
pub name: Option<String>,

// when the user is created with password, this field is set and will never be changed to None
// when the user is created with SSO, this field is None and will never be set
pub password_encrypted: Option<String>,
pub is_admin: bool,

Expand Down
2 changes: 2 additions & 0 deletions ee/tabby-schema/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ interface User {
isAdmin: Boolean!
isOwner: Boolean!
active: Boolean!
isSsoUser: Boolean!
}

"""
Expand Down Expand Up @@ -965,6 +966,7 @@ type UserSecured implements User {
active: Boolean!
authToken: String!
isPasswordSet: Boolean!
isSsoUser: Boolean!
}

type WebContextSource implements ContextSourceId & ContextSource {
Expand Down
5 changes: 5 additions & 0 deletions ee/tabby-schema/src/schema/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ pub struct UserSecured {
pub auth_token: String,
pub is_password_set: bool,

// is_sso_user is used to indicate if the user is created by SSO
// and should not be able to change Name and Password
// e.g. LDAP, OAuth users
pub is_sso_user: bool,

#[graphql(skip)]
pub policy: AccessPolicy,
}
Expand Down
1 change: 1 addition & 0 deletions ee/tabby-schema/src/schema/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct User {
pub is_admin: bool,
pub is_owner: bool,
pub active: bool,
pub is_sso_user: bool,
}

impl relay::NodeType for UserValue {
Expand Down
25 changes: 25 additions & 0 deletions ee/tabby-webserver/src/service/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ impl AuthenticationService for AuthenticationServiceImpl {
}

async fn generate_reset_password_url(&self, id: &ID) -> Result<String> {
let user = self.get_user(id).await?;
if user.is_sso_user {
bail!("Cannot generate reset password url for SSO users");
}

let external_url = self.setting.read_network_setting().await?.external_url;
let id = id.as_rowid()?;
let user = self.db.get_user(id).await?.context("User doesn't exits")?;
Expand All @@ -179,6 +184,10 @@ impl AuthenticationService for AuthenticationServiceImpl {
return Ok(None);
};

if user.is_sso_user {
bail!("Cannot request password reset for SSO users");
}

let id = user.id.as_rowid()?;

// request_password_reset_email is invoked by the user, so we need to check for existing password reset requests to prevent spamming
Expand All @@ -200,6 +209,11 @@ impl AuthenticationService for AuthenticationServiceImpl {
let password_encrypted = password_hash(password).map_err(|_| anyhow!("Unknown error"))?;

let user_id = self.db.verify_password_reset(code).await?;
let user = self.get_user(&user_id.as_id()).await?;
if user.is_sso_user {
bail!("Password cannot be reset for SSO users");
}

let old_pass_encrypted = self
.db
.get_user(user_id)
Expand Down Expand Up @@ -227,6 +241,11 @@ impl AuthenticationService for AuthenticationServiceImpl {
bail!("Changing passwords is disabled in demo mode");
}

let user = self.get_user(id).await?;
if user.is_sso_user {
bail!("Password cannot be changed for SSO users");
}

let user = self
.db
.get_user(id.as_rowid()?)
Expand Down Expand Up @@ -280,6 +299,12 @@ impl AuthenticationService for AuthenticationServiceImpl {
if is_demo_mode() {
bail!("Changing profile data is disabled in demo mode");
}

let user = self.get_user(id).await?;
if user.is_sso_user {
bail!("Name cannot be changed for SSO users");
}

let id = id.as_rowid()?;
self.db.update_user_name(id, name).await?;
Ok(())
Expand Down
5 changes: 5 additions & 0 deletions ee/tabby-webserver/src/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,11 @@ impl UserSecuredExt for tabby_schema::auth::UserSecured {
created_at: val.created_at,
active: val.active,
is_password_set: val.password_encrypted.is_some(),

// when a user created by registration, password_encrypted is set
// when a user created by SSO, password_encrypted is not set
// so, we can determine if a user is SSO user by checking if password_encrypted is set
is_sso_user: val.password_encrypted.is_none(),
}
}
}
Expand Down
Loading