Skip to content
Open
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
22 changes: 18 additions & 4 deletions crates/api-types/src/error_conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,19 +218,33 @@ impl From<CatalogProviderError> for KeystoneApiError {
}

impl From<ApplicationCredentialProviderError> for KeystoneApiError {
fn from(source: ApplicationCredentialProviderError) -> Self {
match source {
fn from(value: ApplicationCredentialProviderError) -> Self {
match value {
ApplicationCredentialProviderError::ApplicationCredentialNotFound(x) => {
Self::NotFound {
resource: "application_credential".into(),
identifier: x,
}
}
ApplicationCredentialProviderError::AccessRuleNotFound(x) => Self::NotFound {
resource: "access_rule".into(),
identifier: x,
},
ApplicationCredentialProviderError::RoleNotFound(x) => Self::NotFound {
resource: "role".into(),
identifier: x,
},
ref err @ ApplicationCredentialProviderError::Conflict(..) => {
Self::Conflict(err.to_string())
}
err @ ApplicationCredentialProviderError::ApplicationCredentialExpired => {
Self::unauthorized(err, None::<String>)
ref err @ ApplicationCredentialProviderError::Validation { .. } => {
Self::BadRequest(err.to_string())
}
ApplicationCredentialProviderError::ApplicationCredentialExpired => {
Self::BadRequest("application credential has expired".into())
}
ApplicationCredentialProviderError::AccessRuleInUse(x) => {
Self::BadRequest(format!("access rule {x} is still in use"))
}
other => Self::InternalError(other.to_string()),
}
Expand Down
3 changes: 3 additions & 0 deletions crates/api-types/src/v3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//
// SPDX-License-Identifier: Apache-2.0
//! # V3 API types
pub mod application_credential;
pub mod auth;
pub mod credential;
pub mod domain;
Expand All @@ -23,6 +24,8 @@ pub mod role;
pub mod role_assignment;
pub mod user;

#[cfg(feature = "conv")]
mod application_credential_conv;
#[cfg(feature = "conv")]
mod auth_conv;
#[cfg(feature = "conv")]
Expand Down
16 changes: 16 additions & 0 deletions crates/api-types/src/v3/application_credential.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

pub mod access_rule;
pub mod application_credential;

Check warning

Code scanning / clippy

module has the same name as its containing module Warning

module has the same name as its containing module
84 changes: 84 additions & 0 deletions crates/api-types/src/v3/application_credential/access_rule.rs

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add docstring to all fields in structures

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

use serde::{Deserialize, Serialize};
/// Short access rule representation.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(
feature = "builder",
derive(derive_builder::Builder),
builder(
build_fn(error = "crate::error::BuilderError"),
setter(strip_option, into)
)
)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct AccessRule {
/// The ID of the access rule.
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 64)))]
pub id: String,

/// The HTTP method permitted.
#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 16)))]
pub method: Option<String>,

/// The API path permitted.
#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 128)))]
pub path: Option<String>,

/// The service type permitted.
#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 64)))]
pub service: Option<String>,
}

/// Access rule for creation (id is optional).
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(
feature = "builder",
derive(derive_builder::Builder),
builder(
build_fn(error = "crate::error::BuilderError"),
setter(strip_option, into)
)
)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct AccessRuleCreate {
#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 64)))]
pub id: Option<String>,

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 16)))]
pub method: Option<String>,

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 128)))]
pub path: Option<String>,

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 64)))]
pub service: Option<String>,
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add docstring to all fields in structures

Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
//! # Application credential API types

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[cfg(feature = "validate")]
use validator::Validate;

use crate::v3::application_credential::access_rule::{AccessRule, AccessRuleCreate};
use crate::v3::role::RoleRef;

/// Full application credential representation.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(
feature = "builder",
derive(derive_builder::Builder),
builder(
build_fn(error = "crate::error::BuilderError"),
setter(strip_option, into)
)
)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct ApplicationCredential {
#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(nested))]
pub access_rules: Option<Vec<AccessRule>>,

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 255)))]
pub description: Option<String>,

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
pub expires_at: Option<DateTime<Utc>>,

#[cfg_attr(feature = "validate", validate(length(min = 1, max = 64)))]
pub id: String,

#[cfg_attr(feature = "validate", validate(length(min = 1, max = 255)))]
pub name: String,

#[cfg_attr(feature = "validate", validate(length(min = 1, max = 64)))]
pub project_id: String,

#[cfg_attr(feature = "validate", validate(nested))]
pub roles: Vec<RoleRef>,

pub unrestricted: bool,

#[cfg_attr(feature = "validate", validate(length(min = 1, max = 64)))]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python keystone does not expose user_id for the application credential, since they are always already bound to the URL. Drop it in all structs

pub user_id: String,
}

/// Data for creating an application credential.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(
feature = "builder",
derive(derive_builder::Builder),
builder(
build_fn(error = "crate::error::BuilderError"),
setter(strip_option, into)
)
)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct ApplicationCredentialCreate {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python keystone allows to specify (optionally) the secret during creation. Add it wrapped as SecretString

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(nested))]
pub access_rules: Option<Vec<AccessRuleCreate>>,

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
pub expires_at: Option<DateTime<Utc>>,

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "validate", validate(length(min = 1, max = 64)))]
pub id: Option<String>,

#[cfg_attr(feature = "validate", validate(length(min = 1, max = 255)))]
pub name: String,

#[cfg_attr(feature = "builder", builder(default))]
pub roles: Vec<RoleRef>,

#[cfg_attr(feature = "builder", builder(default))]
#[serde(skip_serializing_if = "Option::is_none")]
pub unrestricted: Option<bool>,
}

/// Wrapper for a single application credential response.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct ApplicationCredentialResponse {
#[cfg_attr(feature = "validate", validate(nested))]
pub application_credential: ApplicationCredential,
}

/// Wrapper for a create request body.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct ApplicationCredentialCreateRequest {
#[cfg_attr(feature = "validate", validate(nested))]
pub application_credential: ApplicationCredentialCreate,
}

/// Application credential as returned by create — includes secret (shown once only).
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct ApplicationCredentialCreated {
#[serde(skip_serializing_if = "Option::is_none")]
pub access_rules: Option<Vec<AccessRule>>,

#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub expires_at: Option<DateTime<Utc>>,

pub id: String,
pub name: String,
pub project_id: String,
pub roles: Vec<RoleRef>,

/// Only present in create response. Never returned again.
pub secret: String,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this SecretString


pub unrestricted: bool,
pub user_id: String,
}

/// Wrapper for create response body.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct ApplicationCredentialCreateResponse {
pub application_credential: ApplicationCredentialCreated,
}

/// List of application credentials.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct ApplicationCredentialList {
#[cfg_attr(feature = "validate", validate(nested))]
pub application_credentials: Vec<ApplicationCredential>,
}

/// List parameters for filtering application credentials.
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::IntoParams))]
#[cfg_attr(feature = "validate", derive(validator::Validate))]
pub struct ApplicationCredentialListParameters {
#[cfg_attr(feature = "validate", validate(length(max = 255)))]
pub name: Option<String>,
}
Loading
Loading