diff --git a/.sqlx/query-c6ebb402f91d242754872addc3604fb6ffac7e6fdd0d9428070cecb68c666cd8.json b/.sqlx/query-1332e9c8c375774902845e5bebddd49aadbd2516b1ff4fb962d1fc2437401064.json similarity index 58% rename from .sqlx/query-c6ebb402f91d242754872addc3604fb6ffac7e6fdd0d9428070cecb68c666cd8.json rename to .sqlx/query-1332e9c8c375774902845e5bebddd49aadbd2516b1ff4fb962d1fc2437401064.json index 7994ebf797..0cd4df0c7e 100644 --- a/.sqlx/query-c6ebb402f91d242754872addc3604fb6ffac7e6fdd0d9428070cecb68c666cd8.json +++ b/.sqlx/query-1332e9c8c375774902845e5bebddd49aadbd2516b1ff4fb962d1fc2437401064.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO \"openidprovider\" (\"name\",\"base_url\",\"client_id\",\"client_secret\",\"display_name\",\"google_service_account_key\",\"google_service_account_email\",\"admin_email\",\"directory_sync_enabled\",\"directory_sync_interval\",\"directory_sync_user_behavior\",\"directory_sync_admin_behavior\",\"directory_sync_target\",\"okta_private_jwk\",\"okta_dirsync_client_id\",\"directory_sync_group_match\",\"jumpcloud_api_key\",\"prefetch_users\") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18) RETURNING id", + "query": "INSERT INTO \"openidprovider\" (\"name\",\"base_url\",\"kind\",\"client_id\",\"client_secret\",\"display_name\",\"google_service_account_key\",\"google_service_account_email\",\"admin_email\",\"directory_sync_enabled\",\"directory_sync_interval\",\"directory_sync_user_behavior\",\"directory_sync_admin_behavior\",\"directory_sync_target\",\"okta_private_jwk\",\"okta_dirsync_client_id\",\"directory_sync_group_match\",\"jumpcloud_api_key\",\"prefetch_users\") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19) RETURNING id", "describe": { "columns": [ { @@ -13,6 +13,21 @@ "Left": [ "Text", "Text", + { + "Custom": { + "name": "openid_provider_kind", + "kind": { + "Enum": [ + "Custom", + "Google", + "Microsoft", + "Okta", + "JumpCloud", + "Zitadel" + ] + } + } + }, "Text", "Text", "Text", @@ -68,5 +83,5 @@ false ] }, - "hash": "c6ebb402f91d242754872addc3604fb6ffac7e6fdd0d9428070cecb68c666cd8" + "hash": "1332e9c8c375774902845e5bebddd49aadbd2516b1ff4fb962d1fc2437401064" } diff --git a/.sqlx/query-796ef2b0b73f5689a592497320b98ddb54a2a673a531cb882aadea3d5aa25d66.json b/.sqlx/query-20cd8429969e36695d67c52d7c27e824bbcf5ba0c8198c55bc610186f6dc3779.json similarity index 57% rename from .sqlx/query-796ef2b0b73f5689a592497320b98ddb54a2a673a531cb882aadea3d5aa25d66.json rename to .sqlx/query-20cd8429969e36695d67c52d7c27e824bbcf5ba0c8198c55bc610186f6dc3779.json index 528c633238..9232c0709f 100644 --- a/.sqlx/query-796ef2b0b73f5689a592497320b98ddb54a2a673a531cb882aadea3d5aa25d66.json +++ b/.sqlx/query-20cd8429969e36695d67c52d7c27e824bbcf5ba0c8198c55bc610186f6dc3779.json @@ -1,12 +1,27 @@ { "db_name": "PostgreSQL", - "query": "UPDATE openidprovider SET name = $1, base_url = $2, client_id = $3, client_secret = $4, display_name = $5, google_service_account_key = $6, google_service_account_email = $7, admin_email = $8, directory_sync_enabled = $9, directory_sync_interval = $10, directory_sync_user_behavior = $11, directory_sync_admin_behavior = $12, directory_sync_target = $13, okta_private_jwk = $14, okta_dirsync_client_id = $15, directory_sync_group_match = $16, jumpcloud_api_key = $17, prefetch_users = $18 WHERE id = $19", + "query": "UPDATE openidprovider SET name = $1, base_url = $2, kind = $3, client_id = $4, client_secret = $5, display_name = $6, google_service_account_key = $7, google_service_account_email = $8, admin_email = $9, directory_sync_enabled = $10, directory_sync_interval = $11, directory_sync_user_behavior = $12, directory_sync_admin_behavior = $13, directory_sync_target = $14, okta_private_jwk = $15, okta_dirsync_client_id = $16, directory_sync_group_match = $17, jumpcloud_api_key = $18, prefetch_users = $19 WHERE id = $20", "describe": { "columns": [], "parameters": { "Left": [ "Text", "Text", + { + "Custom": { + "name": "openid_provider_kind", + "kind": { + "Enum": [ + "Custom", + "Google", + "Microsoft", + "Okta", + "JumpCloud", + "Zitadel" + ] + } + } + }, "Text", "Text", "Text", @@ -61,5 +76,5 @@ }, "nullable": [] }, - "hash": "796ef2b0b73f5689a592497320b98ddb54a2a673a531cb882aadea3d5aa25d66" + "hash": "20cd8429969e36695d67c52d7c27e824bbcf5ba0c8198c55bc610186f6dc3779" } diff --git a/.sqlx/query-217e11c616a96fdd002fbf31bb0a37735aec6f1bac187cc4a331207154996346.json b/.sqlx/query-23d55f2b3d7f82c0bb6afdd4e88e64b9920b263b3d668704ecbe66d80aa7c586.json similarity index 97% rename from .sqlx/query-217e11c616a96fdd002fbf31bb0a37735aec6f1bac187cc4a331207154996346.json rename to .sqlx/query-23d55f2b3d7f82c0bb6afdd4e88e64b9920b263b3d668704ecbe66d80aa7c586.json index f52051d44e..b6b62477c9 100644 --- a/.sqlx/query-217e11c616a96fdd002fbf31bb0a37735aec6f1bac187cc4a331207154996346.json +++ b/.sqlx/query-23d55f2b3d7f82c0bb6afdd4e88e64b9920b263b3d668704ecbe66d80aa7c586.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT openid_enabled, wireguard_enabled, webhooks_enabled, worker_enabled, challenge_template, instance_name, main_logo_url, nav_logo_url, smtp_server, smtp_port, smtp_encryption \"smtp_encryption: _\", smtp_user, smtp_password \"smtp_password?: SecretStringWrapper\", smtp_sender, enrollment_vpn_step_optional, enrollment_welcome_message, enrollment_welcome_email, enrollment_welcome_email_subject, enrollment_use_welcome_message_as_email, uuid, ldap_url, ldap_bind_username, ldap_bind_password \"ldap_bind_password?: SecretStringWrapper\", ldap_group_search_base, ldap_user_search_base, ldap_user_obj_class, ldap_group_obj_class, ldap_username_attr, ldap_groupname_attr, ldap_group_member_attr, ldap_member_attr, openid_create_account, license, gateway_disconnect_notifications_enabled, ldap_use_starttls, ldap_tls_verify_cert, gateway_disconnect_notifications_inactivity_threshold, gateway_disconnect_notifications_reconnect_notification_enabled, ldap_sync_status \"ldap_sync_status: LdapSyncStatus\", ldap_enabled, ldap_sync_enabled, ldap_is_authoritative, ldap_sync_interval, ldap_user_auxiliary_obj_classes, ldap_uses_ad, ldap_user_rdn_attr, ldap_sync_groups, openid_username_handling \"openid_username_handling: OpenidUsernameHandling\", ca_key_der, ca_cert_der FROM \"settings\" WHERE id = 1", + "query": "SELECT openid_enabled, wireguard_enabled, webhooks_enabled, worker_enabled, challenge_template, instance_name, main_logo_url, nav_logo_url, smtp_server, smtp_port, smtp_encryption \"smtp_encryption: _\", smtp_user, smtp_password \"smtp_password?: SecretStringWrapper\", smtp_sender, enrollment_vpn_step_optional, enrollment_welcome_message, enrollment_welcome_email, enrollment_welcome_email_subject, enrollment_use_welcome_message_as_email, uuid, ldap_url, ldap_bind_username, ldap_bind_password \"ldap_bind_password?: SecretStringWrapper\", ldap_group_search_base, ldap_user_search_base, ldap_user_obj_class, ldap_group_obj_class, ldap_username_attr, ldap_groupname_attr, ldap_group_member_attr, ldap_member_attr, openid_create_account, license, gateway_disconnect_notifications_enabled, ldap_use_starttls, ldap_tls_verify_cert, gateway_disconnect_notifications_inactivity_threshold, gateway_disconnect_notifications_reconnect_notification_enabled, ldap_sync_status \"ldap_sync_status: LdapSyncStatus\", ldap_enabled, ldap_sync_enabled, ldap_is_authoritative, ldap_sync_interval, ldap_user_auxiliary_obj_classes, ldap_uses_ad, ldap_user_rdn_attr, ldap_sync_groups, openid_username_handling \"openid_username_handling: OpenIdUsernameHandling\", ca_key_der, ca_cert_der FROM \"settings\" WHERE id = 1", "describe": { "columns": [ { @@ -261,7 +261,7 @@ }, { "ordinal": 47, - "name": "openid_username_handling: OpenidUsernameHandling", + "name": "openid_username_handling: OpenIdUsernameHandling", "type_info": { "Custom": { "name": "openid_username_handling", @@ -342,5 +342,5 @@ true ] }, - "hash": "217e11c616a96fdd002fbf31bb0a37735aec6f1bac187cc4a331207154996346" + "hash": "23d55f2b3d7f82c0bb6afdd4e88e64b9920b263b3d668704ecbe66d80aa7c586" } diff --git a/.sqlx/query-558fb8aa5e223f6fc273c1431410dabb2ca9c2a831cacb7ebc8d696020b0556c.json b/.sqlx/query-4c259991024808243d03443cb8725da87df96619428383083bded91c2dfdf598.json similarity index 73% rename from .sqlx/query-558fb8aa5e223f6fc273c1431410dabb2ca9c2a831cacb7ebc8d696020b0556c.json rename to .sqlx/query-4c259991024808243d03443cb8725da87df96619428383083bded91c2dfdf598.json index bfd59988cf..fb787d4617 100644 --- a/.sqlx/query-558fb8aa5e223f6fc273c1431410dabb2ca9c2a831cacb7ebc8d696020b0556c.json +++ b/.sqlx/query-4c259991024808243d03443cb8725da87df96619428383083bded91c2dfdf598.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, name, base_url, client_id, client_secret, display_name, google_service_account_key, google_service_account_email, admin_email, directory_sync_enabled,\n directory_sync_interval, directory_sync_user_behavior \"directory_sync_user_behavior: DirectorySyncUserBehavior\", directory_sync_admin_behavior \"directory_sync_admin_behavior: DirectorySyncUserBehavior\", directory_sync_target \"directory_sync_target: DirectorySyncTarget\", okta_private_jwk, okta_dirsync_client_id, directory_sync_group_match, jumpcloud_api_key, prefetch_users FROM openidprovider WHERE name = $1", + "query": "SELECT id, name, base_url, kind \"kind: OpenIdProviderKind\", client_id, client_secret, display_name, google_service_account_key, google_service_account_email, admin_email, directory_sync_enabled,\n directory_sync_interval, directory_sync_user_behavior \"directory_sync_user_behavior: DirectorySyncUserBehavior\", directory_sync_admin_behavior \"directory_sync_admin_behavior: DirectorySyncUserBehavior\", directory_sync_target \"directory_sync_target: DirectorySyncTarget\", okta_private_jwk, okta_dirsync_client_id, directory_sync_group_match, jumpcloud_api_key, prefetch_users FROM openidprovider WHERE name = $1", "describe": { "columns": [ { @@ -20,46 +20,65 @@ }, { "ordinal": 3, + "name": "kind: OpenIdProviderKind", + "type_info": { + "Custom": { + "name": "openid_provider_kind", + "kind": { + "Enum": [ + "Custom", + "Google", + "Microsoft", + "Okta", + "JumpCloud", + "Zitadel" + ] + } + } + } + }, + { + "ordinal": 4, "name": "client_id", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 5, "name": "client_secret", "type_info": "Text" }, { - "ordinal": 5, + "ordinal": 6, "name": "display_name", "type_info": "Text" }, { - "ordinal": 6, + "ordinal": 7, "name": "google_service_account_key", "type_info": "Text" }, { - "ordinal": 7, + "ordinal": 8, "name": "google_service_account_email", "type_info": "Text" }, { - "ordinal": 8, + "ordinal": 9, "name": "admin_email", "type_info": "Text" }, { - "ordinal": 9, + "ordinal": 10, "name": "directory_sync_enabled", "type_info": "Bool" }, { - "ordinal": 10, + "ordinal": 11, "name": "directory_sync_interval", "type_info": "Int4" }, { - "ordinal": 11, + "ordinal": 12, "name": "directory_sync_user_behavior: DirectorySyncUserBehavior", "type_info": { "Custom": { @@ -75,7 +94,7 @@ } }, { - "ordinal": 12, + "ordinal": 13, "name": "directory_sync_admin_behavior: DirectorySyncUserBehavior", "type_info": { "Custom": { @@ -91,7 +110,7 @@ } }, { - "ordinal": 13, + "ordinal": 14, "name": "directory_sync_target: DirectorySyncTarget", "type_info": { "Custom": { @@ -107,27 +126,27 @@ } }, { - "ordinal": 14, + "ordinal": 15, "name": "okta_private_jwk", "type_info": "Text" }, { - "ordinal": 15, + "ordinal": 16, "name": "okta_dirsync_client_id", "type_info": "Text" }, { - "ordinal": 16, + "ordinal": 17, "name": "directory_sync_group_match", "type_info": "TextArray" }, { - "ordinal": 17, + "ordinal": 18, "name": "jumpcloud_api_key", "type_info": "Text" }, { - "ordinal": 18, + "ordinal": 19, "name": "prefetch_users", "type_info": "Bool" } @@ -143,6 +162,7 @@ false, false, false, + false, true, true, true, @@ -159,5 +179,5 @@ false ] }, - "hash": "558fb8aa5e223f6fc273c1431410dabb2ca9c2a831cacb7ebc8d696020b0556c" + "hash": "4c259991024808243d03443cb8725da87df96619428383083bded91c2dfdf598" } diff --git a/.sqlx/query-14302b1c6c7d72d6e6f38c80538040b9fa3479c919f1ace2a787470690be9de3.json b/.sqlx/query-7642a85c7e4a299c2ae6b7deba3642ab7efcb9a7375d01ce85078389edf1340b.json similarity index 73% rename from .sqlx/query-14302b1c6c7d72d6e6f38c80538040b9fa3479c919f1ace2a787470690be9de3.json rename to .sqlx/query-7642a85c7e4a299c2ae6b7deba3642ab7efcb9a7375d01ce85078389edf1340b.json index 8ba998d2cb..075f8cf098 100644 --- a/.sqlx/query-14302b1c6c7d72d6e6f38c80538040b9fa3479c919f1ace2a787470690be9de3.json +++ b/.sqlx/query-7642a85c7e4a299c2ae6b7deba3642ab7efcb9a7375d01ce85078389edf1340b.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, \"name\",\"base_url\",\"client_id\",\"client_secret\",\"display_name\",\"google_service_account_key\",\"google_service_account_email\",\"admin_email\",\"directory_sync_enabled\",\"directory_sync_interval\",\"directory_sync_user_behavior\" \"directory_sync_user_behavior: _\",\"directory_sync_admin_behavior\" \"directory_sync_admin_behavior: _\",\"directory_sync_target\" \"directory_sync_target: _\",\"okta_private_jwk\",\"okta_dirsync_client_id\",\"directory_sync_group_match\" \"directory_sync_group_match: _\",\"jumpcloud_api_key\",\"prefetch_users\" FROM \"openidprovider\" WHERE id = $1", + "query": "SELECT id, \"name\",\"base_url\",\"kind\" \"kind: _\",\"client_id\",\"client_secret\",\"display_name\",\"google_service_account_key\",\"google_service_account_email\",\"admin_email\",\"directory_sync_enabled\",\"directory_sync_interval\",\"directory_sync_user_behavior\" \"directory_sync_user_behavior: _\",\"directory_sync_admin_behavior\" \"directory_sync_admin_behavior: _\",\"directory_sync_target\" \"directory_sync_target: _\",\"okta_private_jwk\",\"okta_dirsync_client_id\",\"directory_sync_group_match\" \"directory_sync_group_match: _\",\"jumpcloud_api_key\",\"prefetch_users\" FROM \"openidprovider\" WHERE id = $1", "describe": { "columns": [ { @@ -20,46 +20,65 @@ }, { "ordinal": 3, + "name": "kind: _", + "type_info": { + "Custom": { + "name": "openid_provider_kind", + "kind": { + "Enum": [ + "Custom", + "Google", + "Microsoft", + "Okta", + "JumpCloud", + "Zitadel" + ] + } + } + } + }, + { + "ordinal": 4, "name": "client_id", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 5, "name": "client_secret", "type_info": "Text" }, { - "ordinal": 5, + "ordinal": 6, "name": "display_name", "type_info": "Text" }, { - "ordinal": 6, + "ordinal": 7, "name": "google_service_account_key", "type_info": "Text" }, { - "ordinal": 7, + "ordinal": 8, "name": "google_service_account_email", "type_info": "Text" }, { - "ordinal": 8, + "ordinal": 9, "name": "admin_email", "type_info": "Text" }, { - "ordinal": 9, + "ordinal": 10, "name": "directory_sync_enabled", "type_info": "Bool" }, { - "ordinal": 10, + "ordinal": 11, "name": "directory_sync_interval", "type_info": "Int4" }, { - "ordinal": 11, + "ordinal": 12, "name": "directory_sync_user_behavior: _", "type_info": { "Custom": { @@ -75,7 +94,7 @@ } }, { - "ordinal": 12, + "ordinal": 13, "name": "directory_sync_admin_behavior: _", "type_info": { "Custom": { @@ -91,7 +110,7 @@ } }, { - "ordinal": 13, + "ordinal": 14, "name": "directory_sync_target: _", "type_info": { "Custom": { @@ -107,27 +126,27 @@ } }, { - "ordinal": 14, + "ordinal": 15, "name": "okta_private_jwk", "type_info": "Text" }, { - "ordinal": 15, + "ordinal": 16, "name": "okta_dirsync_client_id", "type_info": "Text" }, { - "ordinal": 16, + "ordinal": 17, "name": "directory_sync_group_match: _", "type_info": "TextArray" }, { - "ordinal": 17, + "ordinal": 18, "name": "jumpcloud_api_key", "type_info": "Text" }, { - "ordinal": 18, + "ordinal": 19, "name": "prefetch_users", "type_info": "Bool" } @@ -143,6 +162,7 @@ false, false, false, + false, true, true, true, @@ -159,5 +179,5 @@ false ] }, - "hash": "14302b1c6c7d72d6e6f38c80538040b9fa3479c919f1ace2a787470690be9de3" + "hash": "7642a85c7e4a299c2ae6b7deba3642ab7efcb9a7375d01ce85078389edf1340b" } diff --git a/.sqlx/query-e28b02ccc616d67fcb1a1aa940ea35be58cb652e8287a6f5028421656048b58a.json b/.sqlx/query-bbff781ddf881678e2d24bf292a2b1506bf33b00c4ef21c0761d6c3a4f6be964.json similarity index 73% rename from .sqlx/query-e28b02ccc616d67fcb1a1aa940ea35be58cb652e8287a6f5028421656048b58a.json rename to .sqlx/query-bbff781ddf881678e2d24bf292a2b1506bf33b00c4ef21c0761d6c3a4f6be964.json index f59dbf3807..351367d6ff 100644 --- a/.sqlx/query-e28b02ccc616d67fcb1a1aa940ea35be58cb652e8287a6f5028421656048b58a.json +++ b/.sqlx/query-bbff781ddf881678e2d24bf292a2b1506bf33b00c4ef21c0761d6c3a4f6be964.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, name, base_url, client_id, client_secret, display_name, google_service_account_key, google_service_account_email, admin_email, directory_sync_enabled, directory_sync_interval, directory_sync_user_behavior \"directory_sync_user_behavior: DirectorySyncUserBehavior\", directory_sync_admin_behavior \"directory_sync_admin_behavior: DirectorySyncUserBehavior\", directory_sync_target \"directory_sync_target: DirectorySyncTarget\", okta_private_jwk, okta_dirsync_client_id, directory_sync_group_match, jumpcloud_api_key, prefetch_users FROM openidprovider LIMIT 1", + "query": "SELECT id, name, base_url, kind \"kind: OpenIdProviderKind\", client_id, client_secret, display_name, google_service_account_key, google_service_account_email, admin_email, directory_sync_enabled, directory_sync_interval, directory_sync_user_behavior \"directory_sync_user_behavior: DirectorySyncUserBehavior\", directory_sync_admin_behavior \"directory_sync_admin_behavior: DirectorySyncUserBehavior\", directory_sync_target \"directory_sync_target: DirectorySyncTarget\", okta_private_jwk, okta_dirsync_client_id, directory_sync_group_match, jumpcloud_api_key, prefetch_users FROM openidprovider LIMIT 1", "describe": { "columns": [ { @@ -20,46 +20,65 @@ }, { "ordinal": 3, + "name": "kind: OpenIdProviderKind", + "type_info": { + "Custom": { + "name": "openid_provider_kind", + "kind": { + "Enum": [ + "Custom", + "Google", + "Microsoft", + "Okta", + "JumpCloud", + "Zitadel" + ] + } + } + } + }, + { + "ordinal": 4, "name": "client_id", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 5, "name": "client_secret", "type_info": "Text" }, { - "ordinal": 5, + "ordinal": 6, "name": "display_name", "type_info": "Text" }, { - "ordinal": 6, + "ordinal": 7, "name": "google_service_account_key", "type_info": "Text" }, { - "ordinal": 7, + "ordinal": 8, "name": "google_service_account_email", "type_info": "Text" }, { - "ordinal": 8, + "ordinal": 9, "name": "admin_email", "type_info": "Text" }, { - "ordinal": 9, + "ordinal": 10, "name": "directory_sync_enabled", "type_info": "Bool" }, { - "ordinal": 10, + "ordinal": 11, "name": "directory_sync_interval", "type_info": "Int4" }, { - "ordinal": 11, + "ordinal": 12, "name": "directory_sync_user_behavior: DirectorySyncUserBehavior", "type_info": { "Custom": { @@ -75,7 +94,7 @@ } }, { - "ordinal": 12, + "ordinal": 13, "name": "directory_sync_admin_behavior: DirectorySyncUserBehavior", "type_info": { "Custom": { @@ -91,7 +110,7 @@ } }, { - "ordinal": 13, + "ordinal": 14, "name": "directory_sync_target: DirectorySyncTarget", "type_info": { "Custom": { @@ -107,27 +126,27 @@ } }, { - "ordinal": 14, + "ordinal": 15, "name": "okta_private_jwk", "type_info": "Text" }, { - "ordinal": 15, + "ordinal": 16, "name": "okta_dirsync_client_id", "type_info": "Text" }, { - "ordinal": 16, + "ordinal": 17, "name": "directory_sync_group_match", "type_info": "TextArray" }, { - "ordinal": 17, + "ordinal": 18, "name": "jumpcloud_api_key", "type_info": "Text" }, { - "ordinal": 18, + "ordinal": 19, "name": "prefetch_users", "type_info": "Bool" } @@ -141,6 +160,7 @@ false, false, false, + false, true, true, true, @@ -157,5 +177,5 @@ false ] }, - "hash": "e28b02ccc616d67fcb1a1aa940ea35be58cb652e8287a6f5028421656048b58a" + "hash": "bbff781ddf881678e2d24bf292a2b1506bf33b00c4ef21c0761d6c3a4f6be964" } diff --git a/.sqlx/query-c8e9800861c7bc853235858650be8ad3d3d19b0c4f0e69b9002a6a1fbd46a324.json b/.sqlx/query-f6110462d7fd58131e1a2d8cb52711ed9e490ab111a2c0cbb499587f351697b8.json similarity index 56% rename from .sqlx/query-c8e9800861c7bc853235858650be8ad3d3d19b0c4f0e69b9002a6a1fbd46a324.json rename to .sqlx/query-f6110462d7fd58131e1a2d8cb52711ed9e490ab111a2c0cbb499587f351697b8.json index 5c80f34900..789a2f2782 100644 --- a/.sqlx/query-c8e9800861c7bc853235858650be8ad3d3d19b0c4f0e69b9002a6a1fbd46a324.json +++ b/.sqlx/query-f6110462d7fd58131e1a2d8cb52711ed9e490ab111a2c0cbb499587f351697b8.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE \"openidprovider\" SET \"name\" = $2,\"base_url\" = $3,\"client_id\" = $4,\"client_secret\" = $5,\"display_name\" = $6,\"google_service_account_key\" = $7,\"google_service_account_email\" = $8,\"admin_email\" = $9,\"directory_sync_enabled\" = $10,\"directory_sync_interval\" = $11,\"directory_sync_user_behavior\" = $12,\"directory_sync_admin_behavior\" = $13,\"directory_sync_target\" = $14,\"okta_private_jwk\" = $15,\"okta_dirsync_client_id\" = $16,\"directory_sync_group_match\" = $17,\"jumpcloud_api_key\" = $18,\"prefetch_users\" = $19 WHERE id = $1", + "query": "UPDATE \"openidprovider\" SET \"name\" = $2,\"base_url\" = $3,\"kind\" = $4,\"client_id\" = $5,\"client_secret\" = $6,\"display_name\" = $7,\"google_service_account_key\" = $8,\"google_service_account_email\" = $9,\"admin_email\" = $10,\"directory_sync_enabled\" = $11,\"directory_sync_interval\" = $12,\"directory_sync_user_behavior\" = $13,\"directory_sync_admin_behavior\" = $14,\"directory_sync_target\" = $15,\"okta_private_jwk\" = $16,\"okta_dirsync_client_id\" = $17,\"directory_sync_group_match\" = $18,\"jumpcloud_api_key\" = $19,\"prefetch_users\" = $20 WHERE id = $1", "describe": { "columns": [], "parameters": { @@ -8,6 +8,21 @@ "Int8", "Text", "Text", + { + "Custom": { + "name": "openid_provider_kind", + "kind": { + "Enum": [ + "Custom", + "Google", + "Microsoft", + "Okta", + "JumpCloud", + "Zitadel" + ] + } + } + }, "Text", "Text", "Text", @@ -61,5 +76,5 @@ }, "nullable": [] }, - "hash": "c8e9800861c7bc853235858650be8ad3d3d19b0c4f0e69b9002a6a1fbd46a324" + "hash": "f6110462d7fd58131e1a2d8cb52711ed9e490ab111a2c0cbb499587f351697b8" } diff --git a/.sqlx/query-d8db674150231de0063227000a8b39f45c6da9836f93b67307787851a1804f13.json b/.sqlx/query-f851e3667522ee439c614f66e13d89773b783a1b738c453791c45747b11aa106.json similarity index 73% rename from .sqlx/query-d8db674150231de0063227000a8b39f45c6da9836f93b67307787851a1804f13.json rename to .sqlx/query-f851e3667522ee439c614f66e13d89773b783a1b738c453791c45747b11aa106.json index 29d36e4226..088bb362dc 100644 --- a/.sqlx/query-d8db674150231de0063227000a8b39f45c6da9836f93b67307787851a1804f13.json +++ b/.sqlx/query-f851e3667522ee439c614f66e13d89773b783a1b738c453791c45747b11aa106.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, \"name\",\"base_url\",\"client_id\",\"client_secret\",\"display_name\",\"google_service_account_key\",\"google_service_account_email\",\"admin_email\",\"directory_sync_enabled\",\"directory_sync_interval\",\"directory_sync_user_behavior\" \"directory_sync_user_behavior: _\",\"directory_sync_admin_behavior\" \"directory_sync_admin_behavior: _\",\"directory_sync_target\" \"directory_sync_target: _\",\"okta_private_jwk\",\"okta_dirsync_client_id\",\"directory_sync_group_match\" \"directory_sync_group_match: _\",\"jumpcloud_api_key\",\"prefetch_users\" FROM \"openidprovider\"", + "query": "SELECT id, \"name\",\"base_url\",\"kind\" \"kind: _\",\"client_id\",\"client_secret\",\"display_name\",\"google_service_account_key\",\"google_service_account_email\",\"admin_email\",\"directory_sync_enabled\",\"directory_sync_interval\",\"directory_sync_user_behavior\" \"directory_sync_user_behavior: _\",\"directory_sync_admin_behavior\" \"directory_sync_admin_behavior: _\",\"directory_sync_target\" \"directory_sync_target: _\",\"okta_private_jwk\",\"okta_dirsync_client_id\",\"directory_sync_group_match\" \"directory_sync_group_match: _\",\"jumpcloud_api_key\",\"prefetch_users\" FROM \"openidprovider\"", "describe": { "columns": [ { @@ -20,46 +20,65 @@ }, { "ordinal": 3, + "name": "kind: _", + "type_info": { + "Custom": { + "name": "openid_provider_kind", + "kind": { + "Enum": [ + "Custom", + "Google", + "Microsoft", + "Okta", + "JumpCloud", + "Zitadel" + ] + } + } + } + }, + { + "ordinal": 4, "name": "client_id", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 5, "name": "client_secret", "type_info": "Text" }, { - "ordinal": 5, + "ordinal": 6, "name": "display_name", "type_info": "Text" }, { - "ordinal": 6, + "ordinal": 7, "name": "google_service_account_key", "type_info": "Text" }, { - "ordinal": 7, + "ordinal": 8, "name": "google_service_account_email", "type_info": "Text" }, { - "ordinal": 8, + "ordinal": 9, "name": "admin_email", "type_info": "Text" }, { - "ordinal": 9, + "ordinal": 10, "name": "directory_sync_enabled", "type_info": "Bool" }, { - "ordinal": 10, + "ordinal": 11, "name": "directory_sync_interval", "type_info": "Int4" }, { - "ordinal": 11, + "ordinal": 12, "name": "directory_sync_user_behavior: _", "type_info": { "Custom": { @@ -75,7 +94,7 @@ } }, { - "ordinal": 12, + "ordinal": 13, "name": "directory_sync_admin_behavior: _", "type_info": { "Custom": { @@ -91,7 +110,7 @@ } }, { - "ordinal": 13, + "ordinal": 14, "name": "directory_sync_target: _", "type_info": { "Custom": { @@ -107,27 +126,27 @@ } }, { - "ordinal": 14, + "ordinal": 15, "name": "okta_private_jwk", "type_info": "Text" }, { - "ordinal": 15, + "ordinal": 16, "name": "okta_dirsync_client_id", "type_info": "Text" }, { - "ordinal": 16, + "ordinal": 17, "name": "directory_sync_group_match: _", "type_info": "TextArray" }, { - "ordinal": 17, + "ordinal": 18, "name": "jumpcloud_api_key", "type_info": "Text" }, { - "ordinal": 18, + "ordinal": 19, "name": "prefetch_users", "type_info": "Bool" } @@ -141,6 +160,7 @@ false, false, false, + false, true, true, true, @@ -157,5 +177,5 @@ false ] }, - "hash": "d8db674150231de0063227000a8b39f45c6da9836f93b67307787851a1804f13" + "hash": "f851e3667522ee439c614f66e13d89773b783a1b738c453791c45747b11aa106" } diff --git a/Cargo.lock b/Cargo.lock index 535698a6ec..5a465bf7ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4550,9 +4550,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "4910321ebe4151be888e35fe062169554e74aad01beafed60410131420ceffbc" dependencies = [ "web-time", "zeroize", @@ -6203,15 +6203,15 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "9.0.6" +version = "9.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b2bf58be11fc9414104c6d3a2e464163db5ef74b12296bda593cac37b6e4777" +checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75" dependencies = [ "anyhow", "derive_builder", "rustversion", "time", - "vergen-lib", + "vergen-lib 9.1.0", ] [[package]] @@ -6226,7 +6226,7 @@ dependencies = [ "rustversion", "time", "vergen", - "vergen-lib", + "vergen-lib 0.1.6", ] [[package]] @@ -6240,6 +6240,17 @@ dependencies = [ "rustversion", ] +[[package]] +name = "vergen-lib" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", +] + [[package]] name = "version_check" version = "0.9.5" @@ -6273,9 +6284,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ "wit-bindgen", ] @@ -6831,9 +6842,9 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] name = "writeable" diff --git a/crates/defguard_common/src/db/models/settings.rs b/crates/defguard_common/src/db/models/settings.rs index c9d6481721..1801c65274 100644 --- a/crates/defguard_common/src/db/models/settings.rs +++ b/crates/defguard_common/src/db/models/settings.rs @@ -54,7 +54,7 @@ pub enum SmtpEncryption { #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Serialize, PartialEq, ToSchema, Type)] #[sqlx(type_name = "openid_username_handling", rename_all = "snake_case")] -pub enum OpenidUsernameHandling { +pub enum OpenIdUsernameHandling { #[default] /// Removes all forbidden characters RemoveForbidden, @@ -138,7 +138,7 @@ pub struct Settings { pub ldap_sync_groups: Vec, // Whether to create a new account when users try to log in with external OpenID pub openid_create_account: bool, - pub openid_username_handling: OpenidUsernameHandling, + pub openid_username_handling: OpenIdUsernameHandling, pub license: Option, // Gateway disconnect notifications pub gateway_disconnect_notifications_enabled: bool, @@ -252,7 +252,7 @@ impl Settings { ldap_enabled, ldap_sync_enabled, ldap_is_authoritative, \ ldap_sync_interval, ldap_user_auxiliary_obj_classes, ldap_uses_ad, \ ldap_user_rdn_attr, ldap_sync_groups, \ - openid_username_handling \"openid_username_handling: OpenidUsernameHandling\", \ + openid_username_handling \"openid_username_handling: OpenIdUsernameHandling\", \ ca_key_der, ca_cert_der \ FROM \"settings\" WHERE id = 1", ) @@ -381,7 +381,7 @@ impl Settings { self.ldap_uses_ad, self.ldap_user_rdn_attr, &self.ldap_sync_groups as &Vec, - &self.openid_username_handling as &OpenidUsernameHandling, + &self.openid_username_handling as &OpenIdUsernameHandling, &self.ca_key_der as &Option>, &self.ca_cert_der as &Option>, ) diff --git a/crates/defguard_core/src/db/models/activity_log/metadata.rs b/crates/defguard_core/src/db/models/activity_log/metadata.rs index 582897cc30..adeb3888e3 100644 --- a/crates/defguard_core/src/db/models/activity_log/metadata.rs +++ b/crates/defguard_core/src/db/models/activity_log/metadata.rs @@ -6,7 +6,7 @@ use defguard_common::db::{ WireguardNetwork, group::Group, oauth2client::OAuth2Client, - settings::{LdapSyncStatus, OpenidUsernameHandling, SmtpEncryption}, + settings::{LdapSyncStatus, OpenIdUsernameHandling, SmtpEncryption}, user::User, }, }; @@ -391,7 +391,7 @@ pub struct SettingsNoSecrets { pub ldap_sync_groups: Vec, // Whether to create a new account when users try to log in with external OpenID pub openid_create_account: bool, - pub openid_username_handling: OpenidUsernameHandling, + pub openid_username_handling: OpenIdUsernameHandling, pub license: Option, // Gateway disconnect notifications pub gateway_disconnect_notifications_enabled: bool, diff --git a/crates/defguard_core/src/enterprise/db/models/openid_provider.rs b/crates/defguard_core/src/enterprise/db/models/openid_provider.rs index 8279b29a2c..16f15d51ff 100644 --- a/crates/defguard_core/src/enterprise/db/models/openid_provider.rs +++ b/crates/defguard_core/src/enterprise/db/models/openid_provider.rs @@ -3,6 +3,7 @@ use std::fmt; use defguard_common::db::{Id, NoId}; use model_derive::Model; use sqlx::{Error as SqlxError, PgExecutor, PgPool, Type, query, query_as}; +use utoipa::ToSchema; // The behavior when a user is deleted from the directory // Keep: Keep the user, despite being deleted from the external provider's directory @@ -86,11 +87,24 @@ impl From for DirectorySyncTarget { } } -#[derive(Clone, Debug, Deserialize, Model, Serialize, PartialEq)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, ToSchema, Type)] +#[sqlx(type_name = "openid_provider_kind")] +pub enum OpenIdProviderKind { + Custom, + Google, + Microsoft, + Okta, + JumpCloud, + Zitadel, +} + +#[derive(Clone, Debug, Deserialize, Model, PartialEq, Serialize)] pub struct OpenIdProvider { pub id: I, pub name: String, pub base_url: String, + #[model(enum)] + pub kind: OpenIdProviderKind, pub client_id: String, pub client_secret: String, pub display_name: Option, @@ -125,6 +139,7 @@ impl OpenIdProvider { pub fn new>( name: S, base_url: S, + kind: OpenIdProviderKind, client_id: S, client_secret: S, display_name: Option, @@ -146,6 +161,7 @@ impl OpenIdProvider { id: NoId, name: name.into(), base_url: base_url.into(), + kind, client_id: client_id.into(), client_secret: client_secret.into(), display_name, @@ -168,17 +184,17 @@ impl OpenIdProvider { pub(crate) async fn upsert(self, pool: &PgPool) -> Result, SqlxError> { if let Some(provider) = OpenIdProvider::::get_current(pool).await? { query!( - "UPDATE openidprovider SET name = $1, base_url = $2, client_id = $3, \ - client_secret = $4, display_name = $5, google_service_account_key = $6, \ - google_service_account_email = $7, admin_email = $8, directory_sync_enabled = $9, \ - directory_sync_interval = $10, directory_sync_user_behavior = $11, \ - directory_sync_admin_behavior = $12, directory_sync_target = $13, \ - okta_private_jwk = $14, okta_dirsync_client_id = $15, \ - directory_sync_group_match = $16, jumpcloud_api_key = $17, \ - prefetch_users = $18 \ - WHERE id = $19", + "UPDATE openidprovider SET name = $1, base_url = $2, kind = $3, client_id = $4, \ + client_secret = $5, display_name = $6, google_service_account_key = $7, \ + google_service_account_email = $8, admin_email = $9, directory_sync_enabled = $10, \ + directory_sync_interval = $11, directory_sync_user_behavior = $12, \ + directory_sync_admin_behavior = $13, directory_sync_target = $14, \ + okta_private_jwk = $15, okta_dirsync_client_id = $16, \ + directory_sync_group_match = $17, jumpcloud_api_key = $18, prefetch_users = $19 \ + WHERE id = $20", self.name, self.base_url, + self.kind as OpenIdProviderKind, self.client_id, self.client_secret, self.display_name, @@ -214,7 +230,7 @@ impl OpenIdProvider { { query_as!( OpenIdProvider, - "SELECT id, name, base_url, client_id, client_secret, display_name, \ + "SELECT id, name, base_url, kind \"kind: OpenIdProviderKind\", client_id, client_secret, display_name, \ google_service_account_key, google_service_account_email, admin_email, directory_sync_enabled, directory_sync_interval, directory_sync_user_behavior \"directory_sync_user_behavior: DirectorySyncUserBehavior\", \ directory_sync_admin_behavior \"directory_sync_admin_behavior: DirectorySyncUserBehavior\", \ @@ -233,7 +249,7 @@ impl OpenIdProvider { { query_as!( OpenIdProvider, - "SELECT id, name, base_url, client_id, client_secret, display_name, \ + "SELECT id, name, base_url, kind \"kind: OpenIdProviderKind\", client_id, client_secret, display_name, \ google_service_account_key, google_service_account_email, admin_email, directory_sync_enabled, \ directory_sync_interval, directory_sync_user_behavior \"directory_sync_user_behavior: DirectorySyncUserBehavior\", \ directory_sync_admin_behavior \"directory_sync_admin_behavior: DirectorySyncUserBehavior\", \ diff --git a/crates/defguard_core/src/enterprise/directory_sync/tests.rs b/crates/defguard_core/src/enterprise/directory_sync/tests.rs index 1d02ea3d21..c3e6079240 100644 --- a/crates/defguard_core/src/enterprise/directory_sync/tests.rs +++ b/crates/defguard_core/src/enterprise/directory_sync/tests.rs @@ -19,7 +19,7 @@ mod test { use tokio::sync::broadcast; use super::super::*; - use crate::enterprise::db::models::openid_provider::DirectorySyncTarget; + use crate::enterprise::db::models::openid_provider::{DirectorySyncTarget, OpenIdProviderKind}; async fn get_test_network(pool: &PgPool) -> WireguardNetwork { WireguardNetwork::find_by_name(pool, "test") @@ -69,6 +69,7 @@ mod test { OpenIdProvider::new( "Test".to_string(), "base_url".to_string(), + OpenIdProviderKind::Google, "client_id".to_string(), "client_secret".to_string(), Some("display_name".to_string()), diff --git a/crates/defguard_core/src/enterprise/handlers/openid_login.rs b/crates/defguard_core/src/enterprise/handlers/openid_login.rs index b2ab080333..e894f426f0 100644 --- a/crates/defguard_core/src/enterprise/handlers/openid_login.rs +++ b/crates/defguard_core/src/enterprise/handlers/openid_login.rs @@ -13,7 +13,7 @@ use defguard_common::{ config::server_config, db::{ Id, - models::{Settings, settings::OpenidUsernameHandling, user::User}, + models::{Settings, settings::OpenIdUsernameHandling, user::User}, }, }; use openidconnect::{ @@ -59,7 +59,7 @@ use crate::{ /// - only special characters allowed: . - _ /// - no whitespaces #[must_use] -pub fn prune_username(username: &str, handling: OpenidUsernameHandling) -> String { +pub fn prune_username(username: &str, handling: OpenIdUsernameHandling) -> String { let mut result = username.to_string(); // Go through the string and remove any non-alphanumeric characters at the beginning @@ -70,16 +70,16 @@ pub fn prune_username(username: &str, handling: OpenidUsernameHandling) -> Strin let is_char_valid = |c: char| c.is_ascii_alphanumeric() || c == '.' || c == '-' || c == '_'; match handling { - OpenidUsernameHandling::RemoveForbidden => { + OpenIdUsernameHandling::RemoveForbidden => { result.retain(&is_char_valid); } - OpenidUsernameHandling::ReplaceForbidden => { + OpenIdUsernameHandling::ReplaceForbidden => { result = result .chars() .map(|c| if is_char_valid(c) { c } else { '_' }) .collect(); } - OpenidUsernameHandling::PruneEmailDomain => { + OpenIdUsernameHandling::PruneEmailDomain => { if let Some(at_index) = result.find('@') { result.truncate(at_index); } @@ -658,7 +658,7 @@ mod test { #[test] fn test_prune_username() { // Test RemoveForbidden handling - let handling_remove = OpenidUsernameHandling::RemoveForbidden; + let handling_remove = OpenIdUsernameHandling::RemoveForbidden; assert_eq!(prune_username("zenek", handling_remove), "zenek"); assert_eq!(prune_username("zenek34", handling_remove), "zenek34"); assert_eq!(prune_username("zenek@34", handling_remove), "zenek34"); @@ -679,7 +679,7 @@ mod test { assert_eq!(prune_username("...zenek", handling_remove), "zenek"); // Test ReplaceForbidden handling - let handling_replace = OpenidUsernameHandling::ReplaceForbidden; + let handling_replace = OpenIdUsernameHandling::ReplaceForbidden; assert_eq!(prune_username("zenek", handling_replace), "zenek"); assert_eq!(prune_username("zenek34", handling_replace), "zenek34"); assert_eq!(prune_username("zenek@34", handling_replace), "zenek_34"); @@ -696,7 +696,7 @@ mod test { ); // Test PruneEmailDomain handling - let handling_prune_email = OpenidUsernameHandling::PruneEmailDomain; + let handling_prune_email = OpenIdUsernameHandling::PruneEmailDomain; assert_eq!( prune_username("zenek@example.com", handling_prune_email), "zenek" diff --git a/crates/defguard_core/src/enterprise/handlers/openid_providers.rs b/crates/defguard_core/src/enterprise/handlers/openid_providers.rs index e559418c39..8524173b1d 100644 --- a/crates/defguard_core/src/enterprise/handlers/openid_providers.rs +++ b/crates/defguard_core/src/enterprise/handlers/openid_providers.rs @@ -5,7 +5,7 @@ use axum::{ }; use defguard_common::db::models::{ Settings, WireguardNetwork, - settings::{OpenidUsernameHandling, update_current_settings}, + settings::{OpenIdUsernameHandling, update_current_settings}, wireguard::LocationMfaMode, }; use rsa::{RsaPrivateKey, pkcs8::DecodePrivateKey}; @@ -17,7 +17,8 @@ use crate::{ appstate::AppState, auth::{AdminRole, SessionInfo}, enterprise::{ - db::models::openid_provider::OpenIdProvider, directory_sync::test_directory_sync_connection, + db::models::openid_provider::{OpenIdProvider, OpenIdProviderKind}, + directory_sync::test_directory_sync_connection, }, events::{ApiEvent, ApiEventType, ApiRequestContext}, handlers::{ApiResponse, ApiResult}, @@ -27,6 +28,7 @@ use crate::{ pub struct AddProviderData { pub name: String, pub base_url: String, + pub kind: OpenIdProviderKind, pub client_id: String, pub client_secret: String, pub display_name: Option, @@ -38,13 +40,14 @@ pub struct AddProviderData { pub directory_sync_user_behavior: String, pub directory_sync_admin_behavior: String, pub directory_sync_target: String, - pub create_account: bool, pub okta_private_jwk: Option, pub okta_dirsync_client_id: Option, pub directory_sync_group_match: Option, - pub username_handling: OpenidUsernameHandling, pub jumpcloud_api_key: Option, pub prefetch_users: bool, + // Core settings + pub create_account: bool, + pub username_handling: OpenIdUsernameHandling, } /// Add OpenID provider. @@ -156,6 +159,7 @@ pub(crate) async fn add_openid_provider( let new_provider = OpenIdProvider::new( provider_data.name, provider_data.base_url, + provider_data.kind, provider_data.client_id, provider_data.client_secret, provider_data.display_name, @@ -337,6 +341,7 @@ pub(crate) async fn modify_openid_provider( let provider = OpenIdProvider::find_by_name(&mut *transaction, &provider_data.name).await?; if let Some(mut provider) = provider { provider.base_url = provider_data.base_url; + provider.kind = provider_data.kind; provider.client_id = provider_data.client_id; provider.client_secret = provider_data.client_secret; provider.save(&mut *transaction).await?; diff --git a/crates/defguard_core/tests/integration/api/openid_login.rs b/crates/defguard_core/tests/integration/api/openid_login.rs index 2810c54772..69453455d9 100644 --- a/crates/defguard_core/tests/integration/api/openid_login.rs +++ b/crates/defguard_core/tests/integration/api/openid_login.rs @@ -1,11 +1,13 @@ use chrono::{Duration, Utc}; use defguard_common::db::{ Id, - models::{oauth2client::OAuth2Client, settings::OpenidUsernameHandling}, + models::{oauth2client::OAuth2Client, settings::OpenIdUsernameHandling}, }; use defguard_core::{ enterprise::{ - db::models::openid_provider::{DirectorySyncTarget, DirectorySyncUserBehavior}, + db::models::openid_provider::{ + DirectorySyncTarget, DirectorySyncUserBehavior, OpenIdProviderKind, + }, handlers::openid_providers::AddProviderData, license::{License, LicenseTier, set_cached_license}, }, @@ -38,6 +40,7 @@ async fn test_openid_providers(_: PgPoolOptions, options: PgConnectOptions) { name: "test".to_string(), // FIXME: this won't work offline. base_url: "https://accounts.google.com".to_string(), + kind: OpenIdProviderKind::Google, client_id: "client_id".to_string(), client_secret: "client_secret".to_string(), display_name: Some("display_name".to_string()), @@ -53,7 +56,7 @@ async fn test_openid_providers(_: PgPoolOptions, options: PgConnectOptions) { okta_dirsync_client_id: None, okta_private_jwk: None, directory_sync_group_match: None, - username_handling: OpenidUsernameHandling::PruneEmailDomain, + username_handling: OpenIdUsernameHandling::PruneEmailDomain, jumpcloud_api_key: None, prefetch_users: false, }; @@ -140,6 +143,7 @@ async fn test_openid_login(_: PgPoolOptions, options: PgConnectOptions) { let provider_data = AddProviderData { name: "Custom".into(), base_url: url, + kind: OpenIdProviderKind::Custom, client_id: openid_client.client_id.clone(), client_secret: openid_client.client_secret.clone(), display_name: Some("Defguard".to_string()), @@ -155,7 +159,7 @@ async fn test_openid_login(_: PgPoolOptions, options: PgConnectOptions) { okta_dirsync_client_id: None, okta_private_jwk: None, directory_sync_group_match: None, - username_handling: OpenidUsernameHandling::PruneEmailDomain, + username_handling: OpenIdUsernameHandling::PruneEmailDomain, jumpcloud_api_key: None, prefetch_users: false, }; diff --git a/crates/defguard_core/tests/integration/api/wireguard.rs b/crates/defguard_core/tests/integration/api/wireguard.rs index 80a213f5fa..69667beeb7 100644 --- a/crates/defguard_core/tests/integration/api/wireguard.rs +++ b/crates/defguard_core/tests/integration/api/wireguard.rs @@ -5,7 +5,7 @@ use defguard_common::db::{ models::{ Device, WireguardNetwork, device::WireguardNetworkDevice, - settings::OpenidUsernameHandling, + settings::OpenIdUsernameHandling, wireguard::{ DEFAULT_DISCONNECT_THRESHOLD, DEFAULT_KEEPALIVE_INTERVAL, LocationMfaMode, ServiceLocationMode, @@ -14,7 +14,9 @@ use defguard_common::db::{ }; use defguard_core::{ enterprise::{ - db::models::openid_provider::{DirectorySyncTarget, DirectorySyncUserBehavior}, + db::models::openid_provider::{ + DirectorySyncTarget, DirectorySyncUserBehavior, OpenIdProviderKind, + }, handlers::openid_providers::AddProviderData, license::{get_cached_license, set_cached_license}, }, @@ -177,6 +179,7 @@ async fn test_location_mfa_mode_validation_create(_: PgPoolOptions, options: PgC let provider_data = AddProviderData { name: "test".to_string(), base_url: "https://accounts.google.com".to_string(), + kind: OpenIdProviderKind::Custom, client_id: "client_id".to_string(), client_secret: "client_secret".to_string(), display_name: Some("display_name".to_string()), @@ -192,7 +195,7 @@ async fn test_location_mfa_mode_validation_create(_: PgPoolOptions, options: PgC okta_dirsync_client_id: None, okta_private_jwk: None, directory_sync_group_match: None, - username_handling: OpenidUsernameHandling::PruneEmailDomain, + username_handling: OpenIdUsernameHandling::PruneEmailDomain, jumpcloud_api_key: None, prefetch_users: false, }; @@ -275,6 +278,7 @@ async fn test_location_mfa_mode_validation_modify(_: PgPoolOptions, options: PgC let provider_data = AddProviderData { name: "test".to_string(), base_url: "https://accounts.google.com".to_string(), + kind: OpenIdProviderKind::Google, client_id: "client_id".to_string(), client_secret: "client_secret".to_string(), display_name: Some("display_name".to_string()), @@ -290,7 +294,7 @@ async fn test_location_mfa_mode_validation_modify(_: PgPoolOptions, options: PgC okta_dirsync_client_id: None, okta_private_jwk: None, directory_sync_group_match: None, - username_handling: OpenidUsernameHandling::PruneEmailDomain, + username_handling: OpenIdUsernameHandling::PruneEmailDomain, jumpcloud_api_key: None, prefetch_users: false, }; diff --git a/migrations/20260115123545_[2.0.0]_openid_provider_kind.down.sql b/migrations/20260115123545_[2.0.0]_openid_provider_kind.down.sql new file mode 100644 index 0000000000..9451ea998e --- /dev/null +++ b/migrations/20260115123545_[2.0.0]_openid_provider_kind.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE openidprovider DROP COLUMN kind; +DROP TYPE openid_provider_kind; diff --git a/migrations/20260115123545_[2.0.0]_openid_provider_kind.up.sql b/migrations/20260115123545_[2.0.0]_openid_provider_kind.up.sql new file mode 100644 index 0000000000..20dee5a954 --- /dev/null +++ b/migrations/20260115123545_[2.0.0]_openid_provider_kind.up.sql @@ -0,0 +1,10 @@ +CREATE TYPE openid_provider_kind AS ENUM ( + 'Custom', + 'Google', + 'Microsoft', + 'Okta', + 'JumpCloud', + 'Zitadel' +); + +ALTER TABLE openidprovider ADD COLUMN kind openid_provider_kind NOT NULL DEFAULT 'Custom'::openid_provider_kind; diff --git a/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdClientSettingsStep/AddExternalOpenIdClientSettingsStep.tsx b/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdClientSettingsStep/AddExternalOpenIdClientSettingsStep.tsx index ccdd07a92f..8038e5e75e 100644 --- a/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdClientSettingsStep/AddExternalOpenIdClientSettingsStep.tsx +++ b/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdClientSettingsStep/AddExternalOpenIdClientSettingsStep.tsx @@ -2,7 +2,11 @@ import { useMutation } from '@tanstack/react-query'; import { useMemo } from 'react'; import z from 'zod'; import { m } from '../../../../paraglide/messages'; -import { OpenIdProviderUsernameHandling } from '../../../../shared/api/types'; +import { + OpenIdProviderKind, + type OpenIdProviderKindValue, + OpenIdProviderUsernameHandling, +} from '../../../../shared/api/types'; import { Controls } from '../../../../shared/components/Controls/Controls'; import { WizardCard } from '../../../../shared/components/wizard/WizardCard/WizardCard'; import { SUPPORTED_SYNC_PROVIDERS } from '../../../../shared/constants'; @@ -11,10 +15,6 @@ import { SizedBox } from '../../../../shared/defguard-ui/components/SizedBox/Siz import { ThemeSpacing } from '../../../../shared/defguard-ui/types'; import { useAppForm } from '../../../../shared/form'; import { formChangeLogic } from '../../../../shared/formLogic'; -import { - ExternalProvider, - type ExternalProviderValue, -} from '../../../settings/shared/types'; import { formatMicrosoftBaseUrl, providerUsernameHandlingOptions, @@ -22,10 +22,10 @@ import { } from '../../consts'; import { useAddExternalOpenIdStore } from '../../useAddExternalOpenIdStore'; -const baseUrlHidden: Set = new Set([ - ExternalProvider.JumpCloud, - ExternalProvider.Microsoft, - ExternalProvider.Google, +const baseUrlHidden: Set = new Set([ + OpenIdProviderKind.JumpCloud, + OpenIdProviderKind.Microsoft, + OpenIdProviderKind.Google, ]); export const AddExternalOpenIdClientSettingsStep = () => { @@ -76,7 +76,7 @@ export const AddExternalOpenIdClientSettingsStep = () => { microsoftTenantId: z.string().trim().nullable(), }) .superRefine((values, ctx) => { - if (provider === ExternalProvider.Microsoft) { + if (provider === OpenIdProviderKind.Microsoft) { const schema = z .string(m.form_error_required()) .trim() @@ -143,7 +143,7 @@ export const AddExternalOpenIdClientSettingsStep = () => { {(field) => } - {provider === ExternalProvider.Microsoft && ( + {provider === OpenIdProviderKind.Microsoft && ( <> { const handleValidSubmit = useCallback( async (value: Partial) => { - const providerState = useAddExternalOpenIdStore.getState().providerState; - const submitValues = { ...cloneDeep(providerState), value }; + const state = useAddExternalOpenIdStore.getState(); + const providerState = state.providerState; + const provider = state.provider; + const submitValues = { ...cloneDeep(providerState), value, kind: provider }; await mutateAsync(submitValues); }, [mutateAsync], @@ -53,13 +55,13 @@ export const AddExternalOpenIdDirectoryStep = () => { const formRender = useMemo(() => { switch (provider) { - case 'google': + case 'Google': return ; - case 'microsoft': + case 'Microsoft': return ; - case 'okta': + case 'Okta': return ; - case 'jumpCloud': + case 'JumpCloud': return ; } return null; diff --git a/web/src/pages/AddExternalOpenIdWizardPage/useAddExternalOpenIdStore.tsx b/web/src/pages/AddExternalOpenIdWizardPage/useAddExternalOpenIdStore.tsx index 93888f78fa..8492d444e9 100644 --- a/web/src/pages/AddExternalOpenIdWizardPage/useAddExternalOpenIdStore.tsx +++ b/web/src/pages/AddExternalOpenIdWizardPage/useAddExternalOpenIdStore.tsx @@ -5,6 +5,8 @@ import { type AddOpenIdProvider, DirectorySyncBehavior, DirectorySyncTarget, + OpenIdProviderKind, + type OpenIdProviderKindValue, OpenIdProviderUsernameHandling, } from '../../shared/api/types'; import { @@ -13,7 +15,6 @@ import { jumpcloudProviderBaseUrl, SUPPORTED_SYNC_PROVIDERS, } from '../../shared/constants'; -import { ExternalProvider, type ExternalProviderValue } from '../settings/shared/types'; import { AddExternalProviderStep, type AddExternalProviderStepValue } from './types'; type ProviderState = AddOpenIdProvider & { @@ -21,7 +22,7 @@ type ProviderState = AddOpenIdProvider & { }; interface StoreValues { - provider: ExternalProviderValue; + provider: OpenIdProviderKindValue; activeStep: AddExternalProviderStepValue; providerState: ProviderState; testResult: boolean | null; @@ -29,38 +30,42 @@ interface StoreValues { } export const addExternalOpenIdStoreDefaults: StoreValues = { - provider: ExternalProvider.Custom, + provider: OpenIdProviderKind.Custom, activeStep: 'client-settings', testResult: null, testMessage: null, providerState: { - name: ExternalProvider.Custom, - display_name: '', - admin_email: '', + name: OpenIdProviderKind.Custom, base_url: '', + kind: OpenIdProviderKind.Custom, client_id: '', client_secret: '', - create_account: false, - microsoftTenantId: null, - directory_sync_group_match: null, - google_service_account_email: null, + display_name: '', google_service_account_key: null, - okta_dirsync_client_id: null, - okta_private_jwk: null, - jumpcloud_api_key: null, + google_service_account_email: null, + admin_email: '', directory_sync_enabled: false, directory_sync_interval: 600, - directory_sync_target: DirectorySyncTarget.All, - directory_sync_admin_behavior: DirectorySyncBehavior.Keep, directory_sync_user_behavior: DirectorySyncBehavior.Keep, + directory_sync_admin_behavior: DirectorySyncBehavior.Keep, + directory_sync_target: DirectorySyncTarget.All, + okta_private_jwk: null, + okta_dirsync_client_id: null, + directory_sync_group_match: null, + jumpcloud_api_key: null, prefetch_users: false, + + // Core settings + create_account: false, username_handling: OpenIdProviderUsernameHandling.RemoveForbidden, + + microsoftTenantId: null, }, }; interface Store extends StoreValues { reset: () => void; - initialize: (provider: ExternalProviderValue) => void; + initialize: (provider: OpenIdProviderKindValue) => void; next: (data?: Partial) => void; back: (data?: Partial) => void; } @@ -115,24 +120,24 @@ export const useAddExternalOpenIdStore = create()( initialize: (provider) => { const initialProviderState = addExternalOpenIdStoreDefaults.providerState; initialProviderState.name = provider; - if (provider !== ExternalProvider.Custom) { + initialProviderState.kind = provider; + if (provider !== OpenIdProviderKind.Custom) { initialProviderState.display_name = externalProviderName[provider]; } switch (provider) { - case 'google': + case 'Google': initialProviderState.base_url = googleProviderBaseUrl; break; - case 'microsoft': + case 'Microsoft': break; - case 'jumpCloud': + case 'JumpCloud': initialProviderState.base_url = jumpcloudProviderBaseUrl; break; - case 'okta': + case 'Okta': break; } set({ activeStep: 'client-settings', - provider, providerState: initialProviderState, }); }, diff --git a/web/src/pages/settings/SettingsEditOpenIdProviderPage/SettingsEditOpenIdProviderPage.tsx b/web/src/pages/settings/SettingsEditOpenIdProviderPage/SettingsEditOpenIdProviderPage.tsx index 9e7cd381ca..d2b7c5bec9 100644 --- a/web/src/pages/settings/SettingsEditOpenIdProviderPage/SettingsEditOpenIdProviderPage.tsx +++ b/web/src/pages/settings/SettingsEditOpenIdProviderPage/SettingsEditOpenIdProviderPage.tsx @@ -2,11 +2,10 @@ import { useMutation, useSuspenseQuery } from '@tanstack/react-query'; import { Link, useRouter } from '@tanstack/react-router'; import { useCallback, useMemo } from 'react'; import api from '../../../shared/api/api'; -import type { AddOpenIdProvider } from '../../../shared/api/types'; +import { type AddOpenIdProvider, OpenIdProviderKind } from '../../../shared/api/types'; import { EditPage } from '../../../shared/components/EditPage/EditPage'; import { isPresent } from '../../../shared/defguard-ui/utils/isPresent'; import { getExternalProviderQueryOptions } from '../../../shared/query'; -import { ExternalProvider } from '../shared/types'; import { EditCustomProviderForm } from './form/EditCustomProviderForm'; import { EditGoogleProviderForm } from './form/EditGoogleProviderForm'; import { EditJumpCloudProviderForm } from './form/EditJumpCloudProviderForm'; @@ -78,7 +77,7 @@ export const SettingsEditOpenIdProviderPage = () => { title: 'Edit external OpenID provider', }} > - {formData.name === ExternalProvider.Google && ( + {formData.name === OpenIdProviderKind.Google && ( { loading={deletePending} /> )} - {formData.name === ExternalProvider.Microsoft && ( + {formData.name === OpenIdProviderKind.Microsoft && ( { loading={deletePending} /> )} - {formData.name === ExternalProvider.Okta && ( + {formData.name === OpenIdProviderKind.Okta && ( { loading={deletePending} /> )} - {formData.name === ExternalProvider.JumpCloud && ( + {formData.name === OpenIdProviderKind.JumpCloud && ( { loading={deletePending} /> )} - {formData.name === ExternalProvider.Custom && ( + {formData.name === OpenIdProviderKind.Custom && ( { }); const visibleProviders = useMemo(() => { - const res = Object.values(ExternalProvider).filter( - (p) => p !== ExternalProvider.Zitadel, + const res = Object.values(OpenIdProviderKind).filter( + (p) => p !== OpenIdProviderKind.Zitadel, ); if (activeProvider) { return res.filter((p) => p !== activeProvider.name); @@ -47,7 +50,7 @@ export const SettingsExternalOpenIdPage = () => { { navigate({ to: '/settings/edit-openid' }); diff --git a/web/src/pages/settings/SettingsExternalOpenIdPage/components/ExternalProviderCard/ExternalProviderCard.tsx b/web/src/pages/settings/SettingsExternalOpenIdPage/components/ExternalProviderCard/ExternalProviderCard.tsx index ba2f323429..298a22d405 100644 --- a/web/src/pages/settings/SettingsExternalOpenIdPage/components/ExternalProviderCard/ExternalProviderCard.tsx +++ b/web/src/pages/settings/SettingsExternalOpenIdPage/components/ExternalProviderCard/ExternalProviderCard.tsx @@ -1,8 +1,8 @@ import { type ReactNode, useMemo } from 'react'; -import type { ExternalProviderValue } from '../../../shared/types'; import './style.scss'; import clsx from 'clsx'; import { m } from '../../../../../paraglide/messages'; +import type { OpenIdProviderKindValue } from '../../../../../shared/api/types'; import { externalProviderName } from '../../../../../shared/constants'; import { Button } from '../../../../../shared/defguard-ui/components/Button/Button'; import { Icon } from '../../../../../shared/defguard-ui/components/Icon'; @@ -15,33 +15,33 @@ import okta from './assets/okta.png'; import zitadel from './assets/zitadel.png'; type Props = { - provider: ExternalProviderValue; + provider: OpenIdProviderKindValue; displayName?: string; onClick: () => void; disabled?: boolean; edit?: boolean; }; -const providerImage: Record = { - custom: , - google: , - jumpCloud: , - microsoft: , - okta: , - zitadel: , +const providerImage: Record = { + Custom: , + Google: , + JumpCloud: , + Microsoft: , + Okta: , + Zitadel: , }; -const providerDescription: Record = { - custom: +const providerDescription: Record = { + Custom: 'Enter the required details to link your account securely and manage logins with your custom setup.', - zitadel: + Zitadel: 'Get started with a multi-tenant, API-first identity platform with comprehensive SDKs that enable security, compliance, and extensibility.', - jumpCloud: + JumpCloud: "Enable users to log in with their JumpCloud accounts through JumpCloud's secure directory and authentication platform.", - okta: "Allow users to sign in with their Okta accounts using Okta's secure identity management service.", - microsoft: + Okta: "Allow users to sign in with their Okta accounts using Okta's secure identity management service.", + Microsoft: "Enable users to log in with their Microsoft accounts through Microsoft's secure authentication platform.", - google: + Google: "Allow users to sign in securely with their Google accounts using Google's trusted authentication service.", }; diff --git a/web/src/pages/settings/shared/types.ts b/web/src/pages/settings/shared/types.ts deleted file mode 100644 index 1814d531b4..0000000000 --- a/web/src/pages/settings/shared/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const ExternalProvider = { - Google: 'google', - Microsoft: 'microsoft', - Okta: 'okta', - JumpCloud: 'jumpCloud', - Zitadel: 'zitadel', - Custom: 'custom', -} as const; - -export type ExternalProviderValue = - (typeof ExternalProvider)[keyof typeof ExternalProvider]; diff --git a/web/src/shared/api/types.ts b/web/src/shared/api/types.ts index a4c1cb140f..9a0656dafb 100644 --- a/web/src/shared/api/types.ts +++ b/web/src/shared/api/types.ts @@ -1,4 +1,3 @@ -import type { ExternalProviderValue } from '../../pages/settings/shared/types'; import type { ActivityLogEventTypeValue, ActivityLogModuleValue, @@ -679,6 +678,18 @@ export interface OpenIdProviderSettings { username_handling: OpenIdProviderUsernameHandlingValue; } +export const OpenIdProviderKind = { + Custom: 'Custom', + Google: 'Google', + Microsoft: 'Microsoft', + Okta: 'Okta', + JumpCloud: 'JumpCloud', + Zitadel: 'Zitadel', +} as const; + +export type OpenIdProviderKindValue = + (typeof OpenIdProviderKind)[keyof typeof OpenIdProviderKind]; + export const DirectorySyncBehavior = { Keep: 'keep', Disable: 'disable', @@ -708,24 +719,24 @@ export type OpenIdProviderUsernameHandlingValue = export interface OpenIdProvider { id: number; - name: ExternalProviderValue; + name: OpenIdProviderKindValue; base_url: string; + kind: OpenIdProviderKindValue; client_id: string; client_secret: string; display_name: string; + google_service_account_key?: string | null; + google_service_account_email?: string | null; + admin_email?: string | null; directory_sync_enabled: boolean; directory_sync_interval: number; directory_sync_user_behavior: DirectorySyncBehaviorValue; directory_sync_admin_behavior: DirectorySyncBehaviorValue; directory_sync_target: DirectorySyncTargetValue; - google_service_account_key?: string | null; - google_service_account_email?: string | null; - admin_email?: string | null; okta_private_jwk?: string | null; okta_dirsync_client_id?: string | null; - jumpcloud_api_key?: string | null; - // microsoft directory_sync_group_match?: string | null; + jumpcloud_api_key?: string | null; prefetch_users: boolean; } diff --git a/web/src/shared/constants.ts b/web/src/shared/constants.ts index d40741216a..3505edf36c 100644 --- a/web/src/shared/constants.ts +++ b/web/src/shared/constants.ts @@ -1,7 +1,4 @@ -import { - ExternalProvider, - type ExternalProviderValue, -} from '../pages/settings/shared/types'; +import { OpenIdProviderKind, type OpenIdProviderKindValue } from './api/types'; export const externalLink = { defguard: { @@ -20,20 +17,20 @@ export const externalLink = { }, } as const; -export const externalProviderName: Record = { - custom: 'Custom provider', - google: 'Google', - jumpCloud: 'JumpCloud', - microsoft: 'Microsoft', - okta: 'Okta', - zitadel: 'Zitadel', +export const externalProviderName: Record = { + Custom: 'Custom provider', + Google: 'Google', + JumpCloud: 'JumpCloud', + Microsoft: 'Microsoft', + Okta: 'Okta', + Zitadel: 'Zitadel', }; -export const SUPPORTED_SYNC_PROVIDERS: Set = new Set([ - ExternalProvider.Google, - ExternalProvider.Microsoft, - ExternalProvider.Okta, - ExternalProvider.JumpCloud, +export const SUPPORTED_SYNC_PROVIDERS: Set = new Set([ + OpenIdProviderKind.Google, + OpenIdProviderKind.Microsoft, + OpenIdProviderKind.Okta, + OpenIdProviderKind.JumpCloud, ]); export const googleProviderBaseUrl = 'https://accounts.google.com';