Page MenuHomePhabricator

D8434.diff
No OneTemporary

D8434.diff

diff --git a/services/identity/Dockerfile b/services/identity/Dockerfile
--- a/services/identity/Dockerfile
+++ b/services/identity/Dockerfile
@@ -13,10 +13,16 @@
RUN mkdir -p /home/comm/app/identity
WORKDIR /home/comm/app/identity
+RUN cargo init --bin
+
+COPY services/identity/Cargo.toml services/identity/Cargo.lock ./
+COPY shared/ ../../shared/
+
+# Cache build dependencies in a new layer
+RUN cargo build --release
+RUN rm src/*.rs
COPY services/identity .
-COPY shared/protos/identity_client.proto ../../shared/protos/
-COPY shared/comm-opaque2 ../../shared/comm-opaque2
RUN cargo install --locked --path .
diff --git a/services/identity/build.rs b/services/identity/build.rs
--- a/services/identity/build.rs
+++ b/services/identity/build.rs
@@ -3,7 +3,10 @@
.build_server(true)
.build_client(false)
.compile(
- &["../../shared/protos/identity_client.proto"],
+ &[
+ "../../shared/protos/identity_client.proto",
+ "../../shared/protos/identity_authenticated.proto",
+ ],
&["../../shared/protos/"],
)?;
Ok(())
diff --git a/services/identity/src/grpc_services/authenticated.rs b/services/identity/src/grpc_services/authenticated.rs
new file mode 100644
--- /dev/null
+++ b/services/identity/src/grpc_services/authenticated.rs
@@ -0,0 +1,79 @@
+use crate::{client_service::handle_db_error, database::DatabaseClient};
+use tonic::{Request, Response, Status};
+
+// This must be named client, because generated code from the authenticated
+// protobuf file references message structs from the client protobuf file
+// with the client:: namespace
+pub mod client {
+ tonic::include_proto!("identity.client");
+}
+pub mod auth_proto {
+ tonic::include_proto!("identity.authenticated");
+}
+use auth_proto::{
+ identity_client_service_server::IdentityClientService,
+ RefreshUserPreKeysRequest,
+};
+use client::Empty;
+use tracing::debug;
+
+#[derive(derive_more::Constructor)]
+pub struct AuthenticatedService {
+ db_client: DatabaseClient,
+}
+
+fn get_value<T>(req: &Request<T>, key: &str) -> Option<String> {
+ let raw_value = req.metadata().get(key)?;
+ raw_value.to_str().ok().map(|s| s.to_string())
+}
+
+fn get_auth_info(req: &Request<()>) -> Option<(String, String, String)> {
+ debug!("Retrieving auth info for request: {:?}", req);
+
+ let user_id = get_value(req, "user_id")?;
+ let device_id = get_value(req, "device_id")?;
+ let access_token = get_value(req, "access_token")?;
+
+ Some((user_id, device_id, access_token))
+}
+
+pub fn auth_intercept(
+ req: Request<()>,
+ db_client: &DatabaseClient,
+) -> Result<Request<()>, Status> {
+ println!("Intercepting request: {:?}", req);
+
+ let (user_id, device_id, access_token) = get_auth_info(&req)
+ .ok_or(Status::unauthenticated("Missing credentials"))?;
+
+ let handle = tokio::runtime::Handle::current();
+ let new_db_client = db_client.clone();
+
+ // This function cannot be `async`, yet must call the async db call
+ // Force tokio to resolve future in current thread without an explicit .await
+ let valid_token = tokio::task::block_in_place(move || {
+ handle
+ .block_on(new_db_client.verify_access_token(
+ user_id,
+ device_id,
+ access_token,
+ ))
+ .map_err(handle_db_error)
+ })?;
+
+ if !valid_token {
+ return Err(Status::aborted("Bad Credentials"));
+ }
+
+ Ok(req)
+}
+
+#[tonic::async_trait]
+impl IdentityClientService for AuthenticatedService {
+ async fn refresh_user_pre_keys(
+ &self,
+ _request: Request<RefreshUserPreKeysRequest>,
+ ) -> Result<Response<Empty>, Status> {
+ unimplemented!();
+ }
+}
diff --git a/services/identity/src/grpc_services/mod.rs b/services/identity/src/grpc_services/mod.rs
new file mode 100644
--- /dev/null
+++ b/services/identity/src/grpc_services/mod.rs
@@ -0,0 +1 @@
+pub mod authenticated;
diff --git a/services/identity/src/main.rs b/services/identity/src/main.rs
--- a/services/identity/src/main.rs
+++ b/services/identity/src/main.rs
@@ -9,6 +9,7 @@
mod config;
pub mod constants;
mod database;
+mod grpc_services;
mod id;
mod keygen;
mod nonce;
@@ -23,6 +24,8 @@
use tracing_subscriber::EnvFilter;
use client_service::{ClientService, IdentityClientServiceServer};
+use grpc_services::authenticated::auth_proto::identity_client_service_server::IdentityClientServiceServer as AuthServer;
+use grpc_services::authenticated::AuthenticatedService;
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
@@ -70,12 +73,19 @@
.time_to_live(Duration::from_secs(10))
.build();
let client_service = IdentityClientServiceServer::new(
- ClientService::new(database_client, workflow_cache),
+ ClientService::new(database_client.clone(), workflow_cache),
);
+ let raw_auth_service = AuthenticatedService::new(database_client.clone());
+ let auth_service =
+ AuthServer::with_interceptor(raw_auth_service, move |mut req| {
+ grpc_services::authenticated::auth_intercept(req, &database_client)
+ });
+
info!("Listening to gRPC traffic on {}", addr);
Server::builder()
.accept_http1(true)
.add_service(tonic_web::enable(client_service))
+ .add_service(auth_service)
.serve(addr)
.await?;
}
diff --git a/shared/protos/identity_authenticated.proto b/shared/protos/identity_authenticated.proto
new file mode 100644
--- /dev/null
+++ b/shared/protos/identity_authenticated.proto
@@ -0,0 +1,27 @@
+syntax = "proto3";
+
+import "identity_client.proto";
+
+package identity.authenticated;
+
+// RPCs from a client (iOS, Android, or web) to identity service
+//
+// This service will assert authenticity of a device by verifying the access
+// token through an interceptor, thus avoiding the need to explicitly pass
+// the credentials on every request
+service IdentityClientService {
+
+ // Rotate a devices preKey and preKey signature
+ // Rotated for deniability of older messages
+ rpc RefreshUserPreKeys(RefreshUserPreKeysRequest)
+ returns (identity.client.Empty) {}
+}
+
+// Helper types
+
+// RefreshUserPreKeys
+
+message RefreshUserPreKeysRequest {
+ identity.client.PreKey newContentPreKeys = 1;
+ identity.client.PreKey newNotifPreKeys = 2;
+}

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 23, 3:22 AM (18 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2693348
Default Alt Text
D8434.diff (6 KB)

Event Timeline