Repository: DefGuard/defguard (language: rust)

Issue:
Can't add SSH key if someone else has the key
Steps to reproduce:

1. Add key to user: admin & logout
2. Login as rolejnik
3. Add key -> rolejnik has no keys (and no knowledge if someone else added his key)
4. Adding the same key (but for different user): ERROR

Keys should be **uniqe per user not globaly**:



![Image](https://github.com/DefGuard/defguard/assets/139682/1b415f00-7e14-46ac-b419-8cf25337fd99)




Discussion / hints:

Fix patch:
diff --git a/.sqlx/query-59f427b570394e491e95d03c13802d5183039776c67cde0b72f464d159fbf14b.json b/.sqlx/query-d430472056fd352f9d43a3d9d259e00a74aacc38dfca073908281742a315cf06.json
similarity index 59%
rename from .sqlx/query-59f427b570394e491e95d03c13802d5183039776c67cde0b72f464d159fbf14b.json
rename to .sqlx/query-d430472056fd352f9d43a3d9d259e00a74aacc38dfca073908281742a315cf06.json
index 189968abe..4c3a5a0f0 100644
--- a/.sqlx/query-59f427b570394e491e95d03c13802d5183039776c67cde0b72f464d159fbf14b.json
+++ b/.sqlx/query-d430472056fd352f9d43a3d9d259e00a74aacc38dfca073908281742a315cf06.json
@@ -1,6 +1,6 @@
 {
   "db_name": "PostgreSQL",
-  "query": "SELECT COUNT(*) FROM \"authentication_key\" WHERE key = $1",
+  "query": "SELECT COUNT(1) FROM \"authentication_key\" WHERE user_id = $1 AND key = $2",
   "describe": {
     "columns": [
       {
@@ -11,6 +11,7 @@
     ],
     "parameters": {
       "Left": [
+        "Int8",
         "Text"
       ]
     },
@@ -18,5 +19,5 @@
       null
     ]
   },
-  "hash": "59f427b570394e491e95d03c13802d5183039776c67cde0b72f464d159fbf14b"
+  "hash": "d430472056fd352f9d43a3d9d259e00a74aacc38dfca073908281742a315cf06"
 }
diff --git a/migrations/20240318113507_auth_key_constraint.down.sql b/migrations/20240318113507_auth_key_constraint.down.sql
new file mode 100644
index 000000000..8965b0a1d
--- /dev/null
+++ b/migrations/20240318113507_auth_key_constraint.down.sql
@@ -0,0 +1,1 @@
+ALTER TABLE authentication_key DROP CONSTRAINT user_key_unique;
diff --git a/migrations/20240318113507_auth_key_constraint.up.sql b/migrations/20240318113507_auth_key_constraint.up.sql
new file mode 100644
index 000000000..5537d3254
--- /dev/null
+++ b/migrations/20240318113507_auth_key_constraint.up.sql
@@ -0,0 +1,2 @@
+ALTER TABLE authentication_key
+ADD CONSTRAINT user_key_unique UNIQUE (user_id, key_type, key);
diff --git a/src/handlers/ssh_authorized_keys.rs b/src/handlers/ssh_authorized_keys.rs
index 7f565d35a..d7fa09689 100644
--- a/src/handlers/ssh_authorized_keys.rs
+++ b/src/handlers/ssh_authorized_keys.rs
@@ -153,7 +153,7 @@ pub async fn get_authorized_keys(
     Ok(ssh_keys.join("\n"))
 }
 
-#[derive(Deserialize, Serialize)]
+#[derive(Deserialize, Serialize, Debug)]
 pub struct AddAuthenticationKeyData {
     key: String,
     name: String,
@@ -193,23 +193,29 @@ pub async fn add_authentication_key(
 
     // check if exists
     let exists_res = query!(
-        "SELECT COUNT(*) FROM \"authentication_key\" WHERE key = $1",
-        trimmed_key
+        "SELECT COUNT(1) FROM \"authentication_key\" WHERE user_id = $1 AND key = $2",
+        user_id,
+        trimmed_key,
     )
     .fetch_one(&appstate.pool)
     .await?;
-    if exists_res.count.is_some_and(|res| res > 0) {
+    if exists_res.count == Some(1) {
+        error!("User {username} tried to insert existing key: {data:?}");
         return Err(WebError::BadRequest("Key already exists.".into()));
     }
     let mut new_key = AuthenticationKey::new(
         user_id,
         trimmed_key.to_string(),
-        Some(data.name),
-        data.key_type,
+        Some(data.name.clone()),
+        data.key_type.clone(),
         None,
     );
     new_key.save(&appstate.pool).await?;
 
+    info!(
+        "Added new key \"{}\" of type {:?} for user {username}",
+        data.name, data.key_type
+    );
     Ok(ApiResponse {
         json: json!({}),
         status: StatusCode::CREATED,


Test patch: