Page MenuHomePhabricator

D7539.id25637.diff
No OneTemporary

D7539.id25637.diff

diff --git a/services/identity/src/client_service.rs b/services/identity/src/client_service.rs
--- a/services/identity/src/client_service.rs
+++ b/services/identity/src/client_service.rs
@@ -49,6 +49,7 @@
#[derive(Clone)]
pub struct UserLoginInfo {
+ pub user_id: String,
pub flattened_device_key_upload: FlattenedDeviceKeyUpload,
pub opaque_server_login: comm_opaque2::server::Login,
}
@@ -229,9 +230,9 @@
) -> Result<tonic::Response<OpaqueLoginStartResponse>, tonic::Status> {
let message = request.into_inner();
- let password_file_bytes = self
+ let (user_id, password_file_bytes) = self
.client
- .get_password_file_from_username(&message.username)
+ .get_user_id_and_password_file_from_username(&message.username)
.await
.map_err(handle_db_error)?
.ok_or(tonic::Status::not_found("user not found"))?;
@@ -275,6 +276,7 @@
let key_info = KeyPayload::from_str(&payload)
.map_err(|_| tonic::Status::invalid_argument("malformed payload"))?;
let login_state = UserLoginInfo {
+ user_id,
opaque_server_login: server_login,
flattened_device_key_upload: FlattenedDeviceKeyUpload {
device_id_key: key_info.primary_identity_public_keys.curve25519,
@@ -306,9 +308,50 @@
async fn login_password_user_finish(
&self,
- _request: tonic::Request<OpaqueLoginFinishRequest>,
+ request: tonic::Request<OpaqueLoginFinishRequest>,
) -> Result<tonic::Response<OpaqueLoginFinishResponse>, tonic::Status> {
- unimplemented!();
+ let message = request.into_inner();
+
+ if let Some(WorkflowInProgress::Login(state)) =
+ self.cache.get(&message.session_id)
+ {
+ self.cache.invalidate(&message.session_id).await;
+
+ let mut server_login = state.opaque_server_login.clone();
+ server_login
+ .finish(&message.opaque_login_upload)
+ .map_err(protocol_error_to_grpc_status)?;
+
+ self
+ .client
+ .add_device_to_users_table(state.clone())
+ .await
+ .map_err(handle_db_error)?;
+
+ // Create access token
+ let token = AccessTokenData::new(
+ message.session_id,
+ state.flattened_device_key_upload.device_id_key,
+ crate::token::AuthType::Password,
+ &mut OsRng,
+ );
+
+ let access_token = token.access_token.clone();
+
+ self
+ .client
+ .put_access_token_data(token)
+ .await
+ .map_err(handle_db_error)?;
+
+ let response = OpaqueLoginFinishResponse {
+ user_id: state.user_id,
+ access_token,
+ };
+ Ok(Response::new(response))
+ } else {
+ Err(tonic::Status::not_found("session not found"))
+ }
}
async fn login_wallet_user(
diff --git a/services/identity/src/database.rs b/services/identity/src/database.rs
--- a/services/identity/src/database.rs
+++ b/services/identity/src/database.rs
@@ -11,11 +11,11 @@
use aws_sdk_dynamodb::types::Blob;
use aws_sdk_dynamodb::{Client, Error as DynamoDBError};
use chrono::{DateTime, Utc};
-use opaque_ke::{errors::ProtocolError, ServerRegistration};
+use opaque_ke::errors::ProtocolError;
use serde::{Deserialize, Serialize};
use tracing::{debug, error, info, warn};
-use crate::client_service::UserRegistrationInfo;
+use crate::client_service::{UserLoginInfo, UserRegistrationInfo};
use crate::config::CONFIG;
use crate::constants::{
ACCESS_TOKEN_SORT_KEY, ACCESS_TOKEN_TABLE,
@@ -40,7 +40,6 @@
use crate::id::generate_uuid;
use crate::nonce::NonceData;
use crate::token::{AccessTokenData, AuthType};
-use comm_opaque::Cipher;
#[derive(Serialize, Deserialize)]
pub struct OlmKeys {
@@ -222,6 +221,109 @@
Ok(user_id)
}
+
+ pub async fn add_device_to_users_table(
+ &self,
+ login_state: UserLoginInfo,
+ ) -> Result<(), Error> {
+ let device_info = HashMap::from([
+ (
+ USERS_TABLE_DEVICES_MAP_DEVICE_TYPE_ATTRIBUTE_NAME.to_string(),
+ AttributeValue::S(Device::Client.to_string()),
+ ),
+ (
+ USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_ATTRIBUTE_NAME.to_string(),
+ AttributeValue::S(login_state.flattened_device_key_upload.key_payload),
+ ),
+ (
+ USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_SIGNATURE_ATTRIBUTE_NAME
+ .to_string(),
+ AttributeValue::S(
+ login_state
+ .flattened_device_key_upload
+ .key_payload_signature,
+ ),
+ ),
+ (
+ USERS_TABLE_DEVICES_MAP_IDENTITY_PREKEY_ATTRIBUTE_NAME.to_string(),
+ AttributeValue::S(
+ login_state.flattened_device_key_upload.identity_prekey,
+ ),
+ ),
+ (
+ USERS_TABLE_DEVICES_MAP_IDENTITY_PREKEY_SIGNATURE_ATTRIBUTE_NAME
+ .to_string(),
+ AttributeValue::S(
+ login_state
+ .flattened_device_key_upload
+ .identity_prekey_signature,
+ ),
+ ),
+ (
+ USERS_TABLE_DEVICES_MAP_IDENTITY_ONETIME_KEYS_ATTRIBUTE_NAME
+ .to_string(),
+ AttributeValue::L(
+ login_state
+ .flattened_device_key_upload
+ .identity_onetime_keys
+ .into_iter()
+ .map(AttributeValue::S)
+ .collect(),
+ ),
+ ),
+ (
+ USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME.to_string(),
+ AttributeValue::S(login_state.flattened_device_key_upload.notif_prekey),
+ ),
+ (
+ USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME
+ .to_string(),
+ AttributeValue::S(
+ login_state
+ .flattened_device_key_upload
+ .notif_prekey_signature,
+ ),
+ ),
+ (
+ USERS_TABLE_DEVICES_MAP_NOTIF_ONETIME_KEYS_ATTRIBUTE_NAME.to_string(),
+ AttributeValue::L(
+ login_state
+ .flattened_device_key_upload
+ .notif_onetime_keys
+ .into_iter()
+ .map(AttributeValue::S)
+ .collect(),
+ ),
+ ),
+ ]);
+
+ let update_expression =
+ format!("SET {}.#{} = :v", USERS_TABLE_DEVICES_ATTRIBUTE, "deviceID",);
+ let expression_attribute_names = HashMap::from([(
+ format!("#{}", "deviceID"),
+ login_state.flattened_device_key_upload.device_id_key,
+ )]);
+ let expression_attribute_values =
+ HashMap::from([(":v".to_string(), AttributeValue::M(device_info))]);
+
+ self
+ .client
+ .update_item()
+ .table_name(USERS_TABLE)
+ .key(
+ USERS_TABLE_PARTITION_KEY,
+ AttributeValue::S(login_state.user_id),
+ )
+ .update_expression(update_expression)
+ .set_expression_attribute_names(Some(expression_attribute_names))
+ .set_expression_attribute_values(Some(expression_attribute_values))
+ .send()
+ .await
+ .map_err(|e| Error::AwsSdk(e.into()))?;
+
+ Ok(())
+ }
+
pub async fn delete_user(
&self,
user_id: String,
@@ -444,19 +546,25 @@
}
}
- pub async fn get_password_file_from_username(
+ pub async fn get_user_id_and_password_file_from_username(
&self,
username: &str,
- ) -> Result<Option<Vec<u8>>, Error> {
+ ) -> Result<Option<(String, Vec<u8>)>, Error> {
match self
.get_user_from_user_info(username.to_string(), AuthType::Password)
.await
{
- Ok(Some(mut user)) => parse_registration_data_attribute(
- user.remove(USERS_TABLE_REGISTRATION_ATTRIBUTE),
- )
- .map(Some)
- .map_err(Error::Attribute),
+ Ok(Some(mut user)) => {
+ let user_id = parse_string_attribute(
+ USERS_TABLE_PARTITION_KEY,
+ user.remove(USERS_TABLE_PARTITION_KEY),
+ )?;
+ let password_file = parse_registration_data_attribute(
+ user.remove(USERS_TABLE_REGISTRATION_ATTRIBUTE),
+ )?;
+
+ Ok(Some((user_id, password_file)))
+ }
Ok(_) => {
info!(
"No item found for user {} in PAKE registration table",

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 28, 1:01 PM (6 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2720195
Default Alt Text
D7539.id25637.diff (7 KB)

Event Timeline