Feature/expose app credential#948
Conversation
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| pub mod access_rule; | ||
| pub mod application_credential; |
gtema
left a comment
There was a problem hiding this comment.
thanks, look good, but there are issues that need to be addressed
| state | ||
| .provider | ||
| .get_identity_provider() | ||
| .get_user(&ExecutionContext::from_auth(&state, &user_auth), &user_id) |
There was a problem hiding this comment.
you should only create ExecutionContext once. You recreate it few times in every handler
There was a problem hiding this comment.
I will define it at begin of the handler and reuse it in the handler if I need to use it.
| pub roles: Vec<RoleRef>, | ||
|
|
||
| /// Only present in create response. Never returned again. | ||
| pub secret: String, |
|
|
||
| pub unrestricted: bool, | ||
|
|
||
| #[cfg_attr(feature = "validate", validate(length(min = 1, max = 64)))] |
There was a problem hiding this comment.
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
| default allow := false | ||
|
|
||
| allow if { | ||
| input.credentials.user_id == input.target.user_id |
There was a problem hiding this comment.
it would be input.target.application_credential.user_id
|
|
||
| allow if { input.credentials.is_admin } | ||
|
|
||
| allow if { input.credentials.user_id == input.target.user_id } No newline at end of file |
There was a problem hiding this comment.
it's going to be input.target.existing.user_id
| input.credentials.system == "all" | ||
| } | ||
|
|
||
| allow if { input.credentials.user_id == input.target.user_id } No newline at end of file |
There was a problem hiding this comment.
target.application_credential.user_id or target.user_id, but depends on how you set pass it from handler. Anyway - please look at the current policies which document the structure of the data - add it to all policies
| input.credentials.system == "all" | ||
| } | ||
|
|
||
| allow if { input.credentials.user_id == input.target.user_id } No newline at end of file |
There was a problem hiding this comment.
also here user_id is wrapped under the input.existing.application_credential.user_id
| pub async fn get_project_scoped_client() -> Result<Arc<AsyncOpenStack>> { | ||
| let mut tc = AsyncOpenStack::new(&CloudConfig::from_env()?).await?; | ||
|
|
||
| tc.authorize( |
There was a problem hiding this comment.
this should not be necessary - the 'tc' already should be project scoped as directed by the env vars.
Thanks for your review. I'm going to address all issues. |
e386a90 to
c392df6
Compare
gtema
left a comment
There was a problem hiding this comment.
Very very close, just few nits
| Self::BadRequest("application credential has expired".into()) | ||
| } | ||
| ApplicationCredentialProviderError::AccessRuleInUse(x) => { | ||
| Self::BadRequest(format!("access rule {x} is still in use")) |
There was a problem hiding this comment.
InUse is a typical 409 - conflict and not bad request. User 'Self::Conflict' instead
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub expires_at: Option<DateTime<Utc>>, | ||
|
|
||
| /// Optional client-supplied identifier for the application credential. If |
There was a problem hiding this comment.
Passing ID in create through API must not be possible - inconsistency to python Keystone
|
|
||
| assert_eq!(cred.name, "test-cred"); | ||
| assert!(!cred.secret.is_empty()); | ||
| // assert_eq!(cred.user_id, user_id); |
There was a problem hiding this comment.
it is mistake, i've forgotten to uncomment after debugging
| &tc, | ||
| &user_id, | ||
| ApplicationCredentialCreateBuilder::default() | ||
| .name(format!("cred-1")) |
There was a problem hiding this comment.
just use .name("cred-1") - Builder should already have Into
| #[derive(OpenApi)] | ||
| #[openapi( | ||
| tags( | ||
| (name="domains", description=r#"Domains are a collection of projects and users that define administrative boundaries for managing Identity entities. Domains can represent an individual, company, or operator-owned space. They expose administrative activities directly to system users. Users can be granted the administrator role for a domain. A domain administrator can create projects, users, and groups in a domain and assign roles to users and groups in a domain. |
There was a problem hiding this comment.
not related change - please undo
There was a problem hiding this comment.
thanks for review, I have no idea when I changed this file.I will be more careful after that 👍
20fe189 to
ea6182a
Compare
|
@gtema I didnt understand reason of failure in the CI tests.The /health endpoint doesn't response respect of the logs. I have checked last merged commits but none of them has issue like this, Should I change anything in the PR? |
gtema
left a comment
There was a problem hiding this comment.
good progress, there are still some issues. I am currently working on adding more jobs/gates to prevent some of the issues you have here in policies
| pub roles: Vec<RoleRef>, | ||
|
|
||
| /// Only present in create response. Never returned again. | ||
| pub secret: String, |
| .enforce( | ||
| "identity/user/application_credential/delete", | ||
| &user_auth, | ||
| json!({"application_credential": serde_json::to_value(¤t)?}), |
There was a problem hiding this comment.
wrong order: policy_name, auth, target, current. You pass current under target
There was a problem hiding this comment.
-
- **Show**: Passserde_json::to_value(stored_object)?as target,Noneas existing -
- **Delete**: Passserde_json::to_value(stored_object)?as target,Noneas existingBased on ADR doc the current object must pass as target. Should I still change it?
There was a problem hiding this comment.
nice spot - this is a mistake in the ADR. Everywhere in the code we follow this convention (logical that "existing" parameter always points at the object stored on the server side). So yes, please change it and I fix the ADR
| .enforce( | ||
| "identity/user/application_credential/show", | ||
| &user_auth, | ||
| json!({"application_credential": serde_json::to_value(¤t)?}), |
There was a problem hiding this comment.
also here wrong order of target/current
| input.credentials.system == "all" | ||
| } | ||
|
|
||
| allow if { input.credentials.user_id == input.target.application_credential.user_id } |
There was a problem hiding this comment.
the check in this form tells that while input.target.application_credential.user_id = none would not be allowed, we should throw dedicated violation message (smth like listing application credentials require user_id ...)
|
|
||
| allow if { input.credentials.is_admin } | ||
|
|
||
| allow if { input.credentials.user_id == input.target.application_credential.user_id } |
There was a problem hiding this comment.
here it matches the handler, but not the general policy: delete/update/show take input.current and not input.target
ea6182a to
ce559ae
Compare
Signed-off-by: Hamza Konac <hamza.konac@tubitak.gov.tr>
Signed-off-by: Hamza Konac <hamza.konac@tubitak.gov.tr>
Signed-off-by: Hamza Konac <hamza.konac@tubitak.gov.tr>
Signed-off-by: Hamza Konac <hamza.konac@tubitak.gov.tr>
Signed-off-by: Hamza Konac <hamza.konac@tubitak.gov.tr>
Signed-off-by: Hamza Konac <hamza.konac@tubitak.gov.tr>
Signed-off-by: Hamza Konac <hamza.konac@tubitak.gov.tr>
Signed-off-by: Hamza Konac <hamza.konac@tubitak.gov.tr>
ce559ae to
9cfe76f
Compare
gtema
left a comment
There was a problem hiding this comment.
few more remaining issues, very close now
| )] | ||
| #[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))] | ||
| #[cfg_attr(feature = "validate", derive(validator::Validate))] | ||
| pub struct ApplicationCredentialCreate { |
There was a problem hiding this comment.
you still do not have a "secret" specified by the user during AC creation.
| } | ||
| } | ||
|
|
||
| impl From<api_types_application_credential::ApplicationCredentialCreate> |
There was a problem hiding this comment.
when user passes the expected secret we would need to set it here as well
| .enforce( | ||
| "identity/user/application_credential/delete", | ||
| &user_auth, | ||
| json!({"application_credential": null}), |
There was a problem hiding this comment.
no, simply serde_json::Value::Null
| }; | ||
|
|
||
| let mut target = serde_json::to_value(&payload.application_credential)?; | ||
| target["user_id"] = json!(user_id); |
There was a problem hiding this comment.
once you add "secret" to the payload you need to explicitly remove it from the json here so that it is not passed to the policy
| .enforce( | ||
| "identity/user/application_credential/show", | ||
| &user_auth, | ||
| json!({"application_credential": null}), |
There was a problem hiding this comment.
simply use serde_json::Value::Null
This PR implements the Application Credential API (part of #782).
Changes
application_credentialandaccess_rule, along with their converters in theapi-typescrate.