Skip to content

Commit 13dae0a

Browse files
committed
Add permissions to proxy
1 parent fe18e4e commit 13dae0a

File tree

5 files changed

+328
-31
lines changed

5 files changed

+328
-31
lines changed

josh-proxy/src/bin/josh-proxy.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct JoshProxyService {
4646
fetch_permits: Arc<tokio::sync::Semaphore>,
4747
filter_permits: Arc<tokio::sync::Semaphore>,
4848
poll: Polls,
49+
acl: Option<(String, String)>,
4950
}
5051

5152
impl std::fmt::Debug for JoshProxyService {
@@ -244,9 +245,11 @@ async fn do_filter(
244245
temp_ns: Arc<josh_proxy::TmpGitNamespace>,
245246
filter_spec: String,
246247
headref: String,
248+
user: String,
247249
) -> josh::JoshResult<()> {
248250
let permit = service.filter_permits.acquire().await;
249251
let heads_map = service.heads_map.clone();
252+
let acl = service.acl.clone();
250253

251254
let s = tracing::span!(tracing::Level::TRACE, "do_filter worker");
252255
let r = tokio::task::spawn_blocking(move || {
@@ -295,7 +298,28 @@ async fn do_filter(
295298

296299
let mut headref = headref;
297300

298-
josh::filter_refs(&transaction, filter, &from_to, josh::filter::empty())?;
301+
let permissions_filter = if let Some(acl) = acl {
302+
let users = &acl.0;
303+
let groups = &acl.1;
304+
tracing::info!("User: {:?}, Repo: {:?}", user, upstream_repo);
305+
let acl = match josh::get_acl(&users, &groups, &user, &upstream_repo) {
306+
Ok(acl) => acl,
307+
Err(e) => {
308+
tracing::error!("Failed to read ACL file: {:?}", e);
309+
(josh::filter::empty(), josh::filter::nop())
310+
}
311+
};
312+
let whitelist = acl.0;
313+
let blacklist = acl.1;
314+
tracing::info!("Whitelist: {:?}, Blacklist: {:?}", whitelist, blacklist);
315+
josh::filter::make_permissions_filter(filter, whitelist, blacklist)
316+
} else {
317+
josh::filter::empty()
318+
};
319+
320+
tracing::info!("Permissions: {:?}", permissions_filter);
321+
322+
josh::filter_refs(&transaction, filter, &from_to, permissions_filter)?;
299323
if headref == "HEAD" {
300324
headref = heads_map
301325
.read()?
@@ -517,6 +541,7 @@ async fn call_service(
517541
&parsed_url.upstream_repo,
518542
&parsed_url.filter,
519543
&headref,
544+
&username,
520545
)
521546
.in_current_span()
522547
.await?;
@@ -598,6 +623,7 @@ async fn prepare_namespace(
598623
upstream_repo: &str,
599624
filter_spec: &str,
600625
headref: &str,
626+
user: &str,
601627
) -> josh::JoshResult<std::sync::Arc<josh_proxy::TmpGitNamespace>> {
602628
let temp_ns = Arc::new(josh_proxy::TmpGitNamespace::new(
603629
&serv.repo_path,
@@ -606,13 +632,16 @@ async fn prepare_namespace(
606632

607633
let serv = serv.clone();
608634

635+
let user = if user == "" { "anonymous" } else { user };
636+
609637
do_filter(
610638
serv.repo_path.clone(),
611639
serv.clone(),
612640
upstream_repo.to_owned(),
613641
temp_ns.to_owned(),
614642
filter_spec.to_owned(),
615643
headref.to_string(),
644+
user.to_string(),
616645
)
617646
.await?;
618647

@@ -635,6 +664,20 @@ async fn run_proxy() -> josh::JoshResult<i32> {
635664
josh_proxy::create_repo(&local)?;
636665
josh::cache::load(&local)?;
637666

667+
let acl = if ARGS.is_present("users") && ARGS.is_present("groups") {
668+
println!(
669+
"{}, {}",
670+
ARGS.value_of("users").unwrap().to_string(),
671+
ARGS.value_of("groups").unwrap().to_string()
672+
);
673+
Some((
674+
ARGS.value_of("users").unwrap().to_string(),
675+
ARGS.value_of("groups").unwrap().to_string(),
676+
))
677+
} else {
678+
None
679+
};
680+
638681
let proxy_service = Arc::new(JoshProxyService {
639682
port,
640683
repo_path: local.to_owned(),
@@ -646,6 +689,7 @@ async fn run_proxy() -> josh::JoshResult<i32> {
646689
ARGS.value_of("n").unwrap_or("1").parse()?,
647690
)),
648691
filter_permits: Arc::new(tokio::sync::Semaphore::new(10)),
692+
acl,
649693
});
650694

651695
let ps = proxy_service.clone();
@@ -800,6 +844,18 @@ fn parse_args() -> clap::ArgMatches<'static> {
800844
.help("Duration between forced cache refresh")
801845
.takes_value(true),
802846
)
847+
.arg(
848+
clap::Arg::with_name("users")
849+
.long("users")
850+
.takes_value(true)
851+
.help("YAML file listing the groups of the users"),
852+
)
853+
.arg(
854+
clap::Arg::with_name("groups")
855+
.long("groups")
856+
.takes_value(true)
857+
.help("YAML file listing the access rights of the groups"),
858+
)
803859
.get_matches_from(args)
804860
}
805861

josh-proxy/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ impl TmpGitNamespace {
422422
pub fn new(repo_path: &std::path::Path, span: tracing::Span) -> TmpGitNamespace {
423423
let n = format!("request_{}", uuid::Uuid::new_v4());
424424
let n2 = n.clone();
425+
425426
TmpGitNamespace {
426427
name: n,
427428
repo_path: repo_path.to_owned(),

src/lib.rs

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -331,34 +331,42 @@ pub fn get_acl(
331331
let groups: Groups = serde_yaml::from_str(&groups)
332332
.map_err(|err| josh_error(format!("failed to parse groups file: {}", err).as_str()))?;
333333

334-
return users
335-
.get(user)
336-
.and_then(|u| {
337-
let mut whitelist = filter::empty();
338-
let mut blacklist = filter::empty();
339-
for g in &u.groups {
340-
let lists = groups.get(repo).and_then(|repo| {
341-
repo.get(g.as_str()?).and_then(|group| {
342-
let w = filter::parse(&group.whitelist);
343-
let b = filter::parse(&group.blacklist);
344-
Some((w, b))
345-
})
346-
})?;
347-
if let Err(e) = lists.0 {
348-
return Some(Err(JoshError(format!("Error parsing whitelist: {}", e))));
349-
}
350-
if let Err(e) = lists.1 {
351-
return Some(Err(JoshError(format!("Error parsing blacklist: {}", e))));
352-
}
353-
if let Ok(w) = lists.0 {
354-
whitelist = filter::compose(whitelist, w);
355-
}
356-
if let Ok(b) = lists.1 {
357-
blacklist = filter::compose(blacklist, b);
358-
}
334+
let res = users.get(user).and_then(|u| {
335+
let mut whitelist = filter::empty();
336+
let mut blacklist = filter::empty();
337+
for g in &u.groups {
338+
let lists = groups.get(repo).and_then(|repo| {
339+
repo.get(g.as_str()?).and_then(|group| {
340+
let w = filter::parse(&group.whitelist);
341+
let b = filter::parse(&group.blacklist);
342+
Some((w, b))
343+
})
344+
})?;
345+
if let Err(e) = lists.0 {
346+
return Some(Err(JoshError(format!("Error parsing whitelist: {}", e))));
347+
}
348+
if let Err(e) = lists.1 {
349+
return Some(Err(JoshError(format!("Error parsing blacklist: {}", e))));
350+
}
351+
if let Ok(w) = lists.0 {
352+
whitelist = filter::compose(whitelist, w);
359353
}
360-
println!("w: {:?}, b: {:?}", whitelist, blacklist);
361-
Some(Ok((whitelist, blacklist)))
362-
})
363-
.unwrap_or(Ok((filter::empty(), filter::nop())));
354+
if let Ok(b) = lists.1 {
355+
blacklist = filter::compose(blacklist, b);
356+
}
357+
}
358+
println!("w: {:?}, b: {:?}", whitelist, blacklist);
359+
Some(Ok((whitelist, blacklist)))
360+
});
361+
return match res {
362+
Some(Ok(res)) => Ok(res),
363+
Some(Err(e)) => {
364+
tracing::warn!("ACL error: {:?}", e);
365+
Ok((filter::empty(), filter::nop()))
366+
}
367+
None => {
368+
tracing::warn!("ACL: none");
369+
Ok((filter::empty(), filter::nop()))
370+
}
371+
};
364372
}

0 commit comments

Comments
 (0)