Skip to content

Commit

Permalink
[rust][client][auth] token source option (#19647)
Browse files Browse the repository at this point in the history
* feat: add token source support for rust async client

* chore: fix + regen samples

* chore: doc gen

* chore: missing generated sample files
  • Loading branch information
nicolas-vivot authored Oct 1, 2024
1 parent 7e1ebe6 commit 8ef3118
Show file tree
Hide file tree
Showing 78 changed files with 3,749 additions and 27 deletions.
11 changes: 11 additions & 0 deletions bin/configs/rust-reqwest-petstore-async-tokensource.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
generatorName: rust
outputDir: samples/client/petstore/rust/reqwest/petstore-async-tokensource
library: reqwest
inputSpec: modules/openapi-generator/src/test/resources/3_0/rust/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/rust
additionalProperties:
supportAsync: true
supportTokenSource: true
supportMultipleResponses: true
packageName: petstore-reqwest-async-tokensource
useSingleRequestParameter: true
1 change: 1 addition & 0 deletions docs/generators/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|supportAsync|If set, generate async function call instead. This option is for 'reqwest' library only| |true|
|supportMiddleware|If set, add support for reqwest-middleware. This option is for 'reqwest' library only| |false|
|supportMultipleResponses|If set, return type wraps an enum of all possible 2xx schemas. This option is for 'reqwest' library only| |false|
|supportTokenSource|If set, add support for google-cloud-token. This option is for 'reqwest' library only and requires the 'supportAsync' option| |false|
|useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.| |false|
|withAWSV4Signature|whether to include AWS v4 signature support| |false|

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class RustClientCodegen extends AbstractRustCodegen implements CodegenCon
@Setter(AccessLevel.PRIVATE) private boolean useSingleRequestParameter = false;
@Setter(AccessLevel.PRIVATE) private boolean supportAsync = true;
@Setter(AccessLevel.PRIVATE) private boolean supportMiddleware = false;
@Setter(AccessLevel.PRIVATE) private boolean supportTokenSource = false;
private boolean supportMultipleResponses = false;
private boolean withAWSV4Signature = false;
@Setter private boolean preferUnsignedInt = false;
Expand All @@ -62,6 +63,7 @@ public class RustClientCodegen extends AbstractRustCodegen implements CodegenCon
public static final String REQWEST_LIBRARY = "reqwest";
public static final String SUPPORT_ASYNC = "supportAsync";
public static final String SUPPORT_MIDDLEWARE = "supportMiddleware";
public static final String SUPPORT_TOKEN_SOURCE = "supportTokenSource";
public static final String SUPPORT_MULTIPLE_RESPONSES = "supportMultipleResponses";
public static final String PREFER_UNSIGNED_INT = "preferUnsignedInt";
public static final String BEST_FIT_INT = "bestFitInt";
Expand Down Expand Up @@ -192,6 +194,8 @@ public RustClientCodegen() {
.defaultValue(Boolean.TRUE.toString()));
cliOptions.add(new CliOption(SUPPORT_MIDDLEWARE, "If set, add support for reqwest-middleware. This option is for 'reqwest' library only", SchemaTypeUtil.BOOLEAN_TYPE)
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(SUPPORT_TOKEN_SOURCE, "If set, add support for google-cloud-token. This option is for 'reqwest' library only and requires the 'supportAsync' option", SchemaTypeUtil.BOOLEAN_TYPE)
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(SUPPORT_MULTIPLE_RESPONSES, "If set, return type wraps an enum of all possible 2xx schemas. This option is for 'reqwest' library only", SchemaTypeUtil.BOOLEAN_TYPE)
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(CodegenConstants.ENUM_NAME_SUFFIX, CodegenConstants.ENUM_NAME_SUFFIX_DESC).defaultValue(this.enumSuffix));
Expand Down Expand Up @@ -346,6 +350,11 @@ public void processOpts() {
}
writePropertyBack(SUPPORT_MIDDLEWARE, getSupportMiddleware());

if (additionalProperties.containsKey(SUPPORT_TOKEN_SOURCE)) {
this.setSupportTokenSource(convertPropertyToBoolean(SUPPORT_TOKEN_SOURCE));
}
writePropertyBack(SUPPORT_TOKEN_SOURCE, getSupportTokenSource());

if (additionalProperties.containsKey(SUPPORT_MULTIPLE_RESPONSES)) {
this.setSupportMultipleReturns(convertPropertyToBoolean(SUPPORT_MULTIPLE_RESPONSES));
}
Expand Down Expand Up @@ -437,6 +446,10 @@ private boolean getSupportAsync() {
private boolean getSupportMiddleware() {
return supportMiddleware;
}

private boolean getSupportTokenSource() {
return supportTokenSource;
}

public boolean getSupportMultipleReturns() {
return supportMultipleResponses;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,10 @@ reqwest = { version = "^0.12", features = ["json", "multipart"] }
{{#supportMiddleware}}
reqwest-middleware = { version = "^0.3", features = ["json", "multipart"] }
{{/supportMiddleware}}
{{#supportTokenSource}}
async-trait = "^0.1"
# TODO: propose to Yoshidan to externalize this as non google related crate, so that it can easily be extended for other cloud providers.
google-cloud-token = "^0.1"
{{/supportTokenSource}}
{{/supportAsync}}
{{/reqwest}}
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@ pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration:
{{/hasHeaderParams}}
{{#hasAuthMethods}}
{{#authMethods}}
{{#supportTokenSource}}
// Obtain a token from source provider.
// Tokens can be Id or access tokens depending on the provider type and configuration.
let token = local_var_configuration.token_source.token().await.map_err(Error::TokenSource)?;
// The token format is the responsibility of the provider, thus we just set the authorization header with whatever is given.
local_var_req_builder = local_var_req_builder.header(reqwest::header::AUTHORIZATION, token);
{{/supportTokenSource}}
{{^supportTokenSource}}
{{#isApiKey}}
{{#isKeyInHeader}}
if let Some(ref local_var_apikey) = local_var_configuration.api_key {
Expand Down Expand Up @@ -240,6 +248,7 @@ pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration:
local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned());
};
{{/isOAuth}}
{{/supportTokenSource}}
{{/authMethods}}
{{/hasAuthMethods}}
{{#isMultipart}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ pub enum Error<T> {
{{#withAWSV4Signature}}
AWSV4SignatureError(aws_sigv4::http_request::Error),
{{/withAWSV4Signature}}
{{#supportAsync}}
{{#supportTokenSource}}
TokenSource(Box<dyn std::error::Error + Send + Sync>),
{{/supportTokenSource}}
{{/supportAsync}}
}

impl <T> fmt::Display for Error<T> {
Expand All @@ -38,6 +43,11 @@ impl <T> fmt::Display for Error<T> {
{{#withAWSV4Signature}}
Error::AWSV4SignatureError(e) => ("aws v4 signature", e.to_string()),
{{/withAWSV4Signature}}
{{#supportAsync}}
{{#supportTokenSource}}
Error::TokenSource(e) => ("token source failure", e.to_string()),
{{/supportTokenSource}}
{{/supportAsync}}
};
write!(f, "error in {}: {}", module, e)
}
Expand All @@ -56,6 +66,11 @@ impl <T: fmt::Debug> error::Error for Error<T> {
{{#withAWSV4Signature}}
Error::AWSV4SignatureError(_) => return None,
{{/withAWSV4Signature}}
{{#supportAsync}}
{{#supportTokenSource}}
Error::TokenSource(e) => &**e,
{{/supportTokenSource}}
{{/supportAsync}}
})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,33 @@ use aws_sigv4::http_request::{sign, SigningSettings, SigningParams, SignableRequ
use http;
use secrecy::{SecretString, ExposeSecret};
{{/withAWSV4Signature}}
{{#supportTokenSource}}
use std::sync::Arc;
use google_cloud_token::TokenSource;
use async_trait::async_trait;
{{/supportTokenSource}}

#[derive(Debug, Clone)]
pub struct Configuration {
pub base_path: String,
pub user_agent: Option<String>,
pub client: {{#supportMiddleware}}reqwest_middleware::ClientWithMiddleware{{/supportMiddleware}}{{^supportMiddleware}}reqwest{{^supportAsync}}::blocking{{/supportAsync}}::Client{{/supportMiddleware}},
{{^supportTokenSource}}
pub basic_auth: Option<BasicAuth>,
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
{{/supportTokenSource}}
{{#withAWSV4Signature}}
pub aws_v4_key: Option<AWSv4Key>,
{{/withAWSV4Signature}}
// TODO: take an oauth2 token source, similar to the go one
{{#supportAsync}}
{{#supportTokenSource}}
pub token_source: Arc<dyn TokenSource>,
{{/supportTokenSource}}
{{/supportAsync}}
}
{{^supportTokenSource}}

pub type BasicAuth = (String, Option<String>);

Expand All @@ -29,6 +41,7 @@ pub struct ApiKey {
pub prefix: Option<String>,
pub key: String,
}
{{/supportTokenSource}}

{{#withAWSV4Signature}}
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -81,11 +94,29 @@ impl Default for Configuration {
base_path: "{{{basePath}}}".to_owned(),
user_agent: {{#httpUserAgent}}Some("{{{.}}}".to_owned()){{/httpUserAgent}}{{^httpUserAgent}}Some("OpenAPI-Generator/{{{version}}}/rust".to_owned()){{/httpUserAgent}},
client: {{#supportMiddleware}}reqwest_middleware::ClientBuilder::new(reqwest{{^supportAsync}}::blocking{{/supportAsync}}::Client::new()).build(){{/supportMiddleware}}{{^supportMiddleware}}reqwest{{^supportAsync}}::blocking{{/supportAsync}}::Client::new(){{/supportMiddleware}},
{{^supportTokenSource}}
basic_auth: None,
oauth_access_token: None,
bearer_access_token: None,
api_key: None,
{{#withAWSV4Signature}} aws_v4_key: None,{{/withAWSV4Signature}}
{{/supportTokenSource}}
{{#withAWSV4Signature}}
aws_v4_key: None,
{{/withAWSV4Signature}}
{{#supportTokenSource}}
token_source: Arc::new(NoopTokenSource{}),
{{/supportTokenSource}}
}
}
}
{{#supportTokenSource}}
#[derive(Debug)]
struct NoopTokenSource{}

#[async_trait]
impl TokenSource for NoopTokenSource {
async fn token(&self) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
panic!("This is dummy token source. You can use TokenSourceProvider from 'google_cloud_auth' crate, or any other compatible crate.")
}
}
{{/supportTokenSource}}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
// TODO: take an oauth2 token source, similar to the go one
}

pub type BasicAuth = (String, Option<String>);
Expand Down Expand Up @@ -47,7 +46,6 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
// TODO: take an oauth2 token source, similar to the go one
}

pub type BasicAuth = (String, Option<String>);
Expand Down Expand Up @@ -47,7 +46,6 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
// TODO: take an oauth2 token source, similar to the go one
}

pub type BasicAuth = (String, Option<String>);
Expand Down Expand Up @@ -47,7 +46,6 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
// TODO: take an oauth2 token source, similar to the go one
}

pub type BasicAuth = (String, Option<String>);
Expand Down Expand Up @@ -47,7 +46,6 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
// TODO: take an oauth2 token source, similar to the go one
}

pub type BasicAuth = (String, Option<String>);
Expand Down Expand Up @@ -47,7 +46,6 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
// TODO: take an oauth2 token source, similar to the go one
}

pub type BasicAuth = (String, Option<String>);
Expand Down Expand Up @@ -47,7 +46,6 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
// TODO: take an oauth2 token source, similar to the go one
}

pub type BasicAuth = (String, Option<String>);
Expand Down Expand Up @@ -47,7 +46,6 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
// TODO: take an oauth2 token source, similar to the go one
}

pub type BasicAuth = (String, Option<String>);
Expand Down Expand Up @@ -47,7 +46,6 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
// TODO: take an oauth2 token source, similar to the go one
}

pub type BasicAuth = (String, Option<String>);
Expand Down Expand Up @@ -47,7 +46,6 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target/
**/*.rs.bk
Cargo.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
Loading

0 comments on commit 8ef3118

Please sign in to comment.