From 095ed7c95df600880fb9133b96d9b8d24dc508e1 Mon Sep 17 00:00:00 2001 From: Ramin Haeri Azad Date: Thu, 1 Aug 2024 17:47:12 -0400 Subject: [PATCH 1/2] Started the UI for key-pair --- .../providers/AddIdentityProviderDialog.vue | 2 +- .../components/admin/users/AddUserDialog.vue | 2 +- .../src/components/profile/AddTokenDialog.vue | 2 +- .../components/project/AddKeyPairDialog.vue | 113 +++++++++++++++ .../src/components/project/KeyPairsList.vue | 129 ++++++++++++++++++ opal-ui/src/i18n/en/index.js | 13 +- opal-ui/src/pages/ProjectAdminPage.vue | 14 +- opal-ui/src/stores/projects.ts | 17 ++- 8 files changed, 281 insertions(+), 11 deletions(-) create mode 100644 opal-ui/src/components/project/AddKeyPairDialog.vue create mode 100644 opal-ui/src/components/project/KeyPairsList.vue diff --git a/opal-ui/src/components/admin/providers/AddIdentityProviderDialog.vue b/opal-ui/src/components/admin/providers/AddIdentityProviderDialog.vue index c32eefd306..cf78ab7383 100644 --- a/opal-ui/src/components/admin/providers/AddIdentityProviderDialog.vue +++ b/opal-ui/src/components/admin/providers/AddIdentityProviderDialog.vue @@ -17,7 +17,7 @@ :hint="$t('identity_provider.name_hint')" class="q-mb-md" lazy-rules - :rules="[validateRequiredField('validation.identity_provider.name_required')]" + :rules="[validateRequiredField('validation.name_required')]" :disable="editMode" > diff --git a/opal-ui/src/components/admin/users/AddUserDialog.vue b/opal-ui/src/components/admin/users/AddUserDialog.vue index cc37e47bad..f631ff3cd5 100644 --- a/opal-ui/src/components/admin/users/AddUserDialog.vue +++ b/opal-ui/src/components/admin/users/AddUserDialog.vue @@ -168,7 +168,7 @@ function addGroup(val: string, done: any) { } // Validation rules -const validateRequiredName = (val: string) => (val && val.trim().length > 0) || t('validation.user.name_required'); +const validateRequiredName = (val: string) => (val && val.trim().length > 0) || t('validation.name_required'); const validateRequiredCertificate = (val: string) => (editMode.value && (!val || val.length === 0)) || (val && val.trim().length > 0) || diff --git a/opal-ui/src/components/profile/AddTokenDialog.vue b/opal-ui/src/components/profile/AddTokenDialog.vue index d02d426dcd..b67bd49c77 100644 --- a/opal-ui/src/components/profile/AddTokenDialog.vue +++ b/opal-ui/src/components/profile/AddTokenDialog.vue @@ -153,7 +153,7 @@ watch( ); // Validations -const validateRequiredName = (val: string) => (val && val.trim().length > 0) || t('validation.token.name_required'); +const validateRequiredName = (val: string) => (val && val.trim().length > 0) || t('validation.name_required'); // Group options const taskGroupOptions: { label: string; value: string }[] = []; diff --git a/opal-ui/src/components/project/AddKeyPairDialog.vue b/opal-ui/src/components/project/AddKeyPairDialog.vue new file mode 100644 index 0000000000..1af21589f7 --- /dev/null +++ b/opal-ui/src/components/project/AddKeyPairDialog.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/opal-ui/src/components/project/KeyPairsList.vue b/opal-ui/src/components/project/KeyPairsList.vue new file mode 100644 index 0000000000..ee07e2adc9 --- /dev/null +++ b/opal-ui/src/components/project/KeyPairsList.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/opal-ui/src/i18n/en/index.js b/opal-ui/src/i18n/en/index.js index 4c06bfe1b8..a935af09a0 100644 --- a/opal-ui/src/i18n/en/index.js +++ b/opal-ui/src/i18n/en/index.js @@ -334,6 +334,12 @@ export default { id_mappings_info: 'Identifiers mappings listed below that match the entity type of the data are automatically selected during an import/export process.', id_mappings_hint: 'The name of the mapping.', id_mapping: 'Identifiers Mapping', + encryption_keys: 'Encryption Keys', + encryption_keys_info: 'Encrypted data will be automatically decrypted at importation time using the key pairs registered within the project.', + import_key: 'Import Key Pair', + import_key_info: 'Paste encryption key in PEM format.', + private_key: 'Private Key', + public_key: 'Public Key', }, user_profile: { title: 'My profile', @@ -389,8 +395,8 @@ export default { deleteProject: 'Delete', }, validation: { + name_required: 'Name is required', user: { - name_required: 'Name is required', password_required: 'Password is required and must be at least 8 characters long', certificate_required: 'Certificate is required', confirm_password_required: 'Confirm password is required', @@ -410,9 +416,6 @@ export default { old_password: 'Old password is required', new_password: 'New password is required and must be at least 8 characters long', }, - token: { - name_required: 'Token name is required', - }, text_required: 'A text is required', github: { org_required: 'Github organization or username is required', @@ -420,6 +423,8 @@ export default { }, project_admin: { backup_folder_required: 'Backup folder is required', + private_key_required: 'Private Key in PEM format is required', + public_key_required: 'Public Key in PEM format is required', }, }, main: { diff --git a/opal-ui/src/pages/ProjectAdminPage.vue b/opal-ui/src/pages/ProjectAdminPage.vue index 1fd4936c08..17f7fe81c5 100644 --- a/opal-ui/src/pages/ProjectAdminPage.vue +++ b/opal-ui/src/pages/ProjectAdminPage.vue @@ -44,12 +44,19 @@ + + +
{{ $t('project_admin.encryption_keys') }}
+
{{ $t('project_admin.encryption_keys') }}
+ +
+
+
{{ $t('id_mappings') }}
{{ $t('project_admin.id_mappings_info') }}
- - +
@@ -171,6 +178,7 @@ import BackupProjectDialog from 'src/components/project/BackupProjectDialog.vue' import RestoreProjectDialog from 'src/components/project/RestoreProjectDialog.vue'; import AddProjectDialog from 'src/components/project/AddProjectDialog.vue'; import IdMappingsList from 'src/components/project/IdMappingsList.vue'; +import KeyPairsList from 'src/components/project/KeyPairsList.vue'; const route = useRoute(); const router = useRouter(); @@ -295,7 +303,7 @@ function onEdit() { showEditProject.value = true; } -async function onIdMappingsUpdate() { +async function onProjectUpdate() { try { await projectsStore.refreshProject(name.value); await getState(); diff --git a/opal-ui/src/stores/projects.ts b/opal-ui/src/stores/projects.ts index 6a28df5b40..e78b0a03bb 100644 --- a/opal-ui/src/stores/projects.ts +++ b/opal-ui/src/stores/projects.ts @@ -7,7 +7,7 @@ import { ProjectDto_IdentifiersMappingDto, } from 'src/models/Projects'; import { Acl } from 'src/models/Opal'; -import { Subject } from 'src/models/Opal'; +import { Subject, KeyForm } from 'src/models/Opal'; import { CommandStateDto, CommandStateDto_Status, @@ -261,6 +261,18 @@ export const useProjectsStore = defineStore('projects', () => { return updateProject(project); } + async function getKeyPairs(name: string) { + return api.get(`/project/${name}/keystore`).then((response) => response.data); + } + + async function addKeyPair(name: string, keyPair: KeyForm) { + return api.post(`/project/${name}/keystore`, keyPair); + } + + async function deleteKeyPair(name: string, alias: string) { + return api.delete(`/project/${name}/keystore/${alias}`); + } + return { projects, project, @@ -296,5 +308,8 @@ export const useProjectsStore = defineStore('projects', () => { getIdMappings, addIdMappings, deleteIdMappings, + getKeyPairs, + addKeyPair, + deleteKeyPair, }; }); From 3f10fc5aa015a0fde8f0b0d9b7f2da927d03b155 Mon Sep 17 00:00:00 2001 From: Ramin Haeri Azad Date: Fri, 2 Aug 2024 16:07:44 -0400 Subject: [PATCH 2/2] Added KeyPair in project admin pg + fix for private key --- .../opal/web/security/KeyStoreResource.java | 3 +- .../src/components/project/IdMappingsList.vue | 3 +- .../src/components/project/KeyPairsList.vue | 24 +++++++------ opal-ui/src/i18n/en/index.js | 10 ++++-- opal-ui/src/i18n/fr/index.js | 21 ++++++++---- opal-ui/src/pages/ProjectAdminPage.vue | 34 ++++++++++++++----- opal-ui/src/pages/ProjectPermsPage.vue | 12 +++---- opal-ui/src/stores/projects.ts | 15 ++++++-- pom.xml | 2 +- 9 files changed, 85 insertions(+), 39 deletions(-) diff --git a/opal-core-ws/src/main/java/org/obiba/opal/web/security/KeyStoreResource.java b/opal-core-ws/src/main/java/org/obiba/opal/web/security/KeyStoreResource.java index 6875db43d7..5f6f56e8a1 100644 --- a/opal-core-ws/src/main/java/org/obiba/opal/web/security/KeyStoreResource.java +++ b/opal-core-ws/src/main/java/org/obiba/opal/web/security/KeyStoreResource.java @@ -36,6 +36,7 @@ import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.obiba.opal.core.security.OpalKeyStore; import org.obiba.opal.core.service.security.KeyStoreService; +import org.obiba.opal.web.BaseResource; import org.obiba.opal.web.magma.ClientErrorDtos; import org.obiba.opal.web.model.Opal; import org.springframework.beans.factory.annotation.Autowired; @@ -52,7 +53,7 @@ @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) -public class KeyStoreResource { +public class KeyStoreResource implements BaseResource { private OpalKeyStore keyStore; diff --git a/opal-ui/src/components/project/IdMappingsList.vue b/opal-ui/src/components/project/IdMappingsList.vue index 5c87af2209..acad3e6d30 100644 --- a/opal-ui/src/components/project/IdMappingsList.vue +++ b/opal-ui/src/components/project/IdMappingsList.vue @@ -89,7 +89,8 @@ const columns = computed(() => [ label: t('project_admin.entity_type'), align: 'left', field: 'entityType', - style: 'width: 30%', + headerStyle: 'width: 30%; white-space: normal;', + style: 'width: 30%; white-space: normal;', }, { name: 'mapping', diff --git a/opal-ui/src/components/project/KeyPairsList.vue b/opal-ui/src/components/project/KeyPairsList.vue index ee07e2adc9..2ffb2b9de5 100644 --- a/opal-ui/src/components/project/KeyPairsList.vue +++ b/opal-ui/src/components/project/KeyPairsList.vue @@ -21,7 +21,7 @@ @click.prevent="onAdd" /> -