Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3355668
D10438.id34959.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
4 KB
Referenced Files
None
Subscribers
None
D10438.id34959.diff
View Options
diff --git a/services/identity/src/constants.rs b/services/identity/src/constants.rs
--- a/services/identity/src/constants.rs
+++ b/services/identity/src/constants.rs
@@ -124,6 +124,10 @@
pub const NONCE_LENGTH: usize = 17;
pub const NONCE_TTL_DURATION: i64 = 30;
+// Identity
+
+pub const DEFAULT_IDENTITY_ENDPOINT: &str = "http://localhost:50054";
+
// LocalStack
pub const LOCALSTACK_ENDPOINT: &str = "LOCALSTACK_ENDPOINT";
diff --git a/services/identity/src/websockets/auth.rs b/services/identity/src/websockets/auth.rs
new file mode 100644
--- /dev/null
+++ b/services/identity/src/websockets/auth.rs
@@ -0,0 +1,70 @@
+use client_proto::VerifyUserAccessTokenRequest;
+use grpc_clients::identity;
+use grpc_clients::tonic::Request;
+use identity::get_unauthenticated_client;
+use identity::protos::unauthenticated as client_proto;
+use serde::{Deserialize, Serialize};
+use tracing::{debug, error};
+
+use crate::constants::DEFAULT_IDENTITY_ENDPOINT;
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(tag = "type", rename_all = "camelCase")]
+pub struct AuthMessage {
+ #[serde(rename = "userID")]
+ pub user_id: String,
+ #[serde(rename = "deviceID")]
+ pub device_id: String,
+ pub access_token: String,
+}
+
+const PLACEHOLDER_CODE_VERSION: u64 = 0;
+const DEVICE_TYPE: &str = "service";
+
+async fn verify_user_access_token(
+ user_id: &str,
+ device_id: &str,
+ access_token: &str,
+) -> Result<bool, String> {
+ let mut grpc_client = get_unauthenticated_client(
+ DEFAULT_IDENTITY_ENDPOINT,
+ PLACEHOLDER_CODE_VERSION,
+ DEVICE_TYPE.to_string(),
+ )
+ .await
+ .map_err(|e| format!("failed to get unauthenticated client: {}", e))?;
+ let message = VerifyUserAccessTokenRequest {
+ user_id: user_id.to_string(),
+ signing_public_key: device_id.to_string(),
+ access_token: access_token.to_string(),
+ };
+
+ let request = Request::new(message);
+ let response = grpc_client
+ .verify_user_access_token(request)
+ .await
+ .map_err(|e| format!("failed to verify user access token: {}", e))?;
+ Ok(response.into_inner().token_valid)
+}
+
+pub async fn handle_auth_message(message: &str) -> Result<(), String> {
+ error!("Handling auth message: {}", message);
+ let auth_message: AuthMessage = serde_json::from_str(message.trim())
+ .map_err(|e| format!("failed to parse auth message: {}", e))?;
+
+ let user_id = auth_message.user_id;
+ let device_id = auth_message.device_id;
+ let access_token = auth_message.access_token;
+
+ let is_valid_token =
+ verify_user_access_token(&user_id, &device_id, &access_token).await?;
+
+ if is_valid_token {
+ debug!("User {} authenticated", user_id);
+ } else {
+ debug!("User {} not authenticated", user_id);
+ return Err("invalid authentication token".into());
+ }
+
+ Ok(())
+}
diff --git a/services/identity/src/websockets/mod.rs b/services/identity/src/websockets/mod.rs
--- a/services/identity/src/websockets/mod.rs
+++ b/services/identity/src/websockets/mod.rs
@@ -11,6 +11,8 @@
use tokio::net::TcpListener;
use tracing::{debug, error, info};
+mod auth;
+
use crate::config::CONFIG;
use crate::constants::IDENTITY_SERVICE_WEBSOCKET_ADDR;
@@ -151,6 +153,35 @@
let opensearch_url =
format!("https://{}/users/_search/", &CONFIG.opensearch_endpoint);
+ if let Some(Ok(auth_message)) = incoming.next().await {
+ match auth_message {
+ Message::Text(text) => {
+ if let Err(auth_error) = auth::handle_auth_message(&text).await {
+ let error_msg = serde_json::json!({
+ "action": "errorMessage",
+ "error": auth_error.to_string()
+ });
+
+ if let Err(send_error) = outgoing
+ .send(Message::Text(format!("{}", error_msg.to_string())))
+ .await
+ {
+ error!("Error sending auth error response: {}", send_error);
+ }
+
+ return;
+ }
+ }
+ _ => {
+ error!("Invalid authentication message from {}", addr);
+ return;
+ }
+ }
+ } else {
+ error!("No authentication message from {}", addr);
+ return;
+ }
+
while let Some(message) = incoming.next().await {
match message {
Ok(Message::Close(_)) => {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 24, 2:57 PM (21 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2576481
Default Alt Text
D10438.id34959.diff (4 KB)
Attached To
Mode
D10438: [services] [6/n] authentication for search websocket server
Attached
Detach File
Event Timeline
Log In to Comment