1818
1919use std:: fs:: File ;
2020use std:: io:: BufReader ;
21+ use std:: sync:: Arc ;
2122
2223use actix_cors:: Cors ;
23- use actix_web:: { web, App , HttpServer } ;
24+ use actix_web:: {
25+ web:: { self , resource} ,
26+ App , HttpServer ,
27+ } ;
2428use actix_web_prometheus:: PrometheusMetrics ;
2529use actix_web_static_files:: ResourceFiles ;
30+ use log:: info;
31+ use openid:: Discovered ;
2632use rustls:: { Certificate , PrivateKey , ServerConfig } ;
2733use rustls_pemfile:: { certs, pkcs8_private_keys} ;
2834
@@ -37,33 +43,47 @@ mod ingest;
3743mod llm;
3844mod logstream;
3945mod middleware;
46+ mod oidc;
4047mod query;
4148mod rbac;
49+ mod role;
4250
4351include ! ( concat!( env!( "OUT_DIR" ) , "/generated.rs" ) ) ;
4452
4553const MAX_EVENT_PAYLOAD_SIZE : usize = 10485760 ;
4654const API_BASE_PATH : & str = "/api" ;
4755const 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