2022-10-01 08:08:51 +02:00
|
|
|
use std::time::Duration;
|
2019-10-31 01:48:15 +01:00
|
|
|
|
2024-02-27 10:25:02 +01:00
|
|
|
use kanidm_proto::internal::RadiusAuthToken;
|
2022-10-01 08:08:51 +02:00
|
|
|
use time::OffsetDateTime;
|
|
|
|
use uuid::Uuid;
|
2021-04-25 03:35:02 +02:00
|
|
|
|
2019-10-31 01:48:15 +01:00
|
|
|
use crate::entry::{Entry, EntryCommitted, EntryReduced};
|
2022-10-01 08:08:51 +02:00
|
|
|
use crate::idm::group::Group;
|
|
|
|
use crate::prelude::*;
|
2019-10-31 01:48:15 +01:00
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub(crate) struct RadiusAccount {
|
|
|
|
pub name: String,
|
|
|
|
pub displayname: String,
|
|
|
|
pub uuid: Uuid,
|
2024-10-25 02:36:20 +02:00
|
|
|
pub groups: Vec<Group<()>>,
|
2019-10-31 01:48:15 +01:00
|
|
|
pub radius_secret: String,
|
2020-10-10 02:31:51 +02:00
|
|
|
pub valid_from: Option<OffsetDateTime>,
|
|
|
|
pub expire: Option<OffsetDateTime>,
|
2019-10-31 01:48:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RadiusAccount {
|
|
|
|
pub(crate) fn try_from_entry_reduced(
|
2020-08-04 04:58:11 +02:00
|
|
|
value: &Entry<EntryReduced, EntryCommitted>,
|
2020-05-11 13:12:32 +02:00
|
|
|
qs: &mut QueryServerReadTransaction,
|
2019-10-31 01:48:15 +01:00
|
|
|
) -> Result<Self, OperationError> {
|
2023-09-16 04:11:06 +02:00
|
|
|
if !value.attribute_equality(Attribute::Class, &EntryClass::Account.into()) {
|
2024-10-03 02:48:28 +02:00
|
|
|
return Err(OperationError::MissingClass(ENTRYCLASS_ACCOUNT.into()));
|
2019-10-31 01:48:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
let radius_secret = value
|
2023-09-16 04:11:06 +02:00
|
|
|
.get_ava_single_secret(Attribute::RadiusSecret)
|
2024-10-03 02:48:28 +02:00
|
|
|
.ok_or_else(|| OperationError::MissingAttribute(Attribute::RadiusSecret))?
|
2019-10-31 01:48:15 +01:00
|
|
|
.to_string();
|
|
|
|
|
2020-06-24 13:17:46 +02:00
|
|
|
let name = value
|
2023-09-16 04:11:06 +02:00
|
|
|
.get_ava_single_iname(Attribute::Name)
|
2020-06-24 13:17:46 +02:00
|
|
|
.map(|s| s.to_string())
|
2024-10-03 02:48:28 +02:00
|
|
|
.ok_or_else(|| OperationError::MissingAttribute(Attribute::Name))?;
|
2019-10-31 01:48:15 +01:00
|
|
|
|
2022-05-24 02:49:34 +02:00
|
|
|
let uuid = value.get_uuid();
|
2019-10-31 01:48:15 +01:00
|
|
|
|
2020-06-24 13:17:46 +02:00
|
|
|
let displayname = value
|
2023-09-16 04:11:06 +02:00
|
|
|
.get_ava_single_utf8(Attribute::DisplayName)
|
2020-06-24 13:17:46 +02:00
|
|
|
.map(|s| s.to_string())
|
2024-10-03 02:48:28 +02:00
|
|
|
.ok_or_else(|| OperationError::MissingAttribute(Attribute::DisplayName))?;
|
2019-10-31 01:48:15 +01:00
|
|
|
|
2024-10-25 02:36:20 +02:00
|
|
|
let groups = Group::<()>::try_from_account_reduced(value, qs)?;
|
2019-10-31 01:48:15 +01:00
|
|
|
|
2023-09-16 04:11:06 +02:00
|
|
|
let valid_from = value.get_ava_single_datetime(Attribute::AccountValidFrom);
|
2020-10-10 02:31:51 +02:00
|
|
|
|
2023-09-16 04:11:06 +02:00
|
|
|
let expire = value.get_ava_single_datetime(Attribute::AccountExpire);
|
2020-10-10 02:31:51 +02:00
|
|
|
|
2019-10-31 01:48:15 +01:00
|
|
|
Ok(RadiusAccount {
|
2020-01-09 11:07:14 +01:00
|
|
|
name,
|
|
|
|
displayname,
|
2021-08-02 02:54:55 +02:00
|
|
|
uuid,
|
2020-01-09 11:07:14 +01:00
|
|
|
groups,
|
|
|
|
radius_secret,
|
2020-10-10 02:31:51 +02:00
|
|
|
valid_from,
|
|
|
|
expire,
|
2019-10-31 01:48:15 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-10-10 02:31:51 +02:00
|
|
|
fn is_within_valid_time(&self, ct: Duration) -> bool {
|
2023-05-25 00:25:16 +02:00
|
|
|
let cot = OffsetDateTime::UNIX_EPOCH + ct;
|
2020-10-10 02:31:51 +02:00
|
|
|
|
|
|
|
let vmin = if let Some(vft) = &self.valid_from {
|
2023-01-10 04:50:53 +01:00
|
|
|
// If current time greater than start time window
|
2020-10-10 02:31:51 +02:00
|
|
|
vft < &cot
|
|
|
|
} else {
|
|
|
|
// We have no time, not expired.
|
|
|
|
true
|
|
|
|
};
|
|
|
|
let vmax = if let Some(ext) = &self.expire {
|
|
|
|
// If exp greater than ct then expired.
|
|
|
|
&cot < ext
|
|
|
|
} else {
|
|
|
|
// If not present, we are not expired
|
|
|
|
true
|
|
|
|
};
|
|
|
|
// Mix the results
|
|
|
|
vmin && vmax
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn to_radiusauthtoken(
|
|
|
|
&self,
|
|
|
|
ct: Duration,
|
|
|
|
) -> Result<RadiusAuthToken, OperationError> {
|
|
|
|
if !self.is_within_valid_time(ct) {
|
|
|
|
return Err(OperationError::InvalidAccountState(
|
|
|
|
"Account Expired".to_string(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2019-10-31 01:48:15 +01:00
|
|
|
// If we don't have access/permission, then just error instead.
|
|
|
|
// This includes if we don't have the secret.
|
|
|
|
Ok(RadiusAuthToken {
|
|
|
|
name: self.name.clone(),
|
|
|
|
displayname: self.displayname.clone(),
|
2022-04-27 05:35:26 +02:00
|
|
|
uuid: self.uuid.as_hyphenated().to_string(),
|
2019-10-31 01:48:15 +01:00
|
|
|
secret: self.radius_secret.clone(),
|
2020-01-09 11:07:14 +01:00
|
|
|
groups: self.groups.iter().map(|g| g.to_proto()).collect(),
|
2019-10-31 01:48:15 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|