-
Notifications
You must be signed in to change notification settings - Fork 207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: impl basic auth #1531
feat: impl basic auth #1531
Changes from 1 commit
86ac808
94bb684
48e8790
aad84fa
cbb75ec
f169ee3
6c58696
970ef2a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Licensed to the Apache Software Foundation (ASF) under one | ||
// or more contributor license agreements. See the NOTICE file | ||
// distributed with this work for additional information | ||
// regarding copyright ownership. The ASF licenses this file | ||
// to you under the Apache License, Version 2.0 (the | ||
// "License"); you may not use this file except in compliance | ||
// with the License. You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, | ||
// software distributed under the License is distributed on an | ||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
// KIND, either express or implied. See the License for the | ||
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
//! The proxy module provides features such as forwarding and authentication, | ||
//! adapts to different protocols. | ||
|
||
use std::{collections::HashMap, fs::File, io, io::BufRead, path::Path}; | ||
|
||
use snafu::ResultExt; | ||
|
||
use crate::auth::{Auth, FileNotExisted, OpenFile, ReadLine, Result, ADMIN_TENANT}; | ||
|
||
pub struct AuthWithFile { | ||
file_path: String, | ||
users: HashMap<String, String>, | ||
} | ||
|
||
impl AuthWithFile { | ||
pub fn new(file_path: String) -> Self { | ||
Self { | ||
file_path, | ||
users: HashMap::new(), | ||
} | ||
} | ||
} | ||
|
||
impl Auth for AuthWithFile { | ||
/// Load credential from file | ||
fn load_credential(&mut self) -> Result<()> { | ||
let path = Path::new(&self.file_path); | ||
if !path.exists() { | ||
return FileNotExisted { | ||
path: self.file_path.clone(), | ||
} | ||
.fail(); | ||
} | ||
|
||
let file = File::open(path).context(OpenFile)?; | ||
let reader = io::BufReader::new(file); | ||
|
||
for line in reader.lines() { | ||
let line = line.context(ReadLine)?; | ||
if let Some((value, key)) = line.split_once(':') { | ||
self.users.insert(key.to_string(), value.to_string()); | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn identify(&self, tenant: Option<String>, token: Option<String>) -> bool { | ||
if let Some(tenant) = tenant { | ||
if tenant == ADMIN_TENANT { | ||
return true; | ||
} | ||
} | ||
|
||
match token { | ||
Some(token) => self.users.contains_key(&token), | ||
None => false, | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Licensed to the Apache Software Foundation (ASF) under one | ||
// or more contributor license agreements. See the NOTICE file | ||
// distributed with this work for additional information | ||
// regarding copyright ownership. The ASF licenses this file | ||
// to you under the Apache License, Version 2.0 (the | ||
// "License"); you may not use this file except in compliance | ||
// with the License. You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, | ||
// software distributed under the License is distributed on an | ||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
// KIND, either express or implied. See the License for the | ||
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
//! The proxy module provides features such as forwarding and authentication, | ||
//! adapts to different protocols. | ||
|
||
use std::sync::{Arc, Mutex}; | ||
|
||
use macros::define_result; | ||
use serde::{Deserialize, Serialize}; | ||
use snafu::Snafu; | ||
|
||
pub mod auth_with_file; | ||
|
||
#[derive(Debug, Snafu)] | ||
pub enum Error { | ||
#[snafu(display("Failed to open file, err:{}.", source))] | ||
OpenFile { source: std::io::Error }, | ||
|
||
#[snafu(display("Failed to read line, err:{}.", source))] | ||
ReadLine { source: std::io::Error }, | ||
|
||
#[snafu(display("File not existed, file path:{}", path))] | ||
FileNotExisted { path: String }, | ||
} | ||
|
||
define_result!(Error); | ||
|
||
pub type AuthRef = Arc<Mutex<dyn Auth>>; | ||
|
||
/// Header of tenant name | ||
pub const TENANT_HEADER: &str = "x-horaedb-access-tenant"; | ||
/// Header of tenant name | ||
pub const TENANT_TOKEN_HEADER: &str = "x-horaedb-access-token"; | ||
|
||
/// Admin tenant name | ||
pub const ADMIN_TENANT: &str = "admin"; | ||
|
||
#[derive(Debug, Clone, Deserialize, Serialize, Default)] | ||
pub struct Config { | ||
pub enable: bool, | ||
pub auth_type: String, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Define this with an Enum. |
||
pub source: String, | ||
} | ||
|
||
pub trait Auth: Send + Sync { | ||
fn load_credential(&mut self) -> Result<()>; | ||
fn identify(&self, tenant: Option<String>, token: Option<String>) -> bool; | ||
} | ||
|
||
#[derive(Default)] | ||
pub struct AuthBase; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Authorizator |
||
|
||
impl Auth for AuthBase { | ||
fn load_credential(&mut self) -> Result<()> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove default implementation. |
||
Ok(()) | ||
} | ||
|
||
fn identify(&self, _tenant: Option<String>, _token: Option<String>) -> bool { | ||
true | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -81,6 +81,21 @@ impl Proxy { | |
msg: "Missing context", | ||
code: StatusCode::BAD_REQUEST, | ||
})?; | ||
|
||
// Check if the tenant is authorized to access the database. | ||
if !self | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use interceptor to do auth check for gRPC For HTTP, see https://stackoverflow.com/questions/54988438/how-to-check-the-authorization-header-using-warp |
||
.auth | ||
.lock() | ||
.unwrap() | ||
.identify(ctx.tenant.clone(), ctx.access_token) | ||
{ | ||
return ErrNoCause { | ||
msg: format!("tenant: {:?} unauthorized", ctx.tenant), | ||
code: StatusCode::UNAUTHORIZED, | ||
} | ||
.fail(); | ||
} | ||
|
||
let schema = req_ctx.database; | ||
let catalog = self.instance.catalog_manager.default_catalog_name(); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basic authorization use
authorization
header, we should avoid those custom headers.