Skip to content

Commit 597fdff

Browse files
bogdadsunng87
andauthored
Added support for token auth (rebased, ci fixed) (#118)
* (refactor) use http header auth * (feat) add support for token based auth * (test) fix test case that checking parameter length for auth * (fix) revert changes for v1 username and password * (test) use separated integration tests for v1 and v2 * (fix) fix lint issues * (test) fix port error in integration test v2 * (fix) clippy error * (fix) update minimal rust version to 1.46 as socket2 requires * (fix) clippy error * (test) remove test that was duplicated in v2 * (fix) clippy warnings * (test) remove unneeded v2 tests * package `rustls v0.20.8` requires rustc 1.57 or newer * cargo fmt * fix rust version * package `async-global-executor v2.3.1` requires rustc 1.59 or newer * DOCKER_INFLUXDB_INIT_MODE: setup * using one hardcoded bucket in integration tests v2 * fixed no db "mydb" in integration tests seems to not happen anymore on influxdb 2.6 * readme and fixed readme check * style check * integration_tests_v2 are excluded from tarpaulin run because influxdb1.8 does not support auth tokens * clippy --------- Co-authored-by: Ning Sun <[email protected]>
1 parent a3e4a2d commit 597fdff

File tree

9 files changed

+210
-14
lines changed

9 files changed

+210
-14
lines changed

Diff for: .github/workflows/rust.yml

+42-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
runs-on: ${{ matrix.os }}
4040
strategy:
4141
matrix:
42-
rust_release: ["1.56", stable, nightly]
42+
rust_release: ["1.59", stable, nightly]
4343
os: [ubuntu-latest, windows-latest, macOS-latest]
4444

4545
steps:
@@ -50,8 +50,24 @@ jobs:
5050
- name: Build
5151
run: cargo build --verbose
5252

53+
unit_test:
54+
name: Unit test (${{ matrix.rust_release }}/${{ matrix.os }})
55+
runs-on: ${{ matrix.os }}
56+
strategy:
57+
matrix:
58+
rust_release: ["1.59", stable, nightly]
59+
os: [ubuntu-latest, windows-latest, macOS-latest]
60+
61+
steps:
62+
- uses: actions/checkout@v1
63+
- uses: dtolnay/rust-toolchain@master
64+
with:
65+
toolchain: ${{ matrix.rust_release }}
66+
- name: test
67+
run: cargo test --lib
68+
5369
integration_test:
54-
name: Integration Tests (stable/ubuntu-latest)
70+
name: Integration Tests for Influxdb 1.x (stable/ubuntu-latest)
5571
runs-on: ubuntu-latest
5672
strategy:
5773
matrix:
@@ -71,11 +87,33 @@ jobs:
7187
INFLUXDB_ADMIN_PASSWORD: password
7288
INFLUXDB_USER: nopriv_user
7389
INFLUXDB_USER_PASSWORD: password
74-
7590
steps:
7691
- uses: actions/checkout@v3
7792
- uses: dtolnay/rust-toolchain@stable
78-
- run: cargo test --manifest-path=./influxdb/Cargo.toml --no-default-features --features 'use-serde derive ${{ matrix.http-backend }}' --no-fail-fast
93+
- run: cargo test --manifest-path=./influxdb/Cargo.toml --no-default-features --features 'use-serde derive ${{ matrix.http-backend }}' --no-fail-fast --test integration_tests
94+
95+
integration_test_v2:
96+
name: Integration Tests for Influxdb 2.0 (stable/ubuntu-latest)
97+
runs-on: ubuntu-latest
98+
strategy:
99+
matrix:
100+
http-backend: [curl-client, h1-client, h1-client-rustls, hyper-client]
101+
services:
102+
influxdbv2:
103+
image: influxdb:2.6
104+
ports:
105+
- 9086:8086
106+
env:
107+
DOCKER_INFLUXDB_INIT_MODE: setup
108+
DOCKER_INFLUXDB_INIT_USERNAME: admin
109+
DOCKER_INFLUXDB_INIT_PASSWORD: password
110+
DOCKER_INFLUXDB_INIT_ORG: testing
111+
DOCKER_INFLUXDB_INIT_BUCKET: mydb
112+
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: admintoken
113+
steps:
114+
- uses: actions/checkout@v1
115+
- uses: dtolnay/rust-toolchain@stable
116+
- run: cargo test --manifest-path=./influxdb/Cargo.toml --no-default-features --features 'use-serde derive ${{ matrix.http-backend }}' --no-fail-fast --test integration_tests_v2
79117

80118
coverage:
81119
name: Code Coverage (stable/ubuntu-latest)

Diff for: auxiliary/update_cargo-readme.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/bash
22

33
our_version=$(cargo readme -V | perl -ne 'print $1 while /v([\d.]+)/g')
4-
last_version=$(cargo search cargo-readme | perl -ne 'print $1 while /^cargo-readme = "([\d.]+)"/g')
4+
last_version=$(cargo search --color=never cargo-readme | perl -ne 'print $1 while /^cargo-readme = "([\d.]+)"/g')
55

66
if [ "$our_version" == "$last_version" ]; then
77
echo Version $our_version is of cargo-readme is installed and up to date.

Diff for: influxdb/src/client/mod.rs

+34-4
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
use futures_util::TryFutureExt;
1919
use http::StatusCode;
2020
#[cfg(feature = "reqwest")]
21-
use reqwest::{Client as HttpClient, Response as HttpResponse};
21+
use reqwest::{Client as HttpClient, RequestBuilder, Response as HttpResponse};
2222
use std::collections::{BTreeMap, HashMap};
2323
use std::fmt::{self, Debug, Formatter};
2424
use std::sync::Arc;
2525
#[cfg(feature = "surf")]
26-
use surf::{Client as HttpClient, Response as HttpResponse};
26+
use surf::{Client as HttpClient, RequestBuilder, Response as HttpResponse};
2727

2828
use crate::query::QueryType;
2929
use crate::Error;
@@ -34,6 +34,7 @@ use crate::Query;
3434
pub struct Client {
3535
pub(crate) url: Arc<String>,
3636
pub(crate) parameters: Arc<HashMap<&'static str, String>>,
37+
pub(crate) token: Option<String>,
3738
pub(crate) client: HttpClient,
3839
}
3940

@@ -89,6 +90,7 @@ impl Client {
8990
url: Arc::new(url.into()),
9091
parameters: Arc::new(parameters),
9192
client: HttpClient::new(),
93+
token: None,
9294
}
9395
}
9496

