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
3 changes: 3 additions & 0 deletions src/api/v3/user/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use axum::{
response::IntoResponse,
};
use utoipa_axum::{router::OpenApiRouter, routes};
use validator::Validate;

use crate::api::auth::Auth;
use crate::api::error::KeystoneApiError;
Expand Down Expand Up @@ -54,6 +55,7 @@ async fn list(
Query(query): Query<UserListParameters>,
State(state): State<ServiceState>,
) -> Result<impl IntoResponse, KeystoneApiError> {
query.validate()?;
let users: Vec<User> = state
.provider
.get_identity_provider()
Expand Down Expand Up @@ -262,6 +264,7 @@ mod tests {
UserListParameters {
domain_id: Some("domain".into()),
name: Some("name".into()),
..Default::default()
} == *qp
})
.returning(|_, _| Ok(Vec::new()));
Expand Down
71 changes: 64 additions & 7 deletions src/api/v3/user/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ use validator::Validate;

use crate::identity::types as identity_types;

/// User response object.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, ToSchema, Validate)]
pub struct User {
/// User ID
/// User ID.
#[validate(length(max = 64))]
pub id: String,
/// User domain ID
/// User domain ID.
#[validate(length(max = 64))]
pub domain_id: String,
/// User name
/// User name.
#[validate(length(max = 255))]
pub name: String,
/// If the user is enabled, this value is true. If the user is disabled,
Expand Down Expand Up @@ -64,18 +65,24 @@ pub struct User {
#[serde(skip_serializing_if = "Option::is_none")]
#[validate(nested)]
pub options: Option<UserOptions>,
/// List of federated objects associated with a user. Each object in the list contains the idp_id and protocols. protocols is a list of objects, each of which contains protocol_id and unique_id of the protocol and user respectively.
#[serde(skip_serializing_if = "Option::is_none")]
#[validate(nested)]
pub federated: Option<Vec<Federation>>,
}

/// Complete response with the user data.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, ToSchema, Validate)]
pub struct UserResponse {
/// User object
#[validate(nested)]
pub user: User,
}

/// Create user data.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, ToSchema, Validate)]
pub struct UserCreate {
/// User domain ID
/// User domain ID.
#[validate(length(max = 64))]
pub domain_id: String,
/// The user name. Must be unique within the owning domain.
Expand Down Expand Up @@ -110,6 +117,7 @@ pub struct UserCreate {
pub extra: Option<Value>,
}

/// Update user data.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, ToSchema, Validate)]
pub struct UserUpdateRequest {
/// The user name. Must be unique within the owning domain.
Expand Down Expand Up @@ -143,6 +151,7 @@ pub struct UserUpdateRequest {
pub extra: Option<Value>,
}

/// User options.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, ToSchema, Validate)]
pub struct UserOptions {
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -189,9 +198,10 @@ impl From<UserOptions> for identity_types::UserOptions {
}
}

/// Complete create user request.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, ToSchema, Validate)]
pub struct UserCreateRequest {
/// User object
/// User object.
#[validate(nested)]
pub user: UserCreate,
}
Expand Down Expand Up @@ -221,6 +231,9 @@ impl From<identity_types::UserResponse> for User {
extra: value.extra,
password_expires_at: value.password_expires_at,
options: opts,
federated: value
.federated
.map(|val| val.into_iter().map(Into::into).collect()),
}
}
}
Expand All @@ -242,6 +255,45 @@ impl From<UserCreateRequest> for identity_types::UserCreate {
}
}

/// User federation data.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, ToSchema, Validate)]
pub struct Federation {
/// Identity provider ID.
pub idp_id: String,
/// Protocols.
#[validate(nested)]
pub protocols: Vec<FederationProtocol>,
}

/// Federation protocol data.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, ToSchema, Validate)]
pub struct FederationProtocol {
/// Federation protocol ID
#[validate(length(max = 64))]
pub protocol_id: String,
// TODO: unique ID should potentially belong to the IDP and not to the protocol
/// Unique ID of the associated user
#[validate(length(max = 64))]
pub unique_id: String,
}

impl From<identity_types::Federation> for Federation {
fn from(value: identity_types::Federation) -> Self {
Self {
idp_id: value.idp_id,
protocols: value.protocols.into_iter().map(Into::into).collect(),
}
}
}
impl From<identity_types::FederationProtocol> for FederationProtocol {
fn from(value: identity_types::FederationProtocol) -> Self {
Self {
protocol_id: value.protocol_id,
unique_id: value.unique_id,
}
}
}

impl IntoResponse for UserResponse {
fn into_response(self) -> Response {
(StatusCode::OK, Json(self)).into_response()
Expand Down Expand Up @@ -281,21 +333,26 @@ impl IntoResponse for UserList {
}
}

/// User list parameters.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, IntoParams, Validate)]
pub struct UserListParameters {
/// Filter users by Domain ID
/// Filter users by Domain ID.
#[validate(length(max = 64))]
pub domain_id: Option<String>,
/// Filter users by Name
/// Filter users by Name.
#[validate(length(max = 255))]
pub name: Option<String>,
/// Filter users by the federated unique ID.
#[validate(length(max = 64))]
pub unique_id: Option<String>,
}

impl From<UserListParameters> for identity_types::UserListParameters {
fn from(value: UserListParameters) -> Self {
Self {
domain_id: value.domain_id,
name: value.name,
unique_id: value.unique_id,
// limit: value.limit,
}
}
Expand Down
1 change: 1 addition & 0 deletions src/api/v4/user/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ mod tests {
UserListParameters {
domain_id: Some("domain".into()),
name: Some("name".into()),
..Default::default()
} == *qp
})
.returning(|_, _| Ok(Vec::new()));
Expand Down
Loading
Loading