feat: allow setting password and login type from superadmin UI

This commit is contained in:
Ruben Fiszel
2024-11-14 13:12:40 +01:00
parent 47424b1446
commit 0be1a3a09d
11 changed files with 234 additions and 78 deletions

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT flow_status AS \"_id!: Json<Box<RawValue>>\" FROM queue WHERE id = $1 AND workspace_id = $2 LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "_id!: Json<Box<RawValue>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
true
]
},
"hash": "0f04f42a596b6759a84ba7d26ea76f06c6077c619c0ab1ac4edf633b22df98c3"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE password SET login_type = $1 WHERE email = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text"
]
},
"nullable": []
},
"hash": "349396e8fdd96d45875110bc06767e6eb876792ec8f83e9b03c2fb46bb12e0b9"
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT raw_flow->'modules'->($1)->'value'->>'type' = 'flow' FROM queue WHERE id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Uuid"
]
},
"nullable": [
null
]
},
"hash": "3e539fef054ad31bc1736e27276087775a721a6ee7ae35b03fd4ce3563ea3838"
}

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT raw_flow->'modules'->($1)::int AS \"_id: Json<Box<RawValue>>\" FROM queue WHERE id = $2 AND workspace_id = $3 LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "_id: Json<Box<RawValue>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Int4",
"Uuid",
"Text"
]
},
"nullable": [
null
]
},
"hash": "cd40b9c552d76664a552457c4a9610c021a0a5b63ffe5afd7878385c8af6bc6c"
}

View File

@@ -1 +1 @@
e3df64af864f9d3546a97ff21f719c553e34ff1c
0d9c8813acd28848515c736e7b684220b5a785a3

View File

@@ -283,6 +283,71 @@ paths:
text/plain:
schema:
type: string
/users/set_password_of/{user}:
post:
summary: set password for a specific user (require super admin)
operationId: setPasswordForUser
tags:
- user
parameters:
- name: user
in: path
required: true
schema:
type: string
requestBody:
description: set password
required: true
content:
application/json:
schema:
type: object
properties:
password:
type: string
required:
- password
responses:
"200":
description: password set
content:
text/plain:
schema:
type: string
/users/set_login_type/{user}:
post:
summary: set login type for a specific user (require super admin)
operationId: setLoginTypeForUser
tags:
- user
parameters:
- name: user
in: path
required: true
schema:
type: string
requestBody:
description: set login type
required: true
content:
application/json:
schema:
type: object
properties:
login_type:
type: string
required:
- login_type
responses:
"200":
description: login type set
content:
text/plain:
schema:
type: string
/users/create:
post:

View File

@@ -90,6 +90,9 @@ pub fn global_service() -> Router {
.route("/accept_invite", post(accept_invite))
.route("/list_as_super_admin", get(list_users_as_super_admin))
.route("/setpassword", post(set_password))
.route("/set_password_of/:user", post(set_password_of_user))
.route("/set_login_type/:user", post(set_login_type))
.route("/create", post(create_user))
.route("/update/:user", post(update_user))
.route("/delete/:user", delete(delete_user))
@@ -866,6 +869,12 @@ pub struct EditPassword {
pub password: String,
}
#[derive(Deserialize)]
pub struct EditLoginType {
pub login_type: String,
}
#[derive(FromRow, Serialize)]
pub struct TruncatedToken {
pub label: Option<String>,
@@ -2028,7 +2037,52 @@ async fn set_password(
authed: ApiAuthed,
Json(ep): Json<EditPassword>,
) -> Result<String> {
crate::users_ee::set_password(db, argon2, authed, ep).await
let email = authed.email.clone();
crate::users_ee::set_password(db, argon2, authed, &email, ep).await
}
async fn set_password_of_user(
Extension(db): Extension<DB>,
Extension(argon2): Extension<Arc<Argon2<'_>>>,
Path(email): Path<String>,
authed: ApiAuthed,
Json(ep): Json<EditPassword>,
) -> Result<String> {
require_super_admin(&db, &authed.email).await?;
crate::users_ee::set_password(db, argon2, authed, &email, ep).await
}
async fn set_login_type(
Extension(db): Extension<DB>,
Path(email): Path<String>,
authed: ApiAuthed,
Json(et): Json<EditLoginType>,
) -> Result<String> {
require_super_admin(&db, &authed.email).await?;
let mut tx = db.begin().await?;
sqlx::query!(
"UPDATE password SET login_type = $1 WHERE email = $2",
et.login_type,
email
)
.execute(&mut *tx)
.await?;
audit_log(
&mut *tx,
&authed,
"users.set_login_type",
ActionKind::Update,
"global",
Some(&email),
None,
)
.await?;
tx.commit().await?;
Ok(format!("login type of {} updated to {}", email, et.login_type))
}
async fn login(

View File

@@ -27,6 +27,7 @@ pub async fn set_password(
_db: DB,
_argon2: Arc<Argon2<'_>>,
_authed: ApiAuthed,
_user_email: &str,
_ep: EditPassword,
) -> Result<String> {
Err(Error::InternalErr(

View File

@@ -72,11 +72,13 @@
</script>
<div class="flex flex-col max-w-2xl p-2">
{#if isConflict}
<span class="text-sm mb-2 leading-6 font-semibold"
>{isConflict ? 'Fix username conflict' : 'Change username'}</span
>Fix username conflict</span
>
{/if}
<span class="text-xs mb-1 leading-6"
<span class="text-sm font-semibold mb-1 leading-6"
>{isConflict ? 'Auto-generated instance username' : 'New username'}</span
>
<input

View File

@@ -5,17 +5,36 @@
import Popup from './common/popup/Popup.svelte'
import { offset, flip, shift } from 'svelte-floating-ui/dom'
import ChangeInstanceUsernameInner from './ChangeInstanceUsernameInner.svelte'
import { UserService } from '$lib/gen'
import { sendUserToast } from '$lib/toast'
export let value: string | undefined
export let email: string
export let username: string | undefined = undefined
export let automateUsernameCreation: boolean = false
export let login_type: string
let password: string = ''
const dispatch = createEventDispatcher()
function save() {
function saveName() {
dispatch('save', value)
}
async function savePassword() {
if (password.length < 5) {
sendUserToast('Password must be at least 5 characters long', true)
return
}
await UserService.setPasswordForUser({user: email, requestBody:{ password }})
sendUserToast(`Password updated for ${email}`)
}
async function saveLoginType() {
await UserService.setLoginTypeForUser({user: email, requestBody:{ login_type }})
sendUserToast(`Login type updated for ${email}`)
dispatch('refresh')
}
</script>
<Popup
@@ -34,7 +53,7 @@
<ChangeInstanceUsernameInner {email} {username} on:renamed />
{/if}
<label class="block text-primary">
<div class="pb-1 text-xs text-secondary">Name</div>
<div class="pb-2 text-sm font-semibold text-primary">Name</div>
<div class="flex w-full">
<input
type="text"
@@ -44,7 +63,7 @@
on:keydown|stopPropagation
on:keypress|stopPropagation={({ key }) => {
if (key === 'Enter') {
save()
saveName()
close(null)
}
}}
@@ -57,12 +76,78 @@
btnClasses="mt-2 "
aria-label="Save ID"
on:click={() => {
save()
saveName()
close(null)
}}
>
Update name
</Button>
</label>
<label class="block text-primary">
<div class="pb-2 text-sm font-semibold text-primary">Password</div>
<div class="flex w-full">
<input
type="password"
bind:value={password}
class="!w-auto grow"
on:click|stopPropagation={() => {}}
on:keydown|stopPropagation
on:keypress|stopPropagation={({ key }) => {
if (key === 'Enter') {
savePassword()
close(null)
}
}}
/>
</div>
<Button
size="xs"
color="blue"
buttonType="button"
btnClasses="mt-2 "
aria-label="Save ID"
on:click={() => {
savePassword()
close(null)
}}
>
Update password
</Button>
</label>
<label class="block text-primary">
<div class="pb-2 text-sm font-semibold text-primary">Login type</div>
<div class="text-xs text-secondary mb-2">
Must match exact SSO name, "password" or "saml". Examples: password, google, saml, microsoft
</div>
<div class="flex w-full">
<input
type="text"
bind:value={login_type}
class="!w-auto grow"
on:click|stopPropagation={() => {}}
on:keydown|stopPropagation
on:keypress|stopPropagation={({ key }) => {
if (key === 'Enter') {
saveLoginType()
close(null)
}
}}
/>
</div>
<Button
size="xs"
color="blue"
buttonType="button"
btnClasses="mt-2 "
aria-label="Save login type"
on:click={() => {
saveLoginType()
close(null)
}}
>
Update login type
</Button>
</label>
</div>
</Popup>

View File

@@ -276,9 +276,13 @@
<td>
<div class="flex flex-row gap-x-1 justify-end">
<InstanceNameEditor
login_type={login_type}
value={name}
{username}
{email}
on:refresh={() => {
listUsers(activeOnly)
}}
on:save={(e) => {
updateName(e.detail, email)
}}