@@ -126,6 +128,19 @@ impl Client {
126128
self
127129
}
128130

131+
/// Add authorization token to [`Client`](crate::Client)
132+
///
133+
/// This is designed for influxdb 2.0's backward-compatible API which
134+
/// requires authrozation by default. You can create such token from
135+
/// console of influxdb 2.0 .
136+
pub fn with_token<S>(mut self, token: S) -> Self
137+
where
138+
S: Into<String>,
139+
{
140+
self.token = Some(token.into());
141+
self
142+
}
143+
129144
/// Returns the name of the database the client is using
130145
pub fn database_name(&self) -> &str {
131146
// safe to unwrap: we always set the database name in `Self::new`
@@ -218,11 +233,11 @@ impl Client {
218233
error: err.to_string(),
219234
})?;
220235

236+
let mut parameters = self.parameters.as_ref().clone();
221237
let request_builder = match q.get_type() {
222238
QueryType::ReadQuery => {
223239
let read_query = query.get();
224240
let url = &format!("{}/query", &self.url);
225-
let mut parameters = self.parameters.as_ref().clone();
226241
parameters.insert("q", read_query.clone());
227242

228243
if read_query.contains("SELECT") || read_query.contains("SHOW") {
@@ -245,7 +260,8 @@ impl Client {
245260
error: err.to_string(),
246261
})?;
247262

248-
let res = request_builder
263+
let res = self
264+
.auth_if_needed(request_builder)
249265
.send()
250266
.map_err(|err| Error::ConnectionError {
251267
error: err.to_string(),
@@ -273,6 +289,14 @@ impl Client {
273289

274290
Ok(s)
275291
}
292+
293+
fn auth_if_needed(&self, rb: RequestBuilder) -> RequestBuilder {
294+
if let Some(ref token) = self.token {
295+
rb.header("Authorization", format!("Token {}", token))
296+
} else {
297+
rb
298+
}
299+
}
276300
}
277301

278302
pub(crate) fn check_status(res: &HttpResponse) -> Result<(), Error> {
@@ -327,5 +351,11 @@ mod tests {
327351
assert_eq!(with_auth.parameters.get("db").unwrap(), "database");
328352
assert_eq!(with_auth.parameters.get("u").unwrap(), "username");
329353
assert_eq!(with_auth.parameters.get("p").unwrap(), "password");
354+
355+
let client = Client::new("http://localhost:8068", "database");
356+
let with_auth = client.with_token("token");
357+
assert_eq!(with_auth.parameters.len(), 1);
358+
assert_eq!(with_auth.parameters.get("db").unwrap(), "database");
359+
assert_eq!(with_auth.token.unwrap(), "token");
330360
}
331361
}

Diff for: influxdb/src/query/line_proto_term.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ impl LineProtoTerm<'_> {
2323
pub fn escape(self) -> String {
2424
use LineProtoTerm::*;
2525
match self {
26-
Measurement(x) => Self::escape_any(x, &*COMMAS_SPACES),
27-
TagKey(x) | FieldKey(x) => Self::escape_any(x, &*COMMAS_SPACES_EQUALS),
26+
Measurement(x) => Self::escape_any(x, &COMMAS_SPACES),
27+
TagKey(x) | FieldKey(x) => Self::escape_any(x, &COMMAS_SPACES_EQUALS),
2828
FieldValue(x) => Self::escape_field_value(x),
2929
TagValue(x) => Self::escape_tag_value(x),
3030
}
@@ -44,7 +44,7 @@ impl LineProtoTerm<'_> {
4444
Float(v) => v.to_string(),
4545
SignedInteger(v) => format!("{}i", v),
4646
UnsignedInteger(v) => format!("{}u", v),
47-
Text(v) => format!(r#""{}""#, Self::escape_any(v, &*QUOTES_SLASHES)),
47+
Text(v) => format!(r#""{}""#, Self::escape_any(v, &QUOTES_SLASHES)),
4848
}
4949
}
5050

@@ -62,7 +62,7 @@ impl LineProtoTerm<'_> {
6262
Float(v) => format!(r#"{}"#, v),
6363
SignedInteger(v) => format!(r#"{}"#, v),
6464
UnsignedInteger(v) => format!(r#"{}"#, v),
65-
Text(v) => Self::escape_any(v, &*SLASHES),
65+
Text(v) => Self::escape_any(v, &SLASHES),
6666
}
6767
}
6868

Diff for: influxdb/src/query/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,11 @@ mod tests {
281281
}
282282
#[test]
283283
fn test_timestamp_from_chrono_date() {
284-
let timestamp_from_datetime: Timestamp = Utc.ymd(1970, 1, 1).and_hms(0, 0, 1).into();
284+
let timestamp_from_datetime: Timestamp = Utc
285+
.with_ymd_and_hms(1970, 1, 1, 0, 0, 1)
286+
.single()
287+
.unwrap()
288+
.into();
285289
assert_eq!(
286290
Timestamp::Nanoseconds(MILLIS_PER_SECOND * NANOS_PER_MILLI),
287291
timestamp_from_datetime

Diff for: influxdb/tests/derive_integration_tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ async fn test_write_and_read_option() {
101101
.query(&weather_reading.into_query("weather_reading".to_string()))
102102
.await;
103103
assert_result_ok(&write_result);
104+
104105
let query = ReadQuery::new("SELECT time, pressure, wind_strength FROM weather_reading");
105106
let result = client.json_query(query).await.and_then(|mut db_result| {
106107
println!("{:?}", db_result);

Diff for: influxdb/tests/integration_tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ async fn test_non_authed_write_and_read() {
215215

216216
let read_query = ReadQuery::new("SELECT * FROM weather");
217217
let read_result = non_authed_client.query(read_query).await;
218+
218219
assert_result_err(&read_result);
219220
match read_result {
220221
Err(Error::AuthorizationError) => {}

Diff for: influxdb/tests/integration_tests_v2.rs

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
extern crate influxdb;
2+
3+
#[path = "./utilities.rs"]
4+
mod utilities;
5+
use utilities::{assert_result_err, assert_result_ok, run_test};
6+
7+
use influxdb::InfluxDbWriteable;
8+
use influxdb::{Client, Error, ReadQuery, Timestamp};
9+
10+
/// INTEGRATION TEST
11+
///
12+
13+
/// This test case tests the Authentication
14+
#[async_std::test]
15+
#[cfg(not(tarpaulin))]
16+
async fn test_authed_write_and_read() {
17+
run_test(
18+
|| async move {
19+
let client = Client::new("http://127.0.0.1:9086", "mydb").with_token("admintoken");
20+
let write_query = Timestamp::Hours(11)
21+
.into_query("weather")
22+
.add_field("temperature", 82);
23+
let write_result = client.query(&write_query).await;
24+
assert_result_ok(&write_result);
25+
26+
let read_query = ReadQuery::new("SELECT * FROM weather");
27+
let read_result = client.query(read_query).await;
28+
assert_result_ok(&read_result);
29+
assert!(
30+
!read_result.unwrap().contains("error"),
31+
"Data contained a database error"
32+
);
33+
},
34+
|| async move {
35+
let client = Client::new("http://127.0.0.1:9086", "mydb").with_token("admintoken");
36+
let read_query = ReadQuery::new("DELETE MEASUREMENT weather");
37+
let read_result = client.query(read_query).await;
38+
assert_result_ok(&read_result);
39+
assert!(!read_result.unwrap().contains("error"), "Teardown failed");
40+
},
41+
)
42+
.await;
43+
}
44+
45+
/// INTEGRATION TEST
46+
///
47+
/// This test case tests the Authentication
48+
#[async_std::test]
49+
#[cfg(not(tarpaulin))]
50+
async fn test_wrong_authed_write_and_read() {
51+
run_test(
52+
|| async move {
53+
let client = Client::new("http://127.0.0.1:9086", "mydb").with_token("falsetoken");
54+
let write_query = Timestamp::Hours(11)
55+
.into_query("weather")
56+
.add_field("temperature", 82);
57+
let write_result = client.query(&write_query).await;
58+
assert_result_err(&write_result);
59+
match write_result {
60+
Err(Error::AuthorizationError) => {}
61+
_ => panic!(
62+
"Should be an AuthorizationError: {}",
63+
write_result.unwrap_err()
64+
),
65+
}
66+
67+
let read_query = ReadQuery::new("SELECT * FROM weather");
68+
let read_result = client.query(&read_query).await;
69+
assert_result_err(&read_result);
70+
match read_result {
71+
Err(Error::AuthorizationError) => {}
72+
_ => panic!(
73+
"Should be an AuthorizationError: {}",
74+
read_result.unwrap_err()
75+
),
76+
}
77+
},
78+
|| async move {},
79+
)
80+
.await;
81+
}
82+
83+
/// INTEGRATION TEST
84+
///
85+
/// This test case tests the Authentication
86+
#[async_std::test]
87+
#[cfg(not(tarpaulin))]
88+
async fn test_non_authed_write_and_read() {
89+
run_test(
90+
|| async move {
91+
let non_authed_client = Client::new("http://127.0.0.1:9086", "mydb");
92+
let write_query = Timestamp::Hours(11)
93+
.into_query("weather")
94+
.add_field("temperature", 82);
95+
let write_result = non_authed_client.query(&write_query).await;
96+
assert_result_err(&write_result);
97+
match write_result {
98+
Err(Error::AuthorizationError) => {}
99+
_ => panic!(
100+
"Should be an AuthorizationError: {}",
101+
write_result.unwrap_err()
102+
),
103+
}
104+
105+
let read_query = ReadQuery::new("SELECT * FROM weather");
106+
let read_result = non_authed_client.query(&read_query).await;
107+
assert_result_err(&read_result);
108+
match read_result {
109+
Err(Error::AuthorizationError) => {}
110+
_ => panic!(
111+
"Should be an AuthorizationError: {}",
112+
read_result.unwrap_err()
113+
),
114+
}
115+
},
116+
|| async move {},
117+
)
118+
.await;
119+
}

Diff for: influxdb/tests/utilities.rs

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub fn assert_result_ok<A: std::fmt::Debug, B: std::fmt::Debug>(result: &Result<
1414
result.as_ref().expect("assert_result_ok failed");
1515
}
1616

17+
#[allow(dead_code)]
1718
#[cfg(not(tarpaulin_include))]
1819
pub fn create_client<T>(db_name: T) -> Client
1920
where
@@ -22,6 +23,7 @@ where
2223
Client::new("http://127.0.0.1:8086", db_name)
2324
}
2425

26+
#[allow(dead_code)]
2527
#[cfg(not(tarpaulin_include))]
2628
pub async fn create_db<T>(name: T) -> Result<String, Error>
2729
where
@@ -32,6 +34,7 @@ where
3234
create_client(test_name).query(ReadQuery::new(query)).await
3335
}
3436

37+
#[allow(dead_code)]
3538
#[cfg(not(tarpaulin_include))]
3639
pub async fn delete_db<T>(name: T) -> Result<String, Error>
3740
where

0 commit comments

Comments
 (0)