Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b59a4a9
feat(web): stop enforcing root password
dgdavid Feb 11, 2025
fa82860
fix(web): drop auto login from user form
dgdavid Feb 11, 2025
150b553
fix(web): overrides PF form group styles
dgdavid Feb 12, 2025
67aba5d
fix(web): improve user form
dgdavid Feb 12, 2025
25e8d16
feat(web): add a SplitButton component
dgdavid Feb 13, 2025
004834e
fix(web): use TypeScript for SplitButton props validation
dgdavid Feb 13, 2025
ca7b81a
feat(web): rework FirstUser section interface
dgdavid Feb 13, 2025
a3be42d
fix(web): use <a> instead of <button> for Page.Cancel
dgdavid Feb 15, 2025
12be213
fix(web): add basic unit test for FirstUserForm
dgdavid Feb 15, 2025
0924583
fix(web): adapt BootSelection unit test
dgdavid Feb 15, 2025
a899dd4
feat(web): add form for root user auth methods
dgdavid Feb 16, 2025
5c8371d
feat(web): rework root authentication section
dgdavid Feb 16, 2025
db0cea6
web: rename RootAuthMethods to RootUser
dgdavid Feb 16, 2025
93ae41d
web: drop no longer needed components
dgdavid Feb 16, 2025
cbd2e7f
web: minor changes in first user section
dgdavid Feb 16, 2025
6918d92
web: add basic unit tests for RootUserForm
dgdavid Feb 17, 2025
c70444e
fix(web): styles adjustments
dgdavid Feb 17, 2025
8e997a7
web: CSS adjustments to improve split button appearance
dgdavid Feb 17, 2025
8052ed6
web: use Authentication instead of Users
dgdavid Feb 17, 2025
89cdb02
fix(web): wording adjustments
dgdavid Feb 17, 2025
afb1a54
feat(web): allow dealing with hashed passwords too
dgdavid Feb 17, 2025
48858e7
f ix(web): correct order of then/catch methods in first user form
dgdavid Feb 17, 2025
0affcce
feat(ruby): remove the autologin property
imobachgs Feb 17, 2025
76c3949
feat(ruby): expose the root password
imobachgs Feb 17, 2025
a30ba24
feat(rust): remove the autologin property
imobachgs Feb 17, 2025
9aaf36d
feat(rust): adapt the web server to the users API changes
imobachgs Feb 17, 2025
e535cb6
docs(ruby): update org.opensuse.Agama.Users1 documentation
imobachgs Feb 17, 2025
88e6c49
fix(rust): fix UsersStore
imobachgs Feb 17, 2025
c7c424c
fix(web): completely drop autologin support
dgdavid Feb 18, 2025
fa879d1
fix(web): expose password in user form for easier editing
dgdavid Feb 18, 2025
7fa6660
fix(web): expose password in root user form
dgdavid Feb 18, 2025
6c796a3
fix: use "sshPublicKey" instead of "sshkey"
imobachgs Feb 18, 2025
52573bc
web: fix unit tests broken in previous commits
dgdavid Feb 18, 2025
6fedc4a
fix(web): revert no longer needed patch
dgdavid Feb 18, 2025
04b60aa
fix(ruby): fix FirstUser documentation
imobachgs Feb 18, 2025
d695b6d
fix(web): use Authentication instead of Users
dgdavid Feb 18, 2025
e74c821
fix(web): improve Install button Tooltip behavior
dgdavid Feb 18, 2025
a784726
fix(web): adapt unit test
dgdavid Feb 18, 2025
97bada9
feat: expose passwords and drop autologin (#2005)
imobachgs Feb 18, 2025
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
30 changes: 17 additions & 13 deletions doc/dbus/bus/org.opensuse.Agama.Users1.bus.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/opensuse/Agama/Users1">
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="xml_data" direction="out" type="s"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface_name" direction="in" type="s"/>
Expand All @@ -26,10 +22,22 @@
<arg name="invalidated_properties" type="as"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="xml_data" direction="out" type="s"/>
</method>
</interface>
<interface name="org.opensuse.Agama1.Issues">
<property type="a(sssuu)" name="All" access="read"/>
</interface>
<interface name="org.opensuse.Agama1.ServiceStatus">
<property type="aa{sv}" name="All" access="read"/>
<property type="u" name="Current" access="read"/>
</interface>
<interface name="org.opensuse.Agama.Users1">
<method name="SetRootPassword">
<arg name="Value" direction="in" type="s"/>
<arg name="Encrypted" direction="in" type="b"/>
<arg name="Hashed" direction="in" type="b"/>
<arg name="result" direction="out" type="u"/>
</method>
<method name="RemoveRootPassword">
Expand All @@ -43,7 +51,7 @@
<arg name="FullName" direction="in" type="s"/>
<arg name="UserName" direction="in" type="s"/>
<arg name="Password" direction="in" type="s"/>
<arg name="AutoLogin" direction="in" type="b"/>
<arg name="HashedPassword" direction="in" type="b"/>
<arg name="data" direction="in" type="a{sv}"/>
<arg name="result" direction="out" type="(bas)"/>
</method>
Expand All @@ -53,11 +61,7 @@
<method name="Write">
<arg name="result" direction="out" type="u"/>
</method>
<property type="b" name="RootPasswordSet" access="read"/>
<property type="s" name="RootSSHKey" access="read"/>
<property type="(sbs)" name="RootUser" access="read"/>
<property type="(sssba{sv})" name="FirstUser" access="read"/>
</interface>
<interface name="org.opensuse.Agama1.Issues">
<property type="a(ssuu)" name="All" access="read"/>
</interface>
</node>
50 changes: 3 additions & 47 deletions doc/dbus/org.opensuse.Agama.Users1.doc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,23 @@
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/opensuse/Agama/Users1">
<interface name="org.opensuse.Agama.Users1">
<!--
SetRootPassword:

If @Encrypted is set to true, it means that already encrypted password is sent

Example:
<programlisting>SetRootPassword("test", false)</programlisting>
-->
<method name="SetRootPassword">
<arg name="Value" direction="in" type="s"/>
<arg name="Encrypted" direction="in" type="b"/>
<arg name="Hashed" direction="in" type="b"/>
<arg name="result" direction="out" type="u"/>
</method>

<method name="RemoveRootPassword">
<arg name="result" direction="out" type="u"/>
</method>

<!--
SetRootSSHKey:

Set root ssh public keys. Use empty string to unset it.

Example:
<programlisting>SetRootSSHKey("idrsa long key")</programlisting>
-->
<method name="SetRootSSHKey">
<arg name="Value" direction="in" type="s"/>
<arg name="result" direction="out" type="u"/>
</method>

<!--
SetFirstUser:

Sets one non root user after installation.
@FullName and @UserName have to follow restrictions
for respective /etc/passwd entry. To unset it use empty @UserName.
-->
<method name="SetFirstUser">
<arg name="FullName" direction="in" type="s"/>
<arg name="UserName" direction="in" type="s"/>
<arg name="Password" direction="in" type="s"/>
<arg name="AutoLogin" direction="in" type="b"/>
<arg name="HashedPassword" direction="in" type="b"/>
<arg name="data" direction="in" type="a{sv}"/>
<arg name="result" direction="out" type="(bas)"/>
</method>
Expand All @@ -54,25 +28,7 @@
<method name="Write">
<arg name="result" direction="out" type="u"/>
</method>

<!--
RootPasswordSet:
whenever root password will be set by installer
-->
<property type="b" name="RootPasswordSet" access="read"/>

<!--
RootSSHKey:
Root public ssh key that can be used to login to machine.
Can be empty which means not set
-->
<property type="s" name="RootSSHKey" access="read"/>

<!--
FirstUser:
struct( string FullName, string UserName, string Password, boolean AutoLogin, map AdditionalData)
Info about first user to set. if Username is empty, it means not set and other values can be ignored
-->
<property type="(sbs)" name="RootUser" access="read"/>
<property type="(sssba{sv})" name="FirstUser" access="read"/>
</interface>
</node>
2 changes: 1 addition & 1 deletion rust/agama-lib/src/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub mod proxies;
mod settings;
mod store;

pub use client::{FirstUser, UsersClient};
pub use client::{FirstUser, RootUser, UsersClient};
pub use http_client::UsersHTTPClient;
pub use settings::{FirstUserSettings, RootUserSettings, UserSettings};
pub use store::UsersStore;
56 changes: 41 additions & 15 deletions rust/agama-lib/src/users/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

//! Implements a client to access Agama's users service.

use super::proxies::{FirstUser as FirstUserFromDBus, Users1Proxy};
use super::proxies::{FirstUser as FirstUserFromDBus, RootUser as RootUserFromDBus, Users1Proxy};
use crate::error::ServiceError;
use serde::{Deserialize, Serialize};
use zbus::Connection;
Expand All @@ -37,8 +37,6 @@ pub struct FirstUser {
pub password: String,
/// Whether the password is hashed (true) or is plain text (false)
pub hashed_password: bool,
/// Whether auto-login should enabled or not
pub autologin: bool,
}

impl FirstUser {
Expand All @@ -49,7 +47,42 @@ impl FirstUser {
user_name: data.1,
password: data.2,
hashed_password: data.3,
autologin: data.4,
})
}
}

/// Represents the settings for the first user
#[derive(Serialize, Deserialize, Clone, Debug, Default, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct RootUser {
/// Root user password
#[serde(skip_serializing_if = "Option::is_none")]
pub password: Option<String>,
/// Whether the password is hashed (true) or is plain text (false or None)
pub hashed_password: Option<bool>,
/// SSH public key
#[serde(skip_serializing_if = "Option::is_none")]
pub ssh_public_key: Option<String>,
}

impl RootUser {
pub fn from_dbus(dbus_data: RootUserFromDBus) -> zbus::Result<Self> {
let password = if dbus_data.0.is_empty() {
None
} else {
Some(dbus_data.0)
};

let ssh_public_key = if dbus_data.2.is_empty() {
None
} else {
Some(dbus_data.2)
};

Ok(Self {
password,
hashed_password: Some(dbus_data.1),
ssh_public_key,
})
}
}
Expand All @@ -72,6 +105,10 @@ impl<'a> UsersClient<'a> {
FirstUser::from_dbus(self.users_proxy.first_user().await)
}

pub async fn root_user(&self) -> zbus::Result<RootUser> {
RootUser::from_dbus(self.users_proxy.root_user().await?)
}

/// SetRootPassword method
pub async fn set_root_password(&self, value: &str, hashed: bool) -> Result<u32, ServiceError> {
Ok(self.users_proxy.set_root_password(value, hashed).await?)
Expand All @@ -81,16 +118,6 @@ impl<'a> UsersClient<'a> {
Ok(self.users_proxy.remove_root_password().await?)
}

/// Whether the root password is set or not
pub async fn is_root_password(&self) -> Result<bool, ServiceError> {
Ok(self.users_proxy.root_password_set().await?)
}

/// Returns the SSH key for the root user
pub async fn root_ssh_key(&self) -> zbus::Result<String> {
self.users_proxy.root_sshkey().await
}

/// SetRootSSHKey method
pub async fn set_root_sshkey(&self, value: &str) -> Result<u32, ServiceError> {
Ok(self.users_proxy.set_root_sshkey(value).await?)
Expand All @@ -107,7 +134,6 @@ impl<'a> UsersClient<'a> {
&first_user.user_name,
&first_user.password,
first_user.hashed_password,
first_user.autologin,
std::collections::HashMap::new(),
)
.await
Expand Down
22 changes: 5 additions & 17 deletions rust/agama-lib/src/users/http_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
// To contact SUSE LLC about this file by physical or electronic mail, you may
// find current contact information at www.suse.com.

use super::client::FirstUser;
use crate::users::model::{RootConfig, RootPatchSettings};
use super::client::{FirstUser, RootUser};
use crate::users::model::RootPatchSettings;
use crate::{base_http_client::BaseHTTPClient, error::ServiceError};

pub struct UsersHTTPClient {
Expand All @@ -46,39 +46,27 @@ impl UsersHTTPClient {
result
}

async fn root_config(&self) -> Result<RootConfig, ServiceError> {
pub async fn root_user(&self) -> Result<RootUser, ServiceError> {
self.client.get("/users/root").await
}

/// Whether the root password is set or not
pub async fn is_root_password(&self) -> Result<bool, ServiceError> {
let root_config = self.root_config().await?;
Ok(root_config.password)
}

/// SetRootPassword method.
/// Returns 0 if successful (always, for current backend)
pub async fn set_root_password(&self, value: &str, hashed: bool) -> Result<u32, ServiceError> {
let rps = RootPatchSettings {
sshkey: None,
ssh_public_key: None,
password: Some(value.to_owned()),
hashed_password: Some(hashed),
};
let ret = self.client.patch("/users/root", &rps).await?;
Ok(ret)
}

/// Returns the SSH key for the root user
pub async fn root_ssh_key(&self) -> Result<String, ServiceError> {
let root_config = self.root_config().await?;
Ok(root_config.sshkey)
}

/// SetRootSSHKey method.
/// Returns 0 if successful (always, for current backend)
pub async fn set_root_sshkey(&self, value: &str) -> Result<u32, ServiceError> {
let rps = RootPatchSettings {
sshkey: Some(value.to_owned()),
ssh_public_key: Some(value.to_owned()),
password: None,
hashed_password: None,
};
Expand Down
10 changes: 1 addition & 9 deletions rust/agama-lib/src/users/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,11 @@

use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Default, Serialize, Deserialize, utoipa::ToSchema)]
pub struct RootConfig {
/// returns if password for root is set or not
pub password: bool,
/// empty string mean no sshkey is specified
pub sshkey: String,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct RootPatchSettings {
/// empty string here means remove ssh key for root
pub sshkey: Option<String>,
pub ssh_public_key: Option<String>,
/// empty string here means remove password for root
pub password: Option<String>,
/// specify if patched password is provided in plain text (default) or hashed
Expand Down
24 changes: 13 additions & 11 deletions rust/agama-lib/src/users/proxies.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) [2024] SUSE LLC
// Copyright (c) [2024-2025] SUSE LLC
//
// All Rights Reserved.
//
Expand Down Expand Up @@ -31,8 +31,8 @@
//! This type implements the [D-Bus standard interfaces], (`org.freedesktop.DBus.*`) for which the
//! following zbus API can be used:
//!
//! * [`zbus::fdo::IntrospectableProxy`]
//! * [`zbus::fdo::PropertiesProxy`]
//! * [`zbus::fdo::IntrospectableProxy`]
//!
//! Consequently `zbus-xmlgen` did not generate code for the above interfaces.
//!
Expand All @@ -48,18 +48,25 @@ use zbus::proxy;
/// * user name
/// * password
/// * hashed_password (true = hashed, false = plain text)
/// * auto-login (enabled or not)
/// * some optional and additional data
// NOTE: Manually added to this file.
pub type FirstUser = (
String,
String,
String,
bool,
bool,
std::collections::HashMap<String, zbus::zvariant::OwnedValue>,
);

/// Root user as it comes from D-Bus.
///
/// It is composed of:
///
/// * password (an empty string if it is not set)
/// * hashed_password (true = hashed, false = plain text)
/// * SSH public key
pub type RootUser = (String, bool, String);

#[proxy(
default_service = "org.opensuse.Agama.Manager1",
default_path = "/org/opensuse/Agama/Users1",
Expand All @@ -80,7 +87,6 @@ pub trait Users1 {
user_name: &str,
password: &str,
hashed_password: bool,
auto_login: bool,
data: std::collections::HashMap<&str, &zbus::zvariant::Value<'_>>,
) -> zbus::Result<(bool, Vec<String>)>;

Expand All @@ -98,11 +104,7 @@ pub trait Users1 {
#[zbus(property)]
fn first_user(&self) -> zbus::Result<FirstUser>;

/// RootPasswordSet property
/// RootUser property
#[zbus(property)]
fn root_password_set(&self) -> zbus::Result<bool>;

/// RootSSHKey property
#[zbus(property, name = "RootSSHKey")]
fn root_sshkey(&self) -> zbus::Result<String>;
fn root_user(&self) -> zbus::Result<RootUser>;
}
2 changes: 0 additions & 2 deletions rust/agama-lib/src/users/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ pub struct FirstUserSettings {
pub password: Option<String>,
/// Whether the password is hashed or is plain text
pub hashed_password: Option<bool>,
/// Whether auto-login should enabled or not
pub autologin: Option<bool>,
}

/// Root user settings
Expand Down
Loading