edenapi_server: use client identity middleware

Summary: Use the client identity middleware from gotham_ext in the EdenAPI server. This middleware parses validated client identities from HTTP headers inserted by Proxygen; these identities can then be used to enforce repo ACLs.

Reviewed By: HarveyHunt

Differential Revision: D20744887

fbshipit-source-id: 651e171d1b20448b3e99bfc938d118fb6dddea91
This commit is contained in:
Arun Kulshreshtha 2020-03-31 14:01:54 -07:00 committed by Facebook GitHub Bot
parent 063ce6dbe9
commit e236ef9df3
2 changed files with 41 additions and 5 deletions

View File

@ -8,6 +8,7 @@
#![deny(warnings)]
use std::net::SocketAddr;
use std::str::FromStr;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
@ -26,13 +27,17 @@ use openssl::ssl::SslAcceptor;
use slog::{error, info, warn, Logger};
use tokio::net::TcpListener;
use aclchecker::Identity;
use cmdlib::{
args,
helpers::serve_forever,
monitoring::{start_fb303_server, AliveService},
};
use fbinit::FacebookInit;
use gotham_ext::{handler::MononokeHttpHandler, middleware::ServerIdentityMiddleware};
use gotham_ext::{
handler::MononokeHttpHandler,
middleware::{ClientIdentityMiddleware, ServerIdentityMiddleware},
};
use mononoke_api::Mononoke;
use secure_utils::SslConfig;
@ -50,6 +55,7 @@ const ARG_TLS_CERTIFICATE: &str = "tls-certificate";
const ARG_TLS_PRIVATE_KEY: &str = "tls-private-key";
const ARG_TLS_CA: &str = "tls-ca";
const ARG_TLS_TICKET_SEEDS: &str = "tls-ticket-seeds";
const ARG_TRUSTED_PROXY_IDENTITY: &str = "trusted-proxy-identity";
const SERVICE_NAME: &str = "mononoke_edenapi_server";
@ -116,6 +122,14 @@ fn build_tls_acceptor(
Ok(builder.build())
}
/// Parse AclChecker identities passed in as arguments.
fn parse_identities(matches: &ArgMatches) -> Result<Vec<Identity>> {
match matches.values_of(ARG_TRUSTED_PROXY_IDENTITY) {
Some(values) => values.map(FromStr::from_str).collect(),
None => Ok(Vec::new()),
}
}
#[fbinit::main]
fn main(fb: FacebookInit) -> Result<()> {
let app = args::MononokeApp::new("EdenAPI Server")
@ -157,6 +171,15 @@ fn main(fb: FacebookInit) -> Result<()> {
Arg::with_name(ARG_TLS_TICKET_SEEDS)
.long("--tls-ticket-seeds")
.takes_value(true),
)
.arg(
Arg::with_name(ARG_TRUSTED_PROXY_IDENTITY)
.long(ARG_TRUSTED_PROXY_IDENTITY)
.takes_value(true)
.multiple(true)
.number_of_values(1)
.required(false)
.help("Proxy identity to trust"),
);
let matches = app.get_matches();
@ -165,6 +188,7 @@ fn main(fb: FacebookInit) -> Result<()> {
let mysql_options = args::parse_mysql_options(&matches);
let readonly_storage = args::parse_readonly_storage(&matches);
let blobstore_options = args::parse_blobstore_options(&matches);
let trusted_proxy_idents = parse_identities(&matches)?;
let caching = args::init_cachelib(fb, &matches, None);
let logger = args::init_logging(fb, &matches);
@ -198,6 +222,7 @@ fn main(fb: FacebookInit) -> Result<()> {
// middleware is set up during router setup in build_router.
let router = build_router(ctx);
let handler = MononokeHttpHandler::builder()
.add(ClientIdentityMiddleware::new(trusted_proxy_idents))
.add(ServerIdentityMiddleware::new(HeaderValue::from_static(
"edenapi_server",
)))

View File

@ -5,14 +5,15 @@
* GNU General Public License version 2.
*/
use gotham::state::{request_id, State};
use gotham::state::{request_id, FromState, State};
use gotham_derive::StateData;
use hyper::{Body, Response};
use slog::{o, Logger};
use context::{CoreContext, SessionContainer};
use fbinit::FacebookInit;
use gotham_ext::middleware::Middleware;
use gotham_ext::middleware::{ClientIdentity, Middleware};
use identity::{Identity, IdentitySet};
use scuba::ScubaSampleBuilder;
#[derive(StateData)]
@ -45,10 +46,13 @@ impl RequestContextMiddleware {
#[async_trait::async_trait]
impl Middleware for RequestContextMiddleware {
async fn inbound(&self, state: &mut State) -> Option<Response<Body>> {
let request_id = request_id(&state);
let identities = extract_identities(state);
let session = SessionContainer::builder(self.fb)
.identities(identities)
.build();
let request_id = request_id(&state);
let logger = self.logger.new(o!("request_id" => request_id.to_string()));
let session = SessionContainer::new_with_defaults(self.fb);
let ctx = session.new_context(logger, ScubaSampleBuilder::with_discard());
state.put(RequestContext::new(ctx));
@ -56,3 +60,10 @@ impl Middleware for RequestContextMiddleware {
None
}
}
fn extract_identities(state: &State) -> Option<IdentitySet> {
ClientIdentity::borrow_from(state)
.identities()
.clone()
.map(|ids: Vec<Identity>| ids.into_iter().collect())
}