Skip to content

Commit

Permalink
[Rust/Rust Server] Fix example/test code (OpenAPITools#19318)
Browse files Browse the repository at this point in the history
* [Rust Server] Fix code so examples compile

Zero length arrays don't correctly type infer, so if we have no scopes, we need to not create a empty array

We need an authentication middleware - without it the code doesn't compile.

* Update samples

* [Rust Server] Remove trailing whitespace

* Update samples

* [Rust Server] [CI] Build all targets

* [Rust] Fix reqwest test
  • Loading branch information
richardwhiuk authored Aug 9, 2024
1 parent 4b49335 commit ad7acc3
Show file tree
Hide file tree
Showing 28 changed files with 347 additions and 341 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/samples-rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ jobs:
toolchain: stable
- name: Build
working-directory: ${{ matrix.sample }}
run: cargo build
run: cargo build --all-targets
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import joptsimple.internal.Strings;
import lombok.Setter;
Expand Down Expand Up @@ -1108,6 +1109,20 @@ public Map<String, Object> postProcessSupportingFileData(Map<String, Object> bun
bundle.put("callbacks", callbackData);
}

// Flag whether we have any OAuth scopes
Map<String, SecurityScheme> securitySchemeMap = openAPI.getComponents() != null ? openAPI.getComponents().getSecuritySchemes() : null;
List<CodegenSecurity> authMethods = fromSecurity(securitySchemeMap);
boolean hasAuthScopes = false;
if (authMethods != null && !authMethods.isEmpty()) {
for (CodegenSecurity authMethod : authMethods) {
if (authMethod.hasScopes != null && authMethod.hasScopes) {
hasAuthScopes = true;
break;
}
}
}
bundle.put("hasAuthScopes", hasAuthScopes);

return super.postProcessSupportingFileData(bundle);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn main() {
{{#operation}}
{{#vendorExtensions}}
{{^x-no-client-example}}
"{{{operationId}}}",
"{{{operationId}}}",
{{/x-no-client-example}}
{{/vendorExtensions}}
{{/operation}}
Expand Down Expand Up @@ -80,24 +80,29 @@ fn main() {
// In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server
// Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side.
// See https://github.com/Keats/jsonwebtoken for more information

let auth_token = build_token(
Claims {
sub: "tester@acme.com".to_owned(),
sub: "tester@acme.com".to_owned(),
company: "ACME".to_owned(),
iss: "my_identity_provider".to_owned(),
// added a very long expiry time
aud: "org.acme.Resource_Server".to_string(),
exp: 10000000000,
// In this example code all available Scopes are added, so the current Bearer Token gets fully authorization.
scopes: [
{{#authMethods}}
{{#scopes}}
scopes:
{{#hasAuthScopes}}
[
{{#authMethods}}
{{#scopes}}
"{{{scope}}}",
{{/scopes}}
{{/authMethods}}
].join(", ")
},
{{/scopes}}
{{/authMethods}}
].join::<&str>(", ")
{{/hasAuthScopes}}
{{^hasAuthScopes}}
"".to_owned()
{{/hasAuthScopes}}
},
b"secret").unwrap();

let auth_data = if !auth_token.is_empty() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use swagger::{
ApiError,
auth::{Basic, Bearer},
Has,
Has,
XSpanIdString};
use {{{externCrateName}}}::{AuthenticationApi, Claims};
use crate::server::Server;
Expand All @@ -15,29 +15,35 @@ use log::{error, debug};

/// Get a dummy claim with full permissions (all scopes) for testing purposes
fn full_permission_claim() -> Claims {
Claims {
sub: "tester@acme.com".to_owned(),
company: "ACME".to_owned(),
iss: "mini-bank-IDP".to_owned(),
aud: "org.acme.Resource_Server".to_string(),
// added a very long expiry time
exp: 10000000000,
// In this example code all available Scopes are added, so the current Bearer Token gets fully authorization.
scopes: [
{{#authMethods}}
{{#scopes}}
"{{{scope}}}",
{{/scopes}}
{{/authMethods}}
].join(", ")
}
// In this example code all available Scopes are added, so the current Bearer Token gets fully authorization.
Claims {
sub: "tester@acme.com".to_owned(),
company: "ACME".to_owned(),
iss: "mini-bank-IDP".to_owned(),
aud: "org.acme.Resource_Server".to_string(),
// added a very long expiry time
exp: 10000000000,
scopes:
{{#hasAuthScopes}}
[
{{#authMethods}}
{{#scopes}}
"{{{scope}}}",
{{/scopes}}
{{/authMethods}}
].join::<&str>(", ")
{{/hasAuthScopes}}
{{^hasAuthScopes}}
"".to_owned()
{{/hasAuthScopes}}
}
}



/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example.
/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example.
fn extract_token_data(token: &str, key: &[u8]) -> Result<TokenData<Claims>, JwtError::Error> {
// Ensure that you set the correct algorithm and correct key.
// See https://github.com/Keats/jsonwebtoken for more information.
let header = decode_header(token)?;
Expand Down Expand Up @@ -68,8 +74,8 @@ fn build_authorization(claims: Claims) -> Authorization {
let scopes = swagger::auth::Scopes::Some(scopes);

Authorization{
subject: claims.sub,
scopes,
subject: claims.sub,
scopes,
issuer: Some(claims.iss)}
}

Expand Down Expand Up @@ -110,23 +116,23 @@ impl<C> AuthenticationApi for Server<C> where C: Has<XSpanIdString> + Send + Syn
fn apikey_authorization(&self, api_key: &str) -> Result<Authorization, ApiError> {
debug!("\tAuthorizationApi: Received api-key, {api_key:#?}");
// TODO: insert the logic to map received apikey to the set of claims
// TODO: insert the logic to map received apikey to the set of claims
let claims = full_permission_claim();
// and build an authorization out of it
Ok(build_authorization(claims))
}

/// Implementation of the method to map a basic authentication (username and password) to an Authorization
fn basic_authorization(&self, basic: &Basic) -> Result<Authorization, ApiError> {
debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}");
// TODO: insert the logic to map received apikey to the set of claims
// TODO: insert the logic to map received apikey to the set of claims
let claims = full_permission_claim();
// and build an authorization out of it
Ok(build_authorization(claims))
}

}
}

Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ pub async fn create(addr: &str, https: bool) {
let service = MakeService::new(server);
// This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels.
// This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore).
// let service = MakeAllowAllAuthenticator::new(service, "cosmo");
let service = MakeAllowAllAuthenticator::new(service, "cosmo");
#[allow(unused_mut)]
let mut service =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ fn test_types() {
double: 45.56,
string: String::from("something"),
boolean: true,
uuid: Uuid::new_v4()
uuid: Uuid::new_v4(),
bytes: vec![1,2,3,4]
};
assert_eq!(type_of(tt.int32), "i32");
assert_eq!(type_of(tt.int64), "i64");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ fn main() {
.arg(Arg::with_name("operation")
.help("Sets the operation to run")
.possible_values(&[
"MultipartRelatedRequestPost",
"MultipartRequestPost",
"MultipleIdenticalMimeTypesPost",
"MultipartRelatedRequestPost",
"MultipartRequestPost",
"MultipleIdenticalMimeTypesPost",
])
.required(true)
.index(1))
Expand All @@ -61,19 +61,18 @@ fn main() {
// In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server
// Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side.
// See https://github.com/Keats/jsonwebtoken for more information

let auth_token = build_token(
Claims {
sub: "tester@acme.com".to_owned(),
sub: "tester@acme.com".to_owned(),
company: "ACME".to_owned(),
iss: "my_identity_provider".to_owned(),
// added a very long expiry time
aud: "org.acme.Resource_Server".to_string(),
exp: 10000000000,
// In this example code all available Scopes are added, so the current Bearer Token gets fully authorization.
scopes: [
].join(", ")
},
scopes:
"".to_owned()
},
b"secret").unwrap();

let auth_data = if !auth_token.is_empty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ pub async fn create(addr: &str, https: bool) {

let service = MakeService::new(server);

// This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels.
// This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore).
// let service = MakeAllowAllAuthenticator::new(service, "cosmo");
let service = MakeAllowAllAuthenticator::new(service, "cosmo");

#[allow(unused_mut)]
let mut service =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use swagger::{
ApiError,
auth::{Basic, Bearer},
Has,
Has,
XSpanIdString};
use multipart_v3::{AuthenticationApi, Claims};
use crate::server::Server;
Expand All @@ -15,24 +15,24 @@ use log::{error, debug};

/// Get a dummy claim with full permissions (all scopes) for testing purposes
fn full_permission_claim() -> Claims {
Claims {
sub: "tester@acme.com".to_owned(),
company: "ACME".to_owned(),
iss: "mini-bank-IDP".to_owned(),
aud: "org.acme.Resource_Server".to_string(),
// added a very long expiry time
exp: 10000000000,
// In this example code all available Scopes are added, so the current Bearer Token gets fully authorization.
scopes: [
].join(", ")
}
// In this example code all available Scopes are added, so the current Bearer Token gets fully authorization.
Claims {
sub: "tester@acme.com".to_owned(),
company: "ACME".to_owned(),
iss: "mini-bank-IDP".to_owned(),
aud: "org.acme.Resource_Server".to_string(),
// added a very long expiry time
exp: 10000000000,
scopes:
"".to_owned()
}
}



/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example.
/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example.
fn extract_token_data(token: &str, key: &[u8]) -> Result<TokenData<Claims>, JwtError::Error> {

// Ensure that you set the correct algorithm and correct key.
// See https://github.com/Keats/jsonwebtoken for more information.
let header = decode_header(token)?;
Expand Down Expand Up @@ -63,8 +63,8 @@ fn build_authorization(claims: Claims) -> Authorization {
let scopes = swagger::auth::Scopes::Some(scopes);

Authorization{
subject: claims.sub,
scopes,
subject: claims.sub,
scopes,
issuer: Some(claims.iss)}
}

Expand Down Expand Up @@ -105,23 +105,23 @@ impl<C> AuthenticationApi for Server<C> where C: Has<XSpanIdString> + Send + Syn
fn apikey_authorization(&self, api_key: &str) -> Result<Authorization, ApiError> {
debug!("\tAuthorizationApi: Received api-key, {api_key:#?}");

// TODO: insert the logic to map received apikey to the set of claims
// TODO: insert the logic to map received apikey to the set of claims
let claims = full_permission_claim();

// and build an authorization out of it
Ok(build_authorization(claims))
}

/// Implementation of the method to map a basic authentication (username and password) to an Authorization
fn basic_authorization(&self, basic: &Basic) -> Result<Authorization, ApiError> {
debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}");

// TODO: insert the logic to map received apikey to the set of claims
// TODO: insert the logic to map received apikey to the set of claims
let claims = full_permission_claim();

// and build an authorization out of it
Ok(build_authorization(claims))
}

}
}

Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,18 @@ fn main() {
// In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server
// Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side.
// See https://github.com/Keats/jsonwebtoken for more information

let auth_token = build_token(
Claims {
sub: "tester@acme.com".to_owned(),
sub: "tester@acme.com".to_owned(),
company: "ACME".to_owned(),
iss: "my_identity_provider".to_owned(),
// added a very long expiry time
aud: "org.acme.Resource_Server".to_string(),
exp: 10000000000,
// In this example code all available Scopes are added, so the current Bearer Token gets fully authorization.
scopes: [
].join(", ")
},
scopes:
"".to_owned()
},
b"secret").unwrap();

let auth_data = if !auth_token.is_empty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ pub async fn create(addr: &str, https: bool) {

let service = MakeService::new(server);

// This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels.
// This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore).
// let service = MakeAllowAllAuthenticator::new(service, "cosmo");
let service = MakeAllowAllAuthenticator::new(service, "cosmo");

#[allow(unused_mut)]
let mut service =
Expand Down
Loading

0 comments on commit ad7acc3

Please sign in to comment.