Skip to content

Commit aba18e6

Browse files
authored
Add OAuth support (#484)
Fixes #410
1 parent 36a247c commit aba18e6

File tree

20 files changed

+1346
-225
lines changed

20 files changed

+1346
-225
lines changed

Cargo.lock

Lines changed: 101 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ xxhash-rust = { version = "0.8", features = ["xxh3"] }
8989
xz2 = { version = "*", features = ["static"] }
9090
nom = "7.1.3"
9191
humantime = "2.1.0"
92+
openid = { version = "0.12.0", default-features = false, features = ["rustls"] }
93+
url = "2.4.0"
9294

9395
[build-dependencies]
9496
cargo_toml = "0.15"

server/src/handlers/http.rs

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,17 @@
1818

1919
use std::fs::File;
2020
use std::io::BufReader;
21+
use std::sync::Arc;
2122

2223
use actix_cors::Cors;
23-
use actix_web::{web, App, HttpServer};
24+
use actix_web::{
25+
web::{self, resource},
26+
App, HttpServer,
27+
};
2428
use actix_web_prometheus::PrometheusMetrics;
2529
use actix_web_static_files::ResourceFiles;
30+
use log::info;
31+
use openid::Discovered;
2632
use rustls::{Certificate, PrivateKey, ServerConfig};
2733
use rustls_pemfile::{certs, pkcs8_private_keys};
2834

@@ -37,33 +43,47 @@ mod ingest;
3743
mod llm;
3844
mod logstream;
3945
mod middleware;
46+
mod oidc;
4047
mod query;
4148
mod rbac;
49+
mod role;
4250

4351
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
4452

4553
const MAX_EVENT_PAYLOAD_SIZE: usize = 10485760;
4654
const API_BASE_PATH: &str = "/api";
4755
const API_VERSION: &str = "v1";
4856

49-
#[macro_export]
50-
macro_rules! create_app {
51-
($prometheus: expr) => {
57+
pub async fn run_http(
58+
prometheus: PrometheusMetrics,
59+
oidc_client: Option<crate::oidc::OpenidConfig>,
60+
) -> anyhow::Result<()> {
61+
let oidc_client = match oidc_client {
62+
Some(config) => {
63+
let client = config
64+
.connect(&format!("{API_BASE_PATH}/{API_VERSION}/o/code"))
65+
.await?;
66+
Some(Arc::new(client))
67+
}
68+
None => None,
69+
};
70+
71+
let create_app = move || {
5272
App::new()
53-
.wrap($prometheus.clone())
54-
.configure(|cfg| configure_routes(cfg))
73+
.wrap(prometheus.clone())
74+
.configure(|cfg| configure_routes(cfg, oidc_client.clone()))
5575
.wrap(actix_web::middleware::Logger::default())
5676
.wrap(actix_web::middleware::Compress::default())
5777
.wrap(
5878
Cors::default()
5979
.allow_any_header()
6080
.allow_any_method()
61-
.allow_any_origin(),
81+
.allow_any_origin()
82+
.expose_any_header()
83+
.supports_credentials(),
6284
)
6385
};
64-
}
6586

66-
pub async fn run_http(prometheus: PrometheusMetrics) -> anyhow::Result<()> {
6787
let ssl_acceptor = match (
6888
&CONFIG.parseable.tls_cert_path,
6989
&CONFIG.parseable.tls_key_path,
@@ -99,7 +119,7 @@ pub async fn run_http(prometheus: PrometheusMetrics) -> anyhow::Result<()> {
99119
};
100120

101121
// concurrent workers equal to number of cores on the cpu
102-
let http_server = HttpServer::new(move || create_app!(prometheus)).workers(num_cpus::get());
122+
let http_server = HttpServer::new(create_app).workers(num_cpus::get());
103123
if let Some(config) = ssl_acceptor {
104124
http_server
105125
.bind_rustls(&CONFIG.parseable.address, config)?
@@ -112,7 +132,10 @@ pub async fn run_http(prometheus: PrometheusMetrics) -> anyhow::Result<()> {
112132
Ok(())
113133
}
114134

115-
pub fn configure_routes(cfg: &mut web::ServiceConfig) {
135+
pub fn configure_routes(
136+
cfg: &mut web::ServiceConfig,
137+
oidc_client: Option<Arc<openid::Client<Discovered, crate::oidc::Claims>>>,
138+
) {
116139
let generated = generate();
117140

118141
//log stream API
@@ -211,13 +234,13 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
211234
.route(
212235
web::put()
213236
.to(rbac::put_role)
214-
.authorize(Action::PutRoles)
237+
.authorize(Action::PutUserRoles)
215238
.wrap(DisAllowRootUser),
216239
)
217240
.route(
218241
web::get()
219242
.to(rbac::get_role)
220-
.authorize_for_user(Action::GetRole),
243+
.authorize_for_user(Action::GetUserRoles),
221244
),
222245
)
223246
.service(
@@ -238,6 +261,24 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
238261
.authorize(Action::QueryLLM),
239262
),
240263
);
264+
let role_api = web::scope("/role")
265+
.service(resource("").route(web::get().to(role::list).authorize(Action::ListRole)))
266+
.service(
267+
resource("/{name}")
268+
.route(web::put().to(role::put).authorize(Action::PutRole))
269+
.route(web::delete().to(role::delete).authorize(Action::DeleteRole))
270+
.route(web::get().to(role::get).authorize(Action::GetRole)),
271+
);
272+
273+
let mut oauth_api = web::scope("/o")
274+
.service(resource("/login").route(web::get().to(oidc::login)))
275+
.service(resource("/logout").route(web::get().to(oidc::logout)))
276+
.service(resource("/code").route(web::get().to(oidc::reply_login)));
277+
278+
if let Some(client) = oidc_client {
279+
info!("Registered oidc client");
280+
oauth_api = oauth_api.app_data(web::Data::from(client))
281+
}
241282

242283
// Deny request if username is same as the env variable P_USERNAME.
243284
cfg.service(
@@ -280,7 +321,9 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
280321
),
281322
)
282323
.service(user_api)
283-
.service(llm_query_api),
324+
.service(llm_query_api)
325+
.service(oauth_api)
326+
.service(role_api),
284327
)
285328
// GET "/" ==> Serve the static frontend directory
286329
.service(ResourceFiles::new("/", generated).resolve_not_found_to_root());

0 commit comments

Comments
 (0)