Skip to content

Commit 16cec04

Browse files
committed
Add permissions to proxy
1 parent f9a5826 commit 16cec04

File tree

6 files changed

+330
-33
lines changed

6 files changed

+330
-33
lines changed

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

Lines changed: 58 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,29 @@ 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+
{
307+
Ok(acl) => acl,
308+
Err(e) => {
309+
tracing::error!("Failed to read ACL file: {:?}", e);
310+
(josh::filter::empty(), josh::filter::nop())
311+
}
312+
};
313+
let whitelist = acl.0;
314+
let blacklist = acl.1;
315+
tracing::info!("Whitelist: {:?}, Blacklist: {:?}", whitelist, blacklist);
316+
josh::filter::make_permissions_filter(filter, whitelist, blacklist)
317+
} else {
318+
josh::filter::empty()
319+
};
320+
321+
tracing::info!("Permissions: {:?}", permissions_filter);
322+
323+
josh::filter_refs(&transaction, filter, &from_to,permissions_filter)?;
299324
if headref == "HEAD" {
300325
headref = heads_map
301326
.read()?
@@ -517,6 +542,7 @@ async fn call_service(
517542
&parsed_url.upstream_repo,
518543
&parsed_url.filter,
519544
&headref,
545+
&username,
520546
)
521547
.in_current_span()
522548
.await?;
@@ -598,6 +624,7 @@ async fn prepare_namespace(
598624
upstream_repo: &str,
599625
filter_spec: &str,
600626
headref: &str,
627+
user: &str,
601628
) -> josh::JoshResult<std::sync::Arc<josh_proxy::TmpGitNamespace>> {
602629
let temp_ns = Arc::new(josh_proxy::TmpGitNamespace::new(
603630
&serv.repo_path,
@@ -606,13 +633,16 @@ async fn prepare_namespace(
606633

607634
let serv = serv.clone();
608635

636+
let user = if user == "" { "anonymous"} else { user };
637+
609638
do_filter(
610639
serv.repo_path.clone(),
611640
serv.clone(),
612641
upstream_repo.to_owned(),
613642
temp_ns.to_owned(),
614643
filter_spec.to_owned(),
615644
headref.to_string(),
645+
user.to_string(),
616646
)
617647
.await?;
618648

@@ -635,6 +665,20 @@ async fn run_proxy() -> josh::JoshResult<i32> {
635665
josh_proxy::create_repo(&local)?;
636666
josh::cache::load(&local)?;
637667

668+
let acl = if ARGS.is_present("users") && ARGS.is_present("groups") {
669+
println!(
670+
"{}, {}",
671+
ARGS.value_of("users").unwrap().to_string(),
672+
ARGS.value_of("groups").unwrap().to_string()
673+
);
674+
Some((
675+
ARGS.value_of("users").unwrap().to_string(),
676+
ARGS.value_of("groups").unwrap().to_string(),
677+
))
678+
} else {
679+
None
680+
};
681+
638682
let proxy_service = Arc::new(JoshProxyService {
639683
port,
640684
repo_path: local.to_owned(),
@@ -646,6 +690,7 @@ async fn run_proxy() -> josh::JoshResult<i32> {
646690
ARGS.value_of("n").unwrap_or("1").parse()?,
647691
)),
648692
filter_permits: Arc::new(tokio::sync::Semaphore::new(10)),
693+
acl,
649694
});
650695

651696
let ps = proxy_service.clone();
@@ -800,6 +845,18 @@ fn parse_args() -> clap::ArgMatches<'static> {
800845
.help("Duration between forced cache refresh")
801846
.takes_value(true),
802847
)
848+
.arg(
849+
clap::Arg::with_name("users")
850+
.long("users")
851+
.takes_value(true)
852+
.help("YAML file listing the groups of the users"),
853+
)
854+
.arg(
855+
clap::Arg::with_name("groups")
856+
.long("groups")
857+
.takes_value(true)
858+
.help("YAML file listing the access rights of the groups"),
859+
)
803860
.get_matches_from(args)
804861
}
805862

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(),

run-josh.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
#!/bin/bash
2-
cd /josh/
3-
RUST_BACKTRACE=1 josh-proxy --gc --local=/data/git/ --remote="${JOSH_REMOTE}" ${JOSH_EXTRA_OPTS}
2+
RUST_BACKTRACE=1 /home/louismariegivel/Documents/code/josh/target/debug/josh-proxy --gc --local=/data/git/ --remote="${JOSH_REMOTE}" ${JOSH_EXTRA_OPTS}

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)