From 0b1acb7d2c5bff7ed69d5c4100a0c52b20744d74 Mon Sep 17 00:00:00 2001 From: Michael Haufe Date: Fri, 9 Aug 2024 18:56:33 -0500 Subject: [PATCH] 303 migrate login system to microsoft entra external (#313) - Completed Azure AD B2C integration - updated dependencies - Created global error page - Renamed `lib` folder to `utils` - Impelemented generic UI error handler - Created an event-bus - Updated DB schema to support new user model - Updated .env settings for Azure AD B2C - XDataTable now supports custom Create button label - Updated implementation of users screen - Removed approles endpoints - Refactored AppRoles to a enum --- .env.example | 18 +- .github/workflows/azure-deploy.yml | 33 +- CONTRIBUTING.md | 3 +- azure/bicep/main.bicep | 6 - azure/bicep/modules/appService.bicep | 12 - components/TopNavigation.vue | 14 +- components/XDataTable.vue | 4 +- error.vue | 22 + layouts/default.vue | 26 +- lib/reCamelCaseToSnakeCase.ts | 3 - lib/reSnakeCaseToCamelCase.ts | 1 - migrations/.snapshot-cathedral.json | 82 +- migrations/Migration20240808202308.ts | 32 + mikro-orm.config.ts | 14 +- next-auth.d.ts | 8 +- nuxt.config.ts | 35 +- package-lock.json | 20394 +++++++++------- package.json | 20 +- pages/index.client.vue | 12 +- pages/login.vue | 2 +- pages/new-organization.vue | 9 +- .../[solution-slug]/edit-entry.client.vue | 10 +- .../environment/assumptions.client.vue | 18 +- .../environment/components.client.vue | 18 +- .../environment/constraints.client.vue | 18 +- .../environment/effects.client.vue | 17 +- .../environment/glossary.client.vue | 18 +- .../environment/invariants.client.vue | 18 +- .../goals/functionality.client.vue | 18 +- .../goals/limitations.client.vue | 18 +- .../goals/obstacles.client.vue | 15 +- .../[solution-slug]/goals/outcomes.client.vue | 18 +- .../goals/rationale.client.vue | 37 +- .../goals/scenarios.client.vue | 32 +- .../goals/stakeholders.client.vue | 16 +- .../[solution-slug]/index.client.vue | 10 +- .../project/roles-personnel.client.vue | 18 +- .../system/components.client.vue | 19 +- .../system/functionality.client.vue | 19 +- .../system/scenarios.client.vue | 49 +- .../[organization-slug]/edit-entry.client.vue | 10 +- pages/o/[organization-slug]/index.client.vue | 17 +- .../new-solution.client.vue | 14 +- pages/o/[organization-slug]/users.vue | 120 +- plugins/eventBus.ts | 14 + public/congruent_outline.png | Bin 0 -> 268427 bytes seeders/AppRoleSeeder.ts | 17 - seeders/AppUserSeeder.ts | 24 +- server/api/approles/[id].delete.ts | 31 - server/api/approles/[id].get.ts | 27 - server/api/approles/index.get.ts | 39 - server/api/approles/index.post.ts | 45 - .../index.delete.ts | 76 - .../appuser-organization-roles/index.get.ts | 56 - .../appuser-organization-roles/index.post.ts | 76 - server/api/appusers/[id].delete.ts | 63 +- server/api/appusers/[id].get.ts | 49 +- server/api/appusers/[id].put.ts | 71 +- server/api/appusers/index.get.ts | 68 +- server/api/appusers/index.post.ts | 77 +- server/api/auth/[...].ts | 88 +- server/api/organizations/[id].delete.ts | 12 +- server/api/organizations/[id].get.ts | 15 +- server/api/organizations/[id].put.ts | 19 +- server/api/organizations/index.get.ts | 16 +- server/api/organizations/index.post.ts | 16 +- server/api/solutions/[id].delete.ts | 13 +- server/api/solutions/[id].get.ts | 12 +- server/api/solutions/[id].put.ts | 23 +- server/api/solutions/index.get.ts | 17 +- server/api/solutions/index.post.ts | 19 +- server/data/models/AppRoleSchema.ts | 9 - .../models/AppUserOrganizationRoleSchema.ts | 10 +- server/data/models/AppUserSchema.ts | 7 +- server/domain/application/AppRole.ts | 17 +- server/domain/application/AppUser.ts | 17 +- .../application/AppUserOrganizationRole.ts | 10 +- server/domain/application/Organization.ts | 2 +- server/domain/application/Solution.ts | 2 +- server/middleware/auth.ts | 14 +- {lib => utils}/deSlugify.ts | 0 {lib => utils}/debounce.ts | 2 +- {lib => utils}/slugify.ts | 0 83 files changed, 11984 insertions(+), 10386 deletions(-) create mode 100644 error.vue delete mode 100644 lib/reCamelCaseToSnakeCase.ts delete mode 100644 lib/reSnakeCaseToCamelCase.ts create mode 100644 migrations/Migration20240808202308.ts create mode 100644 plugins/eventBus.ts create mode 100644 public/congruent_outline.png delete mode 100644 seeders/AppRoleSeeder.ts delete mode 100644 server/api/approles/[id].delete.ts delete mode 100644 server/api/approles/[id].get.ts delete mode 100644 server/api/approles/index.get.ts delete mode 100644 server/api/approles/index.post.ts delete mode 100644 server/api/appuser-organization-roles/index.delete.ts delete mode 100644 server/api/appuser-organization-roles/index.get.ts delete mode 100644 server/api/appuser-organization-roles/index.post.ts delete mode 100644 server/data/models/AppRoleSchema.ts rename {lib => utils}/deSlugify.ts (100%) rename {lib => utils}/debounce.ts (85%) rename {lib => utils}/slugify.ts (100%) diff --git a/.env.example b/.env.example index b4172c52..d63fc3ca 100644 --- a/.env.example +++ b/.env.example @@ -1,15 +1,15 @@ NODE_TLS_REJECT_UNAUTHORIZED=0 +NODE_ENV=development +NUXT_ORIGIN: https://localhost:3000 POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_HOST: db POSTGRES_PORT: 5432 POSTGRES_DB: cathedral -GH_CLIENT_ID: Ov23lij8q5YhcosEjIzQ -GH_CLIENT_SECRET: 27c98b69344086c13bc15290e1a8b8c86a910d58 -AUTH_SECRET: e792b76a-2573-45d4-a39b-3b8db5712f9c -AUTH_ORIGIN: https://localhost:3000 -# SLACK_ADMIN_MEMBER_ID: *** -# SLACK_BOT_TOKEN: *** -# SLACK_SIGNING_SECRET: *** -# APPLICATIONINSIGHTS_CONNECTION_STRING: *** -# APPINSIGHTS_INSTRUMENTATIONKEY: *** \ No newline at end of file +NUXT_SESSION_PASSWORD: ###generate a random string### +NUXT_AUTH_CLIENT_ID: ###contact the team for the client id### +NUXT_AUTH_CLIENT_SECRET: ###contact the team for the client secret### +NUXT_AUTH_TENANT_NAME: cathedralfinalhillb2c +NUXT_AUTH_TENANT_ID: ###contact the team for the tenant id### +NUXT_AUTH_AUTHORITY_DOMAIN: cathedralfinalhillb2c.b2clogin.com +NUXT_AUTH_PRIMARY_USER_FLOW: B2C_1_signupsignin2 \ No newline at end of file diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml index a4768b68..a78b7dac 100644 --- a/.github/workflows/azure-deploy.yml +++ b/.github/workflows/azure-deploy.yml @@ -33,8 +33,6 @@ jobs: resourceGroupName: ${{ secrets.AZURE_RG }} template: ./azure/bicep/main.bicep parameters: > - authOrigin=${{ secrets.AUTH_ORIGIN }} - authSecret=${{ secrets.AUTH_SECRET }} ghClientId=${{ secrets.GH_CLIENT_ID }} ghClientSecret=${{ secrets.GH_CLIENT_SECRET }} postgresDb=${{ secrets.POSTGRES_DB }} @@ -81,10 +79,15 @@ jobs: echo "POSTGRES_HOST=${{secrets.POSTGRES_HOST}}" >> .env echo "POSTGRES_PORT=${{secrets.POSTGRES_PORT}}" >> .env echo "POSTGRES_DB=${{secrets.POSTGRES_DB}}" >> .env - echo "GH_CLIENT_ID=${{secrets.GH_CLIENT_ID}}" >> .env - echo "GH_CLIENT_SECRET=${{secrets.GH_CLIENT_SECRET}}" >> .env - echo "AUTH_SECRET=${{secrets.AUTH_SECRET}}" >> .env - echo "AUTH_ORIGIN=${{secrets.AUTH_ORIGIN}}" >> .env + echo "NODE_ENV=production" >> .env + echo "NUXT_ORIGIN=${{secrets.NUXT_ORIGIN}}" >> .env + echo "NUXT_SESSION_PASSWORD=${{secrets.NUXT_SESSION_PASSWORD}}" >> .env + echo "NUXT_AUTH_CLIENT_ID=${{secrets.NUXT_AUTH_CLIENT_ID}}" >> .env + echo "NUXT_AUTH_CLIENT_SECRET=${{secrets.NUXT_AUTH_CLIENT_SECRET}}" >> .env + echo "NUXT_AUTH_TENANT_NAME=${{secrets.NUXT_AUTH_TENANT_NAME}}" >> .env + echo "NUXT_AUTH_TENANT_ID=${{secrets.NUXT_AUTH_TENANT_ID}}" >> .env + echo "NUXT_AUTH_AUTHORITY_DOMAIN=${{secrets.NUXT_AUTH_AUTHORITY_DOMAIN}}" >> .env + echo "NUXT_AUTH_PRIMARY_USER_FLOW=${{secrets.NUXT_AUTH_PRIMARY_USER_FLOW}}" >> .env echo "SLACK_ADMIN_MEMBER_ID=${{secrets.SLACK_ADMIN_MEMBER_ID}}" >> .env echo "SLACK_BOT_TOKEN=${{secrets.SLACK_BOT_TOKEN}}" >> .env echo "SLACK_SIGNING_SECRET=${{secrets.SLACK_SIGNING_SECRET}}" >> .env @@ -121,8 +124,6 @@ jobs: template: ./azure/bicep/main.bicep deploymentMode: 'Incremental' parameters: > - authOrigin=${{ secrets.AUTH_ORIGIN }} - authSecret=${{ secrets.AUTH_SECRET }} ghClientId=${{ secrets.GH_CLIENT_ID }} ghClientSecret=${{ secrets.GH_CLIENT_SECRET }} postgresDb=${{ secrets.POSTGRES_DB }} @@ -189,10 +190,18 @@ jobs: echo "POSTGRES_HOST=${{secrets.POSTGRES_HOST}}" >> .env echo "POSTGRES_PORT=${{secrets.POSTGRES_PORT}}" >> .env echo "POSTGRES_DB=${{secrets.POSTGRES_DB}}" >> .env - echo "GH_CLIENT_ID=${{secrets.GH_CLIENT_ID}}" >> .env - echo "GH_CLIENT_SECRET=${{secrets.GH_CLIENT_SECRET}}" >> .env - echo "AUTH_SECRET=${{secrets.AUTH_SECRET}}" >> .env - echo "AUTH_ORIGIN=${{secrets.AUTH_ORIGIN}}" >> .env + echo "NODE_ENV=production" >> .env + echo "NUXT_ORIGIN=${{secrets.NUXT_ORIGIN}}" >> .env + echo "NUXT_SESSION_PASSWORD=${{secrets.NUXT_SESSION_PASSWORD}}" >> .env + echo "NUXT_AUTH_CLIENT_ID=${{secrets.NUXT_AUTH_CLIENT_ID}}" >> .env + echo "NUXT_AUTH_CLIENT_SECRET=${{secrets.NUXT_AUTH_CLIENT_SECRET}}" >> .env + echo "NUXT_AUTH_TENANT_NAME=${{secrets.NUXT_AUTH_TENANT_NAME}}" >> .env + echo "NUXT_AUTH_TENANT_ID=${{secrets.NUXT_AUTH_TENANT_ID}}" >> .env + echo "NUXT_AUTH_AUTHORITY_DOMAIN=${{secrets.NUXT_AUTH_AUTHORITY_DOMAIN}}" >> .env + echo "NUXT_AUTH_PRIMARY_USER_FLOW=${{secrets.NUXT_AUTH_PRIMARY_USER_FLOW}}" >> .env + echo "SLACK_ADMIN_MEMBER_ID=${{secrets.SLACK_ADMIN_MEMBER_ID}}" >> .env + echo "SLACK_BOT_TOKEN=${{secrets.SLACK_BOT_TOKEN}}" >> .env + echo "SLACK_SIGNING_SECRET=${{secrets.SLACK_SIGNING_SECRET}}" >> .env - name: Login to Azure uses: azure/login@v2 with: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb83a6b8..70b0862d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,8 +46,7 @@ The application is built using the following primary technologies: - [PrimeVue](https://primevue.org/) - [PrimeFlex](https://primeflex.org/) - [Zod](https://zod.dev/) -- [Nuxt Auth](https://auth.sidebase.io/) - - Which may be replaced by a native Nuxt.js feature in the future (Nuxt 5?) +- [@azure/msal-node](https://www.npmjs.com/package/@azure/msal-node) - [Node.js](http://nodejs.org/) - [MikroORM](https://mikro-orm.io/) - [PostgreSQL](https://www.postgresql.org/) diff --git a/azure/bicep/main.bicep b/azure/bicep/main.bicep index d01f2e98..cd95b5ac 100644 --- a/azure/bicep/main.bicep +++ b/azure/bicep/main.bicep @@ -7,10 +7,6 @@ param location string = resourceGroup().location @maxLength(22) param name string = 'cathedral' -@secure() -param authOrigin string -@secure() -param authSecret string @secure() param ghClientId string @secure() @@ -60,8 +56,6 @@ module appService './modules/appService.bicep' = { appInsightsInstrumentationKey: appInsights.outputs.appInsightsInstrumentationKey appInsightsConnectionString: appInsights.outputs.appInsightsConnectionString name: name - authOrigin: authOrigin - authSecret: authSecret ghClientId: ghClientId ghClientSecret: ghClientSecret postgresDb: postgresDb diff --git a/azure/bicep/modules/appService.bicep b/azure/bicep/modules/appService.bicep index de8ed526..b76e68dd 100644 --- a/azure/bicep/modules/appService.bicep +++ b/azure/bicep/modules/appService.bicep @@ -4,10 +4,6 @@ param appInsightsInstrumentationKey string @secure() param appInsightsConnectionString string @secure() -param authOrigin string -@secure() -param authSecret string -@secure() param ghClientId string @secure() param ghClientSecret string @@ -90,14 +86,6 @@ resource appService 'Microsoft.Web/sites@2023-12-01' = { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' value: appInsightsConnectionString } - { - name: 'AUTH_ORIGIN' - value: authOrigin - } - { - name: 'AUTH_SECRET' - value: authSecret - } { name: 'GH_CLIENT_ID' value: ghClientId diff --git a/components/TopNavigation.vue b/components/TopNavigation.vue index d30a50e6..03a02c48 100644 --- a/components/TopNavigation.vue +++ b/components/TopNavigation.vue @@ -1,7 +1,6 @@ -

{{ data?.user?.name }}

- {{ data?.user?.email }} +

{{ data?.name }}

+ {{ data?.email }}