Skip to content

feat: implement management client with auth module - #49

Open
shefali-kamal wants to merge 1 commit into
veraison:mainfrom
MonakaResearch:main
Open

shefali-kamal wants to merge 1 commit into
veraison:mainfrom
MonakaResearch:main

Conversation

@shefali-kamal

Copy link
Copy Markdown
  • implement management client for veraison/services
  • add auth module required to submit the policy to the management server

@paulhowardarm paulhowardarm left a comment

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.

Nice extra function for the Rust client, thanks. Looks good overall, although I'm not too familiar with the management API, so definitely worth a second review. I have requested some naming changes, and offered some advice on zeroing sensitive data fields in the authentication parts.

Comment thread src/auth.rs Outdated

/// Supplies the value of the HTTP Authorization header.
#[async_trait::async_trait]
pub trait IAuthenticator {

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.

The name IAuthenticator is not idiomatic for Rust traits. At the very least, the I prefix should be removed, because this is not a convention in Rust. Authenticator is probably suitable, but an alternative would be Authenticate. Rust tends to use verbs or agent nouns for traits.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

updated to Authenticator.

Comment thread src/auth.rs

/// A Basic authenticator that uses a username and password to generate a Basic Authorization header.
#[derive(Default, Deserialize)]
pub struct BasicAuthenticator {

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.

Since this type contains a secret (password), it would probably be good practice to zeroize it on drop. Look at using the zeroize crate and provide a Drop implementation. See: https://docs.rs/zeroize/latest/zeroize/

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

done, please check.

Comment thread src/auth.rs
}

/// An OAuth2 authenticator that uses the Resource Owner Password Credentials grant to obtain an access token and generate a Bearer Authorization header.
#[derive(Default, Deserialize)]

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.

As with BasicAuthenticator, we probably want to ensure any secret-containing fields are zeroized on drop.

Comment thread src/http.rs Outdated
@@ -90,6 +134,7 @@ pub trait ConfigureHttp: Sized {
/// The common builder allows for the configuration of custom TLS root certificates along with
/// middleware layers for client-side caching.

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.

Update the comment here - middleware layers for client-side caching or authentication.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

done

Comment thread src/http.rs Outdated
let authentication = AuthenticationMiddleware {
authenticator: Arc::new(Mutex::new(self.authenticator)),
};
// Now add any required middleware to the client

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.

Need to reposition the comment about adding middleware, because we've already started doing so.

Comment thread src/management.rs Outdated
}

/// A builder for [PolicyRunner] objects.
pub struct PolicyRunnerBuilder {

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.

I would reconsider the names PolicyRunner and PolicyRunnerBuilder. I don't think Runner is very suitable in this context. I suspect this might have been borrowed from the CoSERV client, which uses QueryRunner. But it works in that case because the CoSERV client is about running queries. I think PolicyManager and PolicyManagerBuilder would make more sense than Runner here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

updated as per suggestion.

- implement management client for veraison/services
- add auth module required to submit the policy to the management server

Signed-off-by: Badiyasar, Harshita <Harshita.Badiyasar@fujitsu.com>
@shefali-kamal

Copy link
Copy Markdown
Author

Hi @paulhowardarm ,
Thanks for the review comments. Can you please check the comments addressed and if it looks good approve the PR.

@paulhowardarm paulhowardarm left a comment

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.

Thank you for addressing my earlier observations. Sorry for the delay on re-review, but this LGTM now.

@shefali-kamal

Copy link
Copy Markdown
Author

Hi @thomas-fossati ,
Please review this PR. We have received approval from Paul.

@thomas-fossati thomas-fossati left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the nice contribution and sorry for taking so long to review.

I have inlined a few comments.

Comment thread src/http.rs
) -> MiddlewareResult<reqwest::Response> {
let header = self
.authenticator
.lock()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this is good, because it avoids n parallel refreshes, but if the IdP is slow or hung up this will block indefinitely. We should probably add a "reasonable" timeout to the token request.

Comment thread src/auth.rs
.append_pair("scope", "openid")
.finish();
let response = client
.post(&self.token_url)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(see comment in http.rs about "locking forever".)

we should put a timeout on this request, say 15-20 seconds.

Comment thread src/auth.rs
{
let mut builder = HttpClientBuilder::new();
for path in cert_paths {
builder = builder.with_root_certificate(PathBuf::from(path.as_ref()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

hold on, with_root_certificate is not additive, right? so, if len(cert_paths) > 1 only the last cert survives, which is probably not what you intended.

Comment thread src/management.rs
Comment on lines +163 to +168
let mut url = self.base_url.clone();
let path = template.replace(":scheme", scheme).replace(
":uuid",
&policy_id.map_or_else(String::new, |id| id.to_string()),
);
url.set_path(&path);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this throws away the base URL's path, which may be problematic if the service is behind a reverse proxy/LB that mounts the service on a dedicated path.

another thought: who selects scheme? Asking because applying set_path on an arbitrary input may result in "path evasion" situations.

Comment thread src/auth.rs

impl CachedTokenResponse {
// If expiry is not given then do not cache the token, and always obtain a new one.
fn is_expired(&self) -> bool {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this can become a bit wobbly when the token is nearly but not quite yet expired: it'll pass the check but then it'll get rejected.
I suggest to subtract a few seconds of skew (say 30s).

A (slightly more convoluted) alternative would be to retry once on 401.

Comment thread src/management.rs
}

/// Get all policies for a scheme. (optially filtered by name)
pub async fn get_policies(&self, scheme: &str, name: &str) -> Result<Vec<Policy>, Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

maybe name: Option<&str>

Comment thread src/management.rs
Self::policy_from_response(Self::expect_status(response, StatusCode::OK).await?).await
}

/// Get all policies for a scheme. (optially filtered by name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Get all policies for a scheme. (optially filtered by name)
/// Get all policies for a scheme. (optionally filtered by name)

Comment thread src/auth.rs
.append_pair("grant_type", "password")
.append_pair("username", &self.username)
.append_pair("password", &self.password)
.append_pair("scope", "openid")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why is this hardcoded? I think that the scope should be configurable.

Comment thread src/lib.rs
}
}

/// Obtains the capabilities and endpoints of the Veraison verification service.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Obtains the capabilities and endpoints of the Veraison verification service.
/// Obtains the capabilities and endpoints of the Veraison management service.

Comment thread src/management.rs
Comment on lines +25 to +30
const CREATE_POLICY_ENDPOINT: &str = "/management/v1/policy/:scheme";
const GET_POLICY_ENDPOINT: &str = "/management/v1/policy/:scheme/:uuid";
const DEACTIVATE_POLICIES_ENDPOINT: &str = "/management/v1/policies/:scheme/deactivate";
const GET_ACTIVE_POLICY_ENDPOINT: &str = "/management/v1/policy/:scheme";
const ACTIVATE_POLICY_ENDPOINT: &str = "/management/v1/policy/:scheme/:uuid/activate";
const GET_POLICIES_ENDPOINT: &str = "/management/v1/policies/:scheme";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

unclear if these are hardcoded or discovered?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants