Skip to content
This repository has been archived by the owner on Dec 18, 2024. It is now read-only.

Add authorization integration test #708

Merged
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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions kuksa_databroker/databroker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ name = "databroker"
path = "src/lib.rs"

[dependencies]
common = { path = "../lib"}
kuksa = { path = "../lib/kuksa"}
databroker-proto = { workspace = true }
tonic = { workspace = true, features = ["transport", "channel", "prost"] }
prost = { workspace = true }
Expand Down Expand Up @@ -78,6 +80,7 @@ vergen = { version = "8", features = [

[dev-dependencies]
anyhow = "1.0"
chrono = "^0.4"
cucumber = { version = "0.20", default-features = false, features = ["libtest", "macros"] }

[[test]]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,65 @@
Feature: Reading and writing values of a VSS Data Entry

Rule: Access with right permissions succeeds and fails with wrong/no permissions

Background:
Given a running Databroker server with authorization enabled with the following Data Entries registered
| path | data type | change type | type |
| Vehicle.Speed | float | Static | Sensor |
| Vehicle.ADAS.ABS.IsEnabled | bool | Static | Actuator |

Scenario: Writing the current value of an unset Data Entry without authenticating fails
When a client sets the current value of Vehicle.Width of type float to 13.4
Then the operation fails with status code 16

Scenario: Read the current value of an unset Data Entry without authenticating fails
When a client gets the current value of Vehicle.Width
Then the operation fails with status code 16

Scenario: Writing the current value of a Data Entry without right permissions fails
When a client uses a token with scope read
And a client sets the current value of Vehicle.Speed of type float to 13.4
Then setting the value for Vehicle.Speed fails with error code 403

Scenario: Writing the current value of a Data Entry without right permissions fails
When a client uses a token with scope actuate
And a client sets the current value of Vehicle.Speed of type float to 13.4
Then setting the value for Vehicle.Speed fails with error code 403

Scenario: Writing the current value of a Data Entry without right permissions fails
When a client uses a token with scope provide:Vehicle.ADAS.ABS.IsEnabled
And a client sets the current value of Vehicle.Speed of type float to 13.4
Then setting the value for Vehicle.Speed fails with error code 403

Scenario: Writing the current value of a Data Entry with right permissions succeeds
When a client uses a token with scope provide:Vehicle.Speed
And a client sets the current value of Vehicle.Speed of type float to 13.4
Then the set operation succeeds

Scenario: Writing the target value of a Data Entry without right permissions fails
When a client uses a token with scope read
And a client sets the target value of Vehicle.ADAS.ABS.IsEnabled of type bool to true
Then setting the value for Vehicle.Speed fails with error code 403

Scenario: Writing the target value of a Data Entry without right permissions fails
When a client uses a token with scope provide
And a client sets the target value of Vehicle.ADAS.ABS.IsEnabled of type bool to true
Then setting the value for Vehicle.Speed fails with error code 403

Scenario: Writing the target value of a Data Entry without right permissions fails
When a client uses a token with scope actuate:Vehicle.Speed
And a client sets the target value of Vehicle.ADAS.ABS.IsEnabled of type bool to true
Then setting the value for Vehicle.Speed fails with error code 403

Scenario: Writing the target value of a Data Entry with right permissions succeeds
When a client uses a token with scope actuate:Vehicle.ADAS.ABS.IsEnabled
And a client sets the target value of Vehicle.ADAS.ABS.IsEnabled of type bool to true
Then the set operation succeeds

Rule: Accessing unregistered Data Entries fails

Background:
Given a running Databroker server
Given a running Databroker server with authorization disabled

Scenario: Setting the current value of an unregistered Data Entry fails
When a client sets the current value of No.Such.Path of type float to 13.4
Expand All @@ -24,7 +80,7 @@ Feature: Reading and writing values of a VSS Data Entry
Rule: Target values can only be set on Actuators

Background:
Given a running Databroker server with the following Data Entries registered
Given a running Databroker server with authorization disabled with the following Data Entries registered
| path | data type | change type | type |
| Vehicle.Powertrain.Range | uint32 | Continuous | Sensor |
| Vehicle.Width | uint16 | Static | Attribute |
Expand All @@ -40,7 +96,7 @@ Feature: Reading and writing values of a VSS Data Entry
Rule: Accessing registered Data Entries works

Background:
Given a running Databroker server with the following Data Entries registered
Given a running Databroker server with authorization disabled with the following Data Entries registered
| path | data type | change type | type |
| Vehicle.Cabin.Lights.AmbientLight | uint8 | OnChange | Actuator |
| Vehicle.Cabin.Sunroof.Position | int8 | OnChange | Actuator |
Expand Down
150 changes: 81 additions & 69 deletions kuksa_databroker/databroker/tests/read_write_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@
********************************************************************************/

use core::panic;
use std::{future, time::SystemTime, vec};
use std::{collections::HashMap, future, time::SystemTime, vec};

use cucumber::{cli, gherkin::Step, given, then, when, writer, World as _};
use databroker::broker;
use databroker_proto::kuksa::val::v1::{
datapoint::Value, DataEntry, DataType, Datapoint, EntryRequest, EntryUpdate, Field, GetRequest,
SetRequest, View,
};
use databroker_proto::kuksa::val::v1::{datapoint::Value, DataType, Datapoint};
use tracing::debug;
use world::{DataBrokerWorld, ValueType};

Expand Down Expand Up @@ -75,9 +72,19 @@ fn get_data_entries_from_table(
data_entries
}

#[given(regex = "^a running Databroker server.*$")]
async fn start_databroker_server(w: &mut DataBrokerWorld, step: &Step) {
w.start_databroker(get_data_entries_from_table(step)).await;
#[given(regex = "^a running Databroker server with authorization (enabled|disabled).*$")]
async fn start_databroker_server(w: &mut DataBrokerWorld, auth: String, step: &Step) {
let authorization_enabled: bool;
if auth == "enabled" {
authorization_enabled = true;
} else if auth == "disabled" {
authorization_enabled = false;
} else {
panic!("Not a known authorization keyword use enabled/disabled!")
}

w.start_databroker(get_data_entries_from_table(step), authorization_enabled)
.await;
assert!(w.broker_client.is_some())
}

Expand All @@ -90,7 +97,22 @@ async fn a_known_data_entry_has_value(
value: String,
) {
set_value(w, value_type, path, data_type, value).await;
w.assert_set_response_has_succeeded()
w.assert_set_succeeded()
}

#[when(expr = "a client uses a token with scope {word}")]
async fn authorize_client(w: &mut DataBrokerWorld, scope: String) {
let token = w.create_token(scope);
w.broker_client
.as_mut()
.and_then(|client| match client.basic_client.set_access_token(token) {
Ok(()) => Some(client),
Err(e) => {
println!("Error: {e}");
None
}
})
.expect("no Databroker client available, broker not started?");
}

#[when(expr = "a client sets the {word} value of {word} of type {word} to {word}")]
Expand All @@ -111,42 +133,34 @@ async fn set_value(
value: Some(value),
};

let data_entry = match value_type {
ValueType::Current => DataEntry {
path: path.clone(),
value: Some(datapoint),
actuator_target: None,
metadata: None,
},
ValueType::Target => DataEntry {
path: path.clone(),
value: None,
actuator_target: Some(datapoint),
metadata: None,
},
};
let req = SetRequest {
updates: vec![EntryUpdate {
entry: Some(data_entry),
fields: vec![
Field::ActuatorTarget.into(),
Field::Value.into(),
Field::Path.into(),
],
}],
};
match client.set(req).await {
Ok(res) => {
let set_response = res.into_inner();
debug!(
"response from Databroker [global error: {:?}, Data Entry errors: {:?}]",
set_response.error, set_response.errors
);
w.current_set_response = Some(set_response);
match value_type {
ValueType::Target => {
match client
.set_target_values(HashMap::from([(path.clone(), datapoint.clone())]))
.await
{
Ok(_) => {
w.current_client_error = None;
}
Err(e) => {
debug!("failed to invoke Databroker's set operation: {:?}", e);
w.current_client_error = Some(e);
}
}
}
Err(e) => {
debug!("failed to invoke Databroker's set operation: {:?}", e);
w.current_status = Some(e);
ValueType::Current => {
match client
.set_current_values(HashMap::from([(path.clone(), datapoint.clone())]))
.await
{
Ok(_) => {
w.current_client_error = None;
}
Err(e) => {
debug!("failed to invoke Databroker's set operation: {:?}", e);
w.current_client_error = Some(e);
}
}
}
}
}
Expand All @@ -157,22 +171,21 @@ async fn get_value(w: &mut DataBrokerWorld, value_type: ValueType, path: String)
.broker_client
.as_mut()
.expect("no Databroker client available, broker not started?");
let get_request = GetRequest {
entries: vec![EntryRequest {
path: path.to_string(),
view: match value_type {
ValueType::Current => View::CurrentValue.into(),
ValueType::Target => View::TargetValue.into(),
},
fields: vec![Field::Value.into(), Field::Metadata.into()],
}],
};
match client.get(get_request).await {
Ok(res) => w.current_get_response = Some(res.into_inner()),
Err(e) => {
debug!("failed to invoke Databroker's get operation: {:?}", e);
w.current_status = Some(e);
}
match value_type {
ValueType::Target => match client.get_target_values(vec![&path]).await {
Ok(res) => w.current_data_entries = Some(res),
Err(e) => {
debug!("failed to invoke Databroker's get operation: {:?}", e);
w.current_client_error = Some(e);
}
},
ValueType::Current => match client.get_current_values(vec![path]).await {
Ok(res) => w.current_data_entries = Some(res),
Err(e) => {
debug!("failed to invoke Databroker's get operation: {:?}", e);
w.current_client_error = Some(e);
}
},
}
}

Expand Down Expand Up @@ -224,18 +237,12 @@ fn assert_value_is_unspecified(w: &mut DataBrokerWorld, value_type: ValueType, p

#[then(regex = r"^the (current|target) value is not found$")]
fn assert_value_not_found(w: &mut DataBrokerWorld) {
let error_code = w
.current_get_response
.clone()
.and_then(|res| res.error)
.map(|error| error.code);

assert_eq!(error_code, Some(404));
w.assert_response_has_error_code(vec![404]);
}

#[then(expr = "setting the value for {word} fails with error code {int}")]
fn assert_set_request_failure(w: &mut DataBrokerWorld, path: String, expected_error_code: u32) {
w.assert_set_response_has_error_code(path, expected_error_code)
fn assert_set_request_failure(w: &mut DataBrokerWorld, _path: String, expected_error_code: u32) {
w.assert_response_has_error_code(vec![expected_error_code])
}

/// https://github.com/grpc/grpc/blob/master/doc/statuscodes.md#status-codes-and-their-use-in-grpc
Expand All @@ -244,6 +251,11 @@ fn assert_request_failure(w: &mut DataBrokerWorld, expected_status_code: i32) {
w.assert_status_has_code(expected_status_code)
}

#[then(expr = "the set operation succeeds")]
fn assert_set_succeeds(w: &mut DataBrokerWorld) {
w.assert_set_succeeded()
}

#[tokio::main]
async fn main() {
// databroker::init_logging();
Expand Down
Loading