Skip to content

Commit 9e22255

Browse files
authored
feat: auth by refresh and session tokens. (#16220)
* feat: auth by refresh and session tokens. * fix tests. * remove TokenApi. * polish comments * use Duration const instead of int. * small refactor * /login and /renew return enum. * clean unused code. * more secure nonce. * fix clippy. * remove unused code. * avoid use url path directly. * extract middleware_fn json_response from HttpSessionMiddleware. * fix test. * fix fmt.
1 parent 9a45829 commit 9e22255

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1156
-260
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/common/exception/src/exception_code.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,4 +417,9 @@ build_exceptions! {
417417
build_exceptions! {
418418
// A task that already stopped and can not stopped twice.
419419
AlreadyStopped(5002),
420+
421+
SessionTokenExpired(5100),
422+
RefreshTokenExpired(5101),
423+
SessionTokenNotFound(5102),
424+
RefreshTokenNotFound(5103)
420425
}

src/meta/app/src/principal/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ pub mod tenant_user_ident;
4646
pub mod user_defined_file_format_ident;
4747
pub mod user_setting_ident;
4848
pub mod user_stage_ident;
49+
pub mod user_token;
50+
pub mod user_token_ident;
4951

5052
pub use connection::*;
5153
pub use file_format::*;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2021 Datafuse Labs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use serde::Deserialize;
16+
use serde::Serialize;
17+
18+
/// A client starts with /session/login to get the initial refresh_token and session_token pair.
19+
/// - Use session_token for computing.
20+
/// - Use refresh_token to auth /session/renew and get new pair when session_token expires.
21+
#[derive(
22+
serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq, num_derive::FromPrimitive,
23+
)]
24+
pub enum TokenType {
25+
Refresh = 1,
26+
Session = 2,
27+
}
28+
29+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
30+
pub struct QueryTokenInfo {
31+
pub token_type: TokenType,
32+
/// used to delete refresh token when close session, which authed by session_token too.
33+
/// None for Refresh token.
34+
pub parent: Option<String>,
35+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2021 Datafuse Labs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use crate::tenant_key::ident::TIdent;
16+
17+
/// Define the meta-service key for a user setting.
18+
pub type TokenIdent = TIdent<Resource>;
19+
20+
pub use kvapi_impl::Resource;
21+
22+
mod kvapi_impl {
23+
24+
use databend_common_meta_kvapi::kvapi;
25+
26+
use crate::principal::user_token::QueryTokenInfo;
27+
use crate::tenant_key::resource::TenantResource;
28+
29+
pub struct Resource;
30+
impl TenantResource for Resource {
31+
const PREFIX: &'static str = "__fd_token";
32+
const TYPE: &'static str = "TokenIdent";
33+
const HAS_TENANT: bool = true;
34+
type ValueType = QueryTokenInfo;
35+
}
36+
37+
impl kvapi::Value for QueryTokenInfo {
38+
fn dependency_keys(&self) -> impl IntoIterator<Item = String> {
39+
[]
40+
}
41+
}
42+
}
43+
44+
#[cfg(test)]
45+
mod tests {
46+
use databend_common_meta_kvapi::kvapi::Key;
47+
48+
use crate::principal::user_token_ident::TokenIdent;
49+
use crate::tenant::Tenant;
50+
51+
#[test]
52+
fn test_setting_ident() {
53+
let tenant = Tenant::new_literal("tenant1");
54+
let ident = TokenIdent::new(tenant.clone(), "test");
55+
assert_eq!("__fd_token/tenant1/test", ident.to_string_key());
56+
57+
let got = TokenIdent::from_str_key(&ident.to_string_key()).unwrap();
58+
assert_eq!(ident, got);
59+
}
60+
}

src/meta/proto-conv/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ mod stage_from_to_protobuf_impl;
8686
mod table_from_to_protobuf_impl;
8787
mod tenant_quota_from_to_protobuf_impl;
8888
mod tident_from_to_protobuf_impl;
89+
mod token_from_to_protobuf_impl;
8990
mod udf_from_to_protobuf_impl;
9091
mod user_from_to_protobuf_impl;
9192
mod util;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2021 Datafuse Labs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//! This mod is the key point about compatibility.
16+
//! Everytime update anything in this file, update the `VER` and let the tests pass.
17+
18+
use databend_common_meta_app::principal::user_token as mt;
19+
use databend_common_protos::pb;
20+
use num::FromPrimitive;
21+
22+
use crate::reader_check_msg;
23+
use crate::FromToProto;
24+
use crate::Incompatible;
25+
use crate::MIN_READER_VER;
26+
use crate::VER;
27+
28+
impl FromToProto for mt::QueryTokenInfo {
29+
type PB = pb::TokenInfo;
30+
31+
fn get_pb_ver(p: &Self::PB) -> u64 {
32+
p.ver
33+
}
34+
35+
fn from_pb(p: Self::PB) -> Result<Self, Incompatible>
36+
where Self: Sized {
37+
reader_check_msg(p.ver, p.min_reader_ver)?;
38+
39+
let v = Self {
40+
token_type: FromPrimitive::from_i32(p.token_type).ok_or_else(|| Incompatible {
41+
reason: format!("invalid TokenType: {}", p.token_type),
42+
})?,
43+
parent: p.parent,
44+
};
45+
Ok(v)
46+
}
47+
48+
fn to_pb(&self) -> Result<Self::PB, Incompatible> {
49+
let p = pb::TokenInfo {
50+
ver: VER,
51+
min_reader_ver: MIN_READER_VER,
52+
token_type: self.token_type.clone() as i32,
53+
parent: self.parent.clone(),
54+
};
55+
Ok(p)
56+
}
57+
}

src/meta/proto-conv/src/util.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ const META_CHANGE_LOG: &[(u64, &str)] = &[
135135
(103, "2024-07-31: Add: ShareMetaV2"),
136136
(104, "2024-08-02: Add: add share catalog into Catalog meta"),
137137
(105, "2024-08-05: Add: add Dictionary meta"),
138+
(106, "2024-08-08: Add: add QueryTokenInfo"),
138139
// Dear developer:
139140
// If you're gonna add a new metadata version, you'll have to add a test for it.
140141
// You could just copy an existing test file(e.g., `../tests/it/v024_table_meta.rs`)

src/meta/proto-conv/tests/it/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,4 @@ mod v102_user_must_change_password;
109109
mod v103_share_meta_v2;
110110
mod v104_share_catalog;
111111
mod v105_dictionary_meta;
112+
mod v106_query_token;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2023 Datafuse Labs.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use databend_common_meta_app::principal::user_token::TokenType;
16+
use fastrace::func_name;
17+
18+
use crate::common;
19+
20+
// These bytes are built when a new version in introduced,
21+
// and are kept for backward compatibility test.
22+
//
23+
// *************************************************************
24+
// * These messages should never be updated, *
25+
// * only be added when a new version is added, *
26+
// * or be removed when an old version is no longer supported. *
27+
// *************************************************************
28+
//
29+
// The message bytes are built from the output of `test_pb_from_to()`
30+
#[test]
31+
fn test_v106_query_token_info() -> anyhow::Result<()> {
32+
let query_token_info_v106 = vec![
33+
8, 1, 18, 17, 112, 97, 114, 101, 110, 116, 95, 116, 111, 107, 101, 110, 95, 104, 97, 115,
34+
104, 160, 6, 106, 168, 6, 24,
35+
];
36+
37+
let want = || databend_common_meta_app::principal::user_token::QueryTokenInfo {
38+
token_type: TokenType::Refresh,
39+
parent: Some("parent_token_hash".to_string()),
40+
};
41+
42+
common::test_pb_from_to(func_name!(), want())?;
43+
common::test_load_old(func_name!(), query_token_info_v106.as_slice(), 106, want())
44+
}

0 commit comments

Comments
 (0)