Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
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