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 <sunng@protonmail.com>
1 parent a3e4a2d commit 597fdff

File tree

9 files changed

+210
-14
lines changed

9 files changed

+210
-14
lines changed

.github/workflows/rust.yml

Lines changed: 42 additions & 4 deletions
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)

auxiliary/update_cargo-readme.sh

Lines changed: 1 addition & 1 deletion
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.

influxdb/src/client/mod.rs

Lines changed: 34 additions & 4 deletions
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
}

influxdb/src/query/line_proto_term.rs

Lines changed: 4 additions & 4 deletions
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

influxdb/src/query/mod.rs

Lines changed: 5 additions & 1 deletion
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

influxdb/tests/derive_integration_tests.rs

Lines changed: 1 addition & 0 deletions
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);

influxdb/tests/integration_tests.rs

Lines changed: 1 addition & 0 deletions
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) => {}
Lines changed: 119 additions & 0 deletions
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+
}

influxdb/tests/utilities.rs

Lines changed: 3 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy