generator-jhipster 7.2.0 → 7.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/environment-builder.js +1 -0
- package/cli/import-jdl.js +3 -2
- package/cli/jdl.js +1 -0
- package/cli/jhipster-command.js +2 -2
- package/cli/program.js +32 -29
- package/generators/app/index.js +35 -26
- package/generators/aws/index.js +8 -8
- package/generators/aws/lib/eb.js +1 -1
- package/generators/azure-app-service/index.js +16 -9
- package/generators/azure-app-service/templates/github/workflows/azure-app-service.yml.ejs +2 -2
- package/generators/azure-spring-cloud/index.js +16 -9
- package/generators/azure-spring-cloud/templates/github/workflows/azure-spring-cloud.yml.ejs +2 -2
- package/generators/bootstrap/index.js +57 -61
- package/generators/ci-cd/index.js +11 -8
- package/generators/ci-cd/templates/github-actions.yml.ejs +1 -1
- package/generators/ci-cd/templates/travis.yml.ejs +9 -4
- package/generators/client/__workflow/devserver-angular.json +1 -1
- package/generators/client/__workflow/devserver-react.json +1 -1
- package/generators/client/__workflow/devserver-vue.json +1 -1
- package/generators/client/files-angular.js +6 -0
- package/generators/client/files-common.js +6 -2
- package/generators/client/files-react.js +13 -2
- package/generators/client/files-vue.js +56 -6
- package/generators/client/index.js +114 -32
- package/generators/client/needle-api/needle-client-angular.js +1 -1
- package/generators/client/needle-api/needle-client-vue.js +57 -7
- package/generators/client/templates/angular/.eslintrc.json.ejs +1 -0
- package/generators/client/templates/angular/package.json +19 -19
- package/generators/client/templates/angular/package.json.ejs +2 -1
- package/generators/client/templates/angular/src/main/webapp/app/account/activate/activate.component.spec.ts.ejs +52 -54
- package/generators/client/templates/angular/src/main/webapp/app/account/activate/activate.service.spec.ts.ejs +65 -0
- package/generators/client/templates/angular/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.spec.ts.ejs +35 -37
- package/generators/client/templates/angular/src/main/webapp/app/account/password/password.component.spec.ts.ejs +78 -80
- package/generators/client/templates/angular/src/main/webapp/app/account/password/password.service.spec.ts.ejs +41 -0
- package/generators/client/templates/angular/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.spec.ts.ejs +73 -75
- package/generators/client/templates/angular/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.spec.ts.ejs +62 -0
- package/generators/client/templates/angular/src/main/webapp/app/account/password-reset/init/password-reset-init.component.spec.ts.ejs +44 -46
- package/generators/client/templates/angular/src/main/webapp/app/account/password-reset/init/password-reset-init.service.spec.ts.ejs +61 -0
- package/generators/client/templates/angular/src/main/webapp/app/account/register/register.component.spec.ts.ejs +116 -118
- package/generators/client/templates/angular/src/main/webapp/app/account/register/register.service.spec.ts.ejs +66 -0
- package/generators/client/templates/angular/src/main/webapp/app/account/sessions/sessions.component.spec.ts.ejs +75 -77
- package/generators/client/templates/angular/src/main/webapp/app/account/settings/settings.component.spec.ts.ejs +74 -76
- package/generators/client/templates/angular/src/main/webapp/app/admin/configuration/configuration.component.spec.ts.ejs +48 -50
- package/generators/client/templates/angular/src/main/webapp/app/admin/configuration/configuration.service.spec.ts.ejs +50 -52
- package/generators/client/templates/angular/src/main/webapp/app/admin/health/health.component.spec.ts.ejs +45 -47
- package/generators/client/templates/angular/src/main/webapp/app/admin/health/health.service.spec.ts.ejs +66 -0
- package/generators/client/templates/angular/src/main/webapp/app/admin/health/modal/health-modal.component.spec.ts.ejs +99 -101
- package/generators/client/templates/angular/src/main/webapp/app/admin/logs/logs.component.spec.ts.ejs +61 -63
- package/generators/client/templates/angular/src/main/webapp/app/admin/logs/logs.service.spec.ts.ejs +19 -21
- package/generators/client/templates/angular/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.html.ejs +2 -2
- package/generators/client/templates/angular/src/main/webapp/app/admin/metrics/metrics.component.spec.ts.ejs +28 -30
- package/generators/client/templates/angular/src/main/webapp/app/admin/metrics/metrics.service.spec.ts.ejs +62 -64
- package/generators/client/templates/angular/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.spec.ts.ejs +35 -37
- package/generators/client/templates/angular/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts.ejs +40 -42
- package/generators/client/templates/angular/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts.ejs +87 -89
- package/generators/client/templates/angular/src/main/webapp/app/admin/user-management/service/user-management.service.spec.ts.ejs +41 -43
- package/generators/client/templates/angular/src/main/webapp/app/admin/user-management/update/user-management-update.component.spec.ts.ejs +81 -83
- package/generators/client/templates/angular/src/main/webapp/app/app.module.ts.ejs +3 -0
- package/generators/client/templates/angular/src/main/webapp/app/core/auth/account.service.spec.ts.ejs +178 -180
- package/generators/client/templates/angular/src/main/webapp/app/core/config/application-config.service.ts.ejs +9 -0
- package/generators/client/templates/angular/src/main/webapp/app/entities/user/user.service.spec.ts.ejs +87 -89
- package/generators/client/templates/angular/src/main/webapp/app/home/home.component.spec.ts.ejs +93 -95
- package/generators/client/templates/angular/src/main/webapp/app/layouts/main/main.component.spec.ts.ejs +166 -168
- package/generators/client/templates/angular/src/main/webapp/app/layouts/navbar/navbar.component.spec.ts.ejs +66 -68
- package/generators/client/templates/angular/src/main/webapp/app/layouts/profiles/page-ribbon.component.spec.ts.ejs +27 -29
- package/generators/client/templates/angular/src/main/webapp/app/login/login.component.spec.ts.ejs +112 -114
- package/generators/client/templates/angular/src/main/webapp/app/shared/alert/alert-error.component.spec.ts.ejs +132 -134
- package/generators/client/templates/angular/src/main/webapp/app/shared/alert/alert.component.spec.ts.ejs +29 -31
- package/generators/client/templates/angular/webpack/webpack.custom.js.ejs +2 -3
- package/generators/client/templates/common/README.md.jhi.client.ejs +34 -0
- package/generators/client/templates/common/package.json +7 -7
- package/generators/client/templates/common/webpack/webpack.microfrontend.js.jhi.ejs +56 -0
- package/generators/client/templates/react/.eslintrc.json.ejs +1 -0
- package/generators/client/templates/react/package.json +57 -56
- package/generators/client/templates/react/package.json.ejs +5 -2
- package/generators/client/templates/react/src/main/webapp/app/app.scss.ejs +0 -3
- package/generators/client/templates/react/src/main/webapp/app/modules/account/password/password.tsx.ejs +2 -2
- package/generators/client/templates/react/src/main/webapp/app/modules/administration/configuration/configuration.tsx.ejs +2 -2
- package/generators/client/templates/react/src/main/webapp/app/modules/administration/gateway/gateway.tsx.ejs +2 -2
- package/generators/client/templates/react/src/main/webapp/app/modules/administration/metrics/metrics.tsx.ejs +6 -6
- package/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management.tsx.ejs +8 -8
- package/generators/client/templates/react/src/main/webapp/app/modules/home/home.tsx.ejs +1 -1
- package/generators/client/templates/react/src/main/webapp/app/shared/layout/header/header.tsx.ejs +1 -1
- package/generators/client/templates/react/src/main/webapp/app/shared/layout/menus/account.tsx.ejs +3 -3
- package/generators/client/templates/react/src/main/webapp/app/shared/layout/menus/admin.tsx.ejs +7 -7
- package/generators/client/templates/react/src/main/webapp/app/shared/layout/menus/menu-components.tsx.ejs +1 -1
- package/generators/client/templates/react/webpack/webpack.dev.js.ejs +17 -1
- package/generators/client/templates/react/webpack/webpack.prod.js.ejs +13 -1
- package/generators/client/templates/vue/.eslintrc.js.ejs +8 -5
- package/generators/client/templates/vue/package.json +40 -49
- package/generators/client/templates/vue/package.json.ejs +14 -18
- package/generators/client/templates/vue/src/main/webapp/app/account/account.service.ts.ejs +6 -5
- package/generators/client/templates/vue/src/main/webapp/app/account/settings/settings.vue.ejs +7 -1
- package/generators/client/templates/vue/src/main/webapp/app/admin/configuration/configuration.service.ts.ejs +1 -1
- package/generators/client/templates/vue/src/main/webapp/app/admin/configuration/configuration.vue.ejs +1 -1
- package/generators/client/templates/vue/src/main/webapp/app/admin/metrics/metrics.component.ts.ejs +1 -1
- package/generators/client/templates/vue/src/main/webapp/app/admin/tracker/tracker.service.ts.ejs +5 -4
- package/generators/client/templates/vue/src/main/webapp/app/admin/user-management/user-management-edit.component.ts.ejs +9 -0
- package/generators/client/templates/vue/src/main/webapp/app/admin/user-management/user-management-view.component.ts.ejs +5 -0
- package/generators/client/templates/vue/src/main/webapp/app/admin/user-management/user-management.component.ts.ejs +5 -0
- package/generators/client/templates/vue/src/main/webapp/app/constants.ts.ejs +16 -6
- package/generators/client/templates/vue/src/main/webapp/app/core/jhi-navbar/jhi-navbar.component.ts.ejs +27 -8
- package/generators/client/templates/vue/src/main/webapp/app/core/jhi-navbar/jhi-navbar.vue.ejs +6 -0
- package/generators/client/templates/vue/src/main/webapp/app/declarations.d.ts.ejs +41 -0
- package/generators/client/templates/vue/src/main/webapp/app/entities/entities-menu.component.ts.ejs +34 -0
- package/generators/client/templates/vue/src/main/webapp/app/entities/entities-menu.vue.ejs +13 -0
- package/generators/client/templates/vue/src/main/webapp/app/entities/entities.component.ts.ejs +14 -0
- package/generators/client/templates/vue/src/main/webapp/app/entities/entities.vue.ejs +5 -0
- package/generators/client/templates/vue/{webpack/utils.js.ejs → src/main/webapp/app/index.ts.ejs} +1 -12
- package/generators/client/templates/vue/src/main/webapp/app/locale/translation.service.ts.ejs +26 -9
- package/generators/client/templates/vue/src/main/webapp/app/main.ts.ejs +23 -11
- package/generators/client/templates/vue/src/main/webapp/app/router/admin.ts.ejs +4 -4
- package/generators/client/templates/vue/src/main/webapp/app/router/entities.ts.ejs +45 -3
- package/generators/client/templates/vue/src/main/webapp/app/router/index.ts.ejs +19 -3
- package/generators/client/templates/vue/src/main/webapp/app/shared/alert/alert.service.ts.ejs +61 -0
- package/generators/client/templates/vue/src/main/webapp/app/shared/config/axios-interceptor.ts.ejs +0 -2
- package/generators/client/templates/vue/src/main/webapp/app/shared/data/data-utils.service.ts.ejs +3 -1
- package/generators/client/templates/vue/src/main/webapp/app/shims-vue.d.ts.ejs +17 -3
- package/generators/client/templates/vue/src/test/javascript/jest.conf.js.ejs +25 -10
- package/generators/client/templates/vue/src/test/javascript/spec/app/account/account.service.spec.ts.ejs +2 -2
- package/generators/client/templates/vue/src/test/javascript/spec/app/account/login-form/login-form.component.spec.ts.ejs +2 -2
- package/generators/client/templates/vue/src/test/javascript/spec/app/admin/tracker/tracker.component.spec.ts.ejs +12 -12
- package/generators/client/templates/vue/src/test/javascript/spec/app/admin/tracker/tracker.service.spec.ts.ejs +2 -1
- package/generators/client/templates/vue/src/test/javascript/spec/app/admin/user-management/user-management-edit.component.spec.ts.ejs +5 -1
- package/generators/client/templates/vue/src/test/javascript/spec/app/admin/user-management/user-management-view.component.spec.ts.ejs +2 -1
- package/generators/client/templates/vue/src/test/javascript/spec/app/admin/user-management/user-management.component.spec.ts.ejs +5 -1
- package/generators/client/templates/vue/src/test/javascript/spec/app/core/jhi-navbar/jhi-navbar.component.spec.ts.ejs +10 -4
- package/generators/client/templates/vue/src/test/javascript/spec/app/entities/entities-menu.spec.ts.ejs +52 -0
- package/generators/client/templates/vue/src/test/javascript/spec/app/microfrontends/entities-menu.component.ts.ejs +4 -0
- package/generators/client/templates/vue/src/test/javascript/spec/app/microfrontends/entities-menu.vue.ejs +7 -0
- package/generators/client/templates/vue/src/test/javascript/spec/app/microfrontends/entities-router.ts.ejs +1 -0
- package/generators/client/templates/vue/src/test/javascript/spec/app/shared/alert/alert.service.spec.ts.ejs +124 -0
- package/generators/client/templates/vue/src/test/javascript/spec/app/shared/config/axios-interceptor.spec.ts.ejs +0 -1
- package/generators/client/templates/vue/tsconfig.json.ejs +6 -10
- package/generators/client/templates/vue/tsconfig.spec.json.ejs +37 -0
- package/generators/client/templates/vue/webpack/config.js.ejs +50 -0
- package/generators/client/templates/vue/webpack/vue.utils.js.ejs +33 -32
- package/generators/client/templates/vue/webpack/webpack.common.js.ejs +152 -126
- package/generators/client/templates/vue/webpack/webpack.dev.js.ejs +19 -76
- package/generators/client/templates/vue/webpack/webpack.microfrontend.js.jhi.vue.ejs +77 -0
- package/generators/client/templates/vue/webpack/webpack.prod.js.ejs +5 -41
- package/generators/cloudfoundry/index.js +9 -9
- package/generators/common/index.js +12 -10
- package/generators/common/templates/.husky/pre-commit +1 -1
- package/generators/common/templates/.prettierrc.ejs +1 -1
- package/generators/common/templates/README.md.jhi.ejs +21 -0
- package/generators/common/templates/package.json +4 -4
- package/generators/cypress/index.js +12 -9
- package/generators/cypress/templates/cypress.json.ejs +9 -2
- package/generators/cypress/templates/src/test/javascript/cypress/plugins/index.ts.ejs +4 -4
- package/generators/cypress/templates/src/test/javascript/cypress/support/commands.ts.ejs +30 -2
- package/generators/cypress/templates/src/test/javascript/cypress/support/entity.ts.ejs +4 -4
- package/generators/cypress/templates/src/test/javascript/cypress/support/index.ts.ejs +1 -1
- package/generators/cypress/templates/src/test/javascript/cypress/support/management.ts.ejs +1 -1
- package/generators/cypress/templates/src/test/javascript/cypress/support/navbar.ts.ejs +1 -1
- package/generators/database-changelog/index.js +33 -22
- package/generators/database-changelog-liquibase/index.js +12 -8
- package/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/updated_entity_constraints.xml.ejs +1 -1
- package/generators/docker-compose/index.js +11 -12
- package/generators/docker-compose/templates/realm-config/jhipster-realm.json.ejs +13 -12
- package/generators/entities/index.js +35 -26
- package/generators/entities-client/index.js +10 -7
- package/generators/entity/index.js +49 -29
- package/generators/entity-client/files.js +7 -16
- package/generators/entity-client/index.js +74 -11
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/delete/entity-management-delete-dialog.component.spec.ts.ejs +42 -44
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/detail/entity-management-detail.component.spec.ts.ejs +58 -60
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management.module.ts.ejs +1 -1
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.spec.ts.ejs +105 -107
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.ts.ejs +8 -1
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing-resolve.service.spec.ts.ejs +52 -54
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing.module.ts.ejs +1 -1
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/service/entity.service.spec.ts.ejs +173 -175
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.html.ejs +2 -4
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.spec.ts.ejs +193 -195
- package/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.ts.ejs +7 -0
- package/generators/entity-client/templates/common/src/test/javascript/cypress/integration/entity/entity.spec.ts.ejs +269 -109
- package/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-delete-dialog.tsx.ejs +5 -2
- package/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-update.tsx.ejs +17 -14
- package/generators/entity-client/templates/react/src/main/webapp/app/entities/entity.tsx.ejs +11 -13
- package/generators/entity-client/templates/vue/src/main/webapp/app/entities/entity-details.component.ts.ejs +5 -0
- package/generators/entity-client/templates/vue/src/main/webapp/app/entities/entity-update.component.ts.ejs +23 -8
- package/generators/entity-client/templates/vue/src/main/webapp/app/entities/entity-update.vue.ejs +6 -9
- package/generators/entity-client/templates/vue/src/main/webapp/app/entities/entity.component.ts.ejs +9 -1
- package/generators/entity-client/templates/vue/src/main/webapp/app/entities/entity.model.ts.ejs +1 -1
- package/generators/entity-client/templates/vue/src/main/webapp/app/entities/entity.service.ts.ejs +2 -6
- package/generators/entity-client/templates/vue/src/test/javascript/spec/app/entities/entity-details.component.spec.ts.ejs +2 -1
- package/generators/entity-client/templates/vue/src/test/javascript/spec/app/entities/entity-update.component.spec.ts.ejs +8 -1
- package/generators/entity-client/templates/vue/src/test/javascript/spec/app/entities/entity.component.spec.ts.ejs +8 -2
- package/generators/entity-client/templates/vue/src/test/javascript/spec/app/entities/entity.service.spec.ts.ejs +1 -1
- package/generators/entity-i18n/index.js +7 -4
- package/generators/entity-server/files-couchbase.js +2 -2
- package/generators/entity-server/files.js +35 -30
- package/generators/entity-server/index.js +12 -8
- package/generators/entity-server/templates/couchbase/src/main/java/package/repository/EntityRepository.java.ejs +2 -2
- package/generators/entity-server/templates/couchbase/src/main/resources/config/couchmove/changelog/entity.fts.ejs +1 -1
- package/generators/entity-server/templates/src/main/java/package/domain/Entity.java.jhi.ejs +6 -2
- package/generators/entity-server/templates/src/main/java/package/domain/enumeration/Enum.java.ejs +1 -1
- package/generators/entity-server/templates/src/main/java/package/repository/EntityRepository.java.ejs +2 -2
- package/generators/entity-server/templates/src/main/java/package/repository/EntityRepositoryInternalImpl_reactive.java.ejs +17 -30
- package/generators/entity-server/templates/src/main/java/package/repository/EntityRepository_reactive.java.ejs +5 -5
- package/generators/entity-server/templates/src/main/java/package/repository/EntitySqlHelper_reactive.java.ejs +46 -0
- package/generators/entity-server/templates/src/main/java/package/repository/rowmapper/EntityRowMapper.java.ejs +3 -3
- package/generators/entity-server/templates/src/main/java/package/repository/search/EntitySearchRepository.java.ejs +2 -2
- package/generators/entity-server/templates/src/main/java/package/service/EntityQueryService.java.ejs +8 -8
- package/generators/entity-server/templates/src/main/java/package/service/EntityService.java.ejs +4 -4
- package/generators/entity-server/templates/src/main/java/package/service/criteria/EntityCriteria.java.ejs +4 -4
- package/generators/entity-server/templates/src/main/java/package/service/dto/EntityDTO.java.ejs +7 -3
- package/generators/entity-server/templates/src/main/java/package/service/impl/EntityServiceImpl.java.ejs +8 -8
- package/generators/entity-server/templates/src/main/java/package/service/mapper/BaseEntityMapper.java.ejs +1 -1
- package/generators/entity-server/templates/src/main/java/package/service/mapper/EntityMapper.java.ejs +7 -3
- package/generators/entity-server/templates/src/main/java/package/web/rest/EntityResource.java.ejs +51 -53
- package/generators/entity-server/templates/src/test/java/package/domain/EntityTest.java.ejs +1 -1
- package/generators/entity-server/templates/src/test/java/package/repository/search/EntitySearchRepositoryMockConfiguration.java.ejs +1 -1
- package/generators/entity-server/templates/src/test/java/package/service/dto/EntityDTOTest.java.ejs +1 -1
- package/generators/entity-server/templates/src/test/java/package/service/mapper/EntityMapperTest.java.ejs +1 -1
- package/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIT.java.ejs +17 -14
- package/generators/gae/index.js +10 -10
- package/generators/generator-base-blueprint.js +14 -46
- package/generators/generator-base-private.js +42 -22
- package/generators/generator-base.js +57 -20
- package/generators/generator-constants.js +29 -21
- package/generators/generator-transforms.js +39 -27
- package/generators/heroku/index.js +27 -48
- package/generators/init/constants.cjs +1 -1
- package/generators/init/templates/.husky/pre-commit +1 -1
- package/generators/java/constants.cjs +1 -1
- package/generators/kubernetes/files.js +3 -0
- package/generators/kubernetes/index.js +10 -10
- package/generators/kubernetes/templates/db/couchbase.yml.ejs +1 -1
- package/generators/kubernetes/templates/deployment.yml.ejs +8 -3
- package/generators/kubernetes/templates/istio/destination-rule.yml.ejs +1 -1
- package/generators/kubernetes/templates/istio/gateway/grafana-gateway.yml.ejs +5 -2
- package/generators/kubernetes/templates/istio/gateway/jhipster-grafana-gateway.yml.ejs +5 -2
- package/generators/kubernetes/templates/istio/gateway/kiali-gateway.yml.ejs +10 -8
- package/generators/kubernetes/templates/istio/gateway/zipkin-gateway.yml.ejs +5 -2
- package/generators/kubernetes/templates/istio/gateway.yml.ejs +7 -5
- package/generators/kubernetes/templates/secret/couchbase-secret.yml.ejs +9 -0
- package/generators/kubernetes-base.js +1 -0
- package/generators/kubernetes-helm/files.js +3 -8
- package/generators/kubernetes-helm/index.js +10 -10
- package/generators/kubernetes-helm/templates/README-KUBERNETES-HELM.md.ejs +0 -1
- package/generators/kubernetes-helm/templates/app/Chart.yml.ejs +27 -0
- package/generators/kubernetes-helm/templates/app/helpers.tpl.ejs +0 -11
- package/generators/kubernetes-helm/templates/app/requirements.yml.ejs +7 -2
- package/generators/kubernetes-helm/templates/app/values.yml.ejs +68 -5
- package/generators/kubernetes-helm/templates/csvc/Chart.yml.ejs +17 -0
- package/generators/kubernetes-helm/templates/csvc/requirements.yml.ejs +2 -2
- package/generators/kubernetes-knative/index.js +10 -10
- package/generators/kubernetes-knative/templates/istio/gateway.yml.ejs +6 -4
- package/generators/kubernetes-knative/templates/service.yml.ejs +1 -1
- package/generators/languages/index.js +13 -13
- package/generators/languages/templates/src/main/webapp/i18n/hr/reset.json.ejs +1 -2
- package/generators/languages/templates/src/main/webapp/i18n/vi/login.json +1 -1
- package/generators/maven/templates/.mvn/wrapper/maven-wrapper.properties +1 -1
- package/generators/openapi-client/index.js +13 -10
- package/generators/openshift/index.js +10 -11
- package/generators/openshift/templates/deployment.yml.ejs +1 -1
- package/generators/page/index.js +12 -10
- package/generators/server/__snapshots__/generator.spec.mjs.snap +12 -0
- package/generators/server/files-sql.js +52 -0
- package/generators/server/files.js +15 -0
- package/generators/server/index.js +100 -33
- package/generators/server/needle-api/needle-server-cache.js +4 -6
- package/generators/server/templates/.mvn/wrapper/maven-wrapper.properties +1 -1
- package/generators/server/templates/build.gradle.ejs +17 -1
- package/generators/server/templates/gradle.properties.ejs +11 -11
- package/generators/server/templates/npmw +1 -1
- package/generators/server/templates/npmw.cmd +1 -1
- package/generators/server/templates/pom.xml.ejs +128 -9
- package/generators/server/templates/settings.gradle.ejs +9 -0
- package/generators/server/templates/sql/reactive/src/main/java/package/repository/UserSqlHelper.java.ejs +48 -0
- package/generators/server/templates/src/main/docker/app.yml.ejs +2 -1
- package/generators/server/templates/src/main/docker/config/realm-config/jhipster-realm.json.ejs +13 -12
- package/generators/server/templates/src/main/java/package/aop/logging/LoggingAspect.java.ejs +1 -1
- package/generators/server/templates/src/main/java/package/config/DatabaseConfiguration_cassandra.java.ejs +0 -6
- package/generators/server/templates/src/main/java/package/config/DatabaseConfiguration_sql.java.ejs +2 -2
- package/generators/server/templates/src/main/java/package/config/JacksonConfiguration.java.ejs +1 -1
- package/generators/server/templates/src/main/java/package/config/LocaleConfiguration.java.ejs +0 -2
- package/generators/server/templates/src/main/java/package/config/SecurityConfiguration.java.ejs +2 -5
- package/generators/server/templates/src/main/java/package/config/SecurityConfiguration_reactive.java.ejs +9 -1
- package/generators/server/templates/src/main/java/package/config/WebConfigurer.java.ejs +0 -1
- package/generators/server/templates/src/main/java/package/management/SecurityMetersService.java.ejs +68 -0
- package/generators/server/templates/src/main/java/package/repository/UserRepository.java.ejs +0 -23
- package/generators/server/templates/src/main/java/package/security/PersistentTokenRememberMeServices.java.ejs +0 -2
- package/generators/server/templates/src/main/java/package/security/jwt/TokenProvider.java.ejs +29 -4
- package/generators/server/templates/src/main/java/package/security/oauth2/CustomClaimConverter.java.ejs +21 -9
- package/generators/server/templates/src/main/java/package/service/UserService.java.ejs +13 -5
- package/generators/server/templates/src/main/resources/config/application-dev.yml.ejs +1 -1
- package/generators/server/templates/src/main/resources/config/application-prod.yml.ejs +1 -1
- package/generators/server/templates/src/main/resources/config/application.yml.ejs +7 -7
- package/generators/server/templates/src/main/resources/static/microservices_index.html.ejs +1 -1
- package/generators/server/templates/src/test/java/package/management/SecurityMetersServiceTests.java.ejs +113 -0
- package/generators/server/templates/src/test/java/package/security/jwt/JWTFilterTest.java.ejs +6 -1
- package/generators/server/templates/src/test/java/package/security/jwt/TokenProviderSecurityMetersTests.java.ejs +198 -0
- package/generators/server/templates/src/test/java/package/security/jwt/TokenProviderTest.java.ejs +13 -3
- package/generators/server/templates/src/test/java/package/security/oauth2/AuthorizationHeaderUtilTest.java.ejs +16 -2
- package/generators/server/templates/src/test/java/package/security/oauth2/CustomClaimConverterIT.java.ejs +63 -0
- package/generators/spring-controller/index.js +9 -7
- package/generators/spring-service/index.js +10 -7
- package/generators/upgrade/index.js +4 -5
- package/generators/utils.js +2 -2
- package/generators/workspaces/index.js +16 -7
- package/jdl/jhipster/default-application-options.js +9 -7
- package/package.json +23 -23
- package/utils/entity.js +21 -4
- package/utils/field.js +12 -2
- package/utils/multi-step-transform/index.js +8 -8
- package/generators/client/templates/react/.npmrc.ejs +0 -1
- package/generators/client/templates/vue/webpack/dev.env.js.ejs +0 -17
- package/generators/client/templates/vue/webpack/env.js.ejs +0 -67
- package/generators/client/templates/vue/webpack/loader.conf.js.ejs +0 -20
- package/generators/client/templates/vue/webpack/prod.env.js.ejs +0 -15
|
@@ -34,6 +34,7 @@ import org.springframework.web.client.RestTemplate;
|
|
|
34
34
|
import org.springframework.web.context.request.RequestContextHolder;
|
|
35
35
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
36
36
|
|
|
37
|
+
import java.util.Arrays;
|
|
37
38
|
import java.util.Collections;
|
|
38
39
|
import java.util.HashMap;
|
|
39
40
|
import java.util.List;
|
|
@@ -62,7 +63,7 @@ public class CustomClaimConverter implements Converter<Map<String, Object>, Map<
|
|
|
62
63
|
|
|
63
64
|
public Map<String, Object> convert(Map<String, Object> claims) {
|
|
64
65
|
Map<String, Object> convertedClaims = this.delegate.convert(claims);
|
|
65
|
-
if (RequestContextHolder.getRequestAttributes() != null) {
|
|
66
|
+
if (RequestContextHolder.getRequestAttributes() != null && ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) != null) {
|
|
66
67
|
// Retrieve and set the token
|
|
67
68
|
String token = bearerTokenResolver.resolve(((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
|
|
68
69
|
HttpHeaders headers = new HttpHeaders();
|
|
@@ -83,20 +84,31 @@ public class CustomClaimConverter implements Converter<Map<String, Object>, Map<
|
|
|
83
84
|
if (user.has("family_name")) {
|
|
84
85
|
convertedClaims.put("family_name", user.get("family_name").asText());
|
|
85
86
|
}
|
|
87
|
+
if (user.has("email")) {
|
|
88
|
+
convertedClaims.put("email", user.get("email").asText());
|
|
89
|
+
}
|
|
90
|
+
// Allow full name in a name claim - happens with Auth0
|
|
91
|
+
if (user.has("name")) {
|
|
92
|
+
String[] name = user.get("name").asText().split("\\s+");
|
|
93
|
+
if (name.length > 0) {
|
|
94
|
+
convertedClaims.put("given_name", name[0]);
|
|
95
|
+
convertedClaims.put("family_name",
|
|
96
|
+
String.join(" ", Arrays.copyOfRange(name, 1, name.length)));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
86
99
|
if (user.has("groups")) {
|
|
87
100
|
List<String> groups = StreamSupport.stream(user.get("groups").spliterator(), false)
|
|
88
101
|
.map(JsonNode::asText)
|
|
89
102
|
.collect(Collectors.toList());
|
|
90
103
|
convertedClaims.put("groups", groups);
|
|
91
104
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
.
|
|
98
|
-
|
|
99
|
-
convertedClaims.put("roles", roles);
|
|
105
|
+
if (user.has(SecurityUtils.CLAIMS_NAMESPACE + "roles")) {
|
|
106
|
+
List<String> roles = StreamSupport
|
|
107
|
+
.stream(user.get(SecurityUtils.CLAIMS_NAMESPACE + "roles").spliterator(), false)
|
|
108
|
+
.map(JsonNode::asText)
|
|
109
|
+
.collect(Collectors.toList());
|
|
110
|
+
convertedClaims.put("roles", roles);
|
|
111
|
+
}
|
|
100
112
|
}
|
|
101
113
|
}
|
|
102
114
|
return convertedClaims;
|
|
@@ -1017,15 +1017,20 @@ public class UserService {
|
|
|
1017
1017
|
private static <%= databaseTypeNo ? asDto('AdminUser') : asEntity('User') %> getUser(Map<String, Object> details) {
|
|
1018
1018
|
<%= databaseTypeNo ? asDto('AdminUser') : asEntity('User') %> user = new <%= databaseTypeNo ? asDto('AdminUser') : asEntity('User') %>();
|
|
1019
1019
|
Boolean activated = Boolean.TRUE;
|
|
1020
|
+
String sub = String.valueOf(details.get("sub"));
|
|
1021
|
+
String username = null;
|
|
1022
|
+
if (details.get("preferred_username") != null) {
|
|
1023
|
+
username = ((String) details.get("preferred_username")).toLowerCase();
|
|
1024
|
+
}
|
|
1020
1025
|
// handle resource server JWT, where sub claim is email and uid is ID
|
|
1021
1026
|
if (details.get("uid") != null) {
|
|
1022
1027
|
user.setId((String) details.get("uid"));
|
|
1023
|
-
user.setLogin(
|
|
1028
|
+
user.setLogin(sub);
|
|
1024
1029
|
} else {
|
|
1025
|
-
user.setId(
|
|
1030
|
+
user.setId(sub);
|
|
1026
1031
|
}
|
|
1027
|
-
if (
|
|
1028
|
-
user.setLogin(
|
|
1032
|
+
if (username != null) {
|
|
1033
|
+
user.setLogin(username);
|
|
1029
1034
|
} else if (user.getLogin() == null) {
|
|
1030
1035
|
user.setLogin(user.getId());
|
|
1031
1036
|
}
|
|
@@ -1042,8 +1047,11 @@ public class UserService {
|
|
|
1042
1047
|
}
|
|
1043
1048
|
if (details.get("email") != null) {
|
|
1044
1049
|
user.setEmail(((String) details.get("email")).toLowerCase());
|
|
1050
|
+
} else if (sub.contains("|") && (username != null && username.contains("@"))) {
|
|
1051
|
+
// special handling for Auth0
|
|
1052
|
+
user.setEmail(username);
|
|
1045
1053
|
} else {
|
|
1046
|
-
user.setEmail(
|
|
1054
|
+
user.setEmail(sub);
|
|
1047
1055
|
}
|
|
1048
1056
|
if (details.get("langKey") != null) {
|
|
1049
1057
|
user.setLangKey((String) details.get("langKey"));
|
|
@@ -357,7 +357,7 @@ jhipster:
|
|
|
357
357
|
# CORS is only enabled by default with the "dev" profile
|
|
358
358
|
cors:
|
|
359
359
|
# Allow Ionic for JHipster by default (* no longer allowed in Spring Boot 2.4+)
|
|
360
|
-
allowed-origins: "http://localhost:8100,https://localhost:8100,http://localhost:9000,https://localhost:9000<%_ if (!skipClient) { _%>,http://localhost:<%= devServerPort %>,https://localhost:<%= devServerPort %><%_ } _%>"
|
|
360
|
+
allowed-origins: "http://localhost:8100,https://localhost:8100,http://localhost:9000,https://localhost:9000<%_ if (!skipClient) { _%>,http://localhost:<%= devServerPort %>,https://localhost:<%= devServerPort %><%_ if (applicationTypeGateway && microfrontend) { for ({applicationIndex, devServerPort: microserviceDevServerPort = devServerPort + applicationIndex} of Object.values(jhipsterConfig.applications || {})) { _%>,http://localhost:<%= microserviceDevServerPort %>,https://localhost:<%= microserviceDevServerPort %><%_ } } _%><%_ } _%>"
|
|
361
361
|
allowed-methods: "*"
|
|
362
362
|
allowed-headers: "*"
|
|
363
363
|
<%_ if (authenticationTypeSession) { _%>
|
|
@@ -251,7 +251,7 @@ server:
|
|
|
251
251
|
shutdown: graceful # see https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-graceful-shutdown
|
|
252
252
|
compression:
|
|
253
253
|
enabled: true
|
|
254
|
-
mime-types: text/html,text/xml,text/plain,text/css,
|
|
254
|
+
mime-types: text/html,text/xml,text/plain,text/css,application/javascript,application/json,image/svg+xml
|
|
255
255
|
min-response-size: 1024
|
|
256
256
|
|
|
257
257
|
# ===================================================================
|
|
@@ -92,17 +92,17 @@ management:
|
|
|
92
92
|
roles: "ROLE_ADMIN"
|
|
93
93
|
probes:
|
|
94
94
|
enabled: true
|
|
95
|
+
group:
|
|
96
|
+
liveness:
|
|
97
|
+
include: livenessState
|
|
98
|
+
readiness:
|
|
99
|
+
include: readinessState<% if (databaseTypeSql) { %>,db<% } %>
|
|
95
100
|
jhimetrics:
|
|
96
101
|
enabled: true
|
|
97
102
|
info:
|
|
98
103
|
git:
|
|
99
104
|
mode: full
|
|
100
105
|
health:
|
|
101
|
-
group:
|
|
102
|
-
liveness:
|
|
103
|
-
include: livenessState
|
|
104
|
-
readiness:
|
|
105
|
-
include: readinessState<% if (databaseTypeSql) { %>,db<% } %>
|
|
106
106
|
mail:
|
|
107
107
|
enabled: false # When using the MailService, configure an SMTP server and set this to true
|
|
108
108
|
metrics:
|
|
@@ -320,8 +320,8 @@ jhipster:
|
|
|
320
320
|
api-docs:
|
|
321
321
|
default-include-pattern: ${server.servlet.context-path:}/api/.*
|
|
322
322
|
management-include-pattern: ${server.servlet.context-path:}/management/.*
|
|
323
|
-
title: <%=
|
|
324
|
-
description: <%=
|
|
323
|
+
title: <%= humanizedBaseName %> API
|
|
324
|
+
description: <%= humanizedBaseName %> API documentation
|
|
325
325
|
version: 0.0.1
|
|
326
326
|
terms-of-service-url:
|
|
327
327
|
contact-name:
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
|
|
79
79
|
<ul>
|
|
80
80
|
<%_ if (microfrontend) { %>
|
|
81
|
-
<li>
|
|
81
|
+
<li>JHipster's microfrontends implementation doesn't provide a stand-alone UI. Packaged microfrontends should be accessed through a JHipster gateway.</li>
|
|
82
82
|
<li>Stand-alone development server can be started by `npm start`.</li>
|
|
83
83
|
<%_ } else { %>
|
|
84
84
|
<li>It does not have a front-end. The front-end should be generated on a JHipster gateway.</li>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
Copyright 2013-2021 the original author or authors from the JHipster project.
|
|
3
|
+
|
|
4
|
+
This file is part of the JHipster project, see https://www.jhipster.tech/
|
|
5
|
+
for more information.
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
18
|
+
-%>
|
|
19
|
+
package <%= packageName %>.management;
|
|
20
|
+
|
|
21
|
+
import io.micrometer.core.instrument.Counter;
|
|
22
|
+
import io.micrometer.core.instrument.MeterRegistry;
|
|
23
|
+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
|
24
|
+
import org.junit.jupiter.api.BeforeEach;
|
|
25
|
+
import org.junit.jupiter.api.Test;
|
|
26
|
+
|
|
27
|
+
import java.util.Collection;
|
|
28
|
+
|
|
29
|
+
import static org.assertj.core.api.Assertions.assertThat;
|
|
30
|
+
|
|
31
|
+
class SecurityMetersServiceTests {
|
|
32
|
+
private static final String INVALID_TOKENS_METER_EXPECTED_NAME = "security.authentication.invalid-tokens";
|
|
33
|
+
|
|
34
|
+
private MeterRegistry meterRegistry;
|
|
35
|
+
|
|
36
|
+
private SecurityMetersService securityMetersService;
|
|
37
|
+
|
|
38
|
+
@BeforeEach
|
|
39
|
+
public void setup() {
|
|
40
|
+
meterRegistry = new SimpleMeterRegistry();
|
|
41
|
+
|
|
42
|
+
securityMetersService = new SecurityMetersService(meterRegistry);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Test
|
|
46
|
+
public void testInvalidTokensCountersByCauseAreCreated() {
|
|
47
|
+
meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).counter();
|
|
48
|
+
|
|
49
|
+
meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
50
|
+
.tag("cause", "expired")
|
|
51
|
+
.counter();
|
|
52
|
+
|
|
53
|
+
meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
54
|
+
.tag("cause", "unsupported")
|
|
55
|
+
.counter();
|
|
56
|
+
|
|
57
|
+
meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
58
|
+
.tag("cause", "invalid-signature")
|
|
59
|
+
.counter();
|
|
60
|
+
|
|
61
|
+
meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
62
|
+
.tag("cause", "malformed")
|
|
63
|
+
.counter();
|
|
64
|
+
|
|
65
|
+
Collection<Counter> counters = meterRegistry.find(INVALID_TOKENS_METER_EXPECTED_NAME).counters();
|
|
66
|
+
|
|
67
|
+
assertThat(counters.size()).isEqualTo(4);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@Test
|
|
71
|
+
public void testCountMethodsShouldBeBoundToCorrectCounters() {
|
|
72
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
73
|
+
.tag("cause", "expired")
|
|
74
|
+
.counter().count()).isEqualTo(0);
|
|
75
|
+
|
|
76
|
+
securityMetersService.trackTokenExpired();
|
|
77
|
+
|
|
78
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
79
|
+
.tag("cause", "expired")
|
|
80
|
+
.counter().count()).isEqualTo(1);
|
|
81
|
+
|
|
82
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
83
|
+
.tag("cause", "unsupported")
|
|
84
|
+
.counter().count()).isEqualTo(0);
|
|
85
|
+
|
|
86
|
+
securityMetersService.trackTokenUnsupported();
|
|
87
|
+
|
|
88
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
89
|
+
.tag("cause", "unsupported")
|
|
90
|
+
.counter().count()).isEqualTo(1);
|
|
91
|
+
|
|
92
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
93
|
+
.tag("cause", "invalid-signature")
|
|
94
|
+
.counter().count()).isEqualTo(0);
|
|
95
|
+
|
|
96
|
+
securityMetersService.trackTokenInvalidSignature();
|
|
97
|
+
|
|
98
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
99
|
+
.tag("cause", "invalid-signature")
|
|
100
|
+
.counter().count()).isEqualTo(1);
|
|
101
|
+
|
|
102
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
103
|
+
.tag("cause", "malformed")
|
|
104
|
+
.counter().count()).isEqualTo(0);
|
|
105
|
+
|
|
106
|
+
securityMetersService.trackTokenMalformed();
|
|
107
|
+
|
|
108
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
109
|
+
.tag("cause", "malformed")
|
|
110
|
+
.counter().count()).isEqualTo(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}
|
package/generators/server/templates/src/test/java/package/security/jwt/JWTFilterTest.java.ejs
CHANGED
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
-%>
|
|
19
19
|
package <%= packageName %>.security.jwt;
|
|
20
20
|
|
|
21
|
+
import <%= packageName %>.management.SecurityMetersService;
|
|
21
22
|
import <%= packageName %>.security.AuthoritiesConstants;
|
|
22
23
|
import tech.jhipster.config.JHipsterProperties;
|
|
24
|
+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
|
23
25
|
import io.jsonwebtoken.io.Decoders;
|
|
24
26
|
import io.jsonwebtoken.security.Keys;
|
|
25
27
|
|
|
@@ -63,7 +65,10 @@ class JWTFilterTest {
|
|
|
63
65
|
JHipsterProperties jHipsterProperties = new JHipsterProperties();
|
|
64
66
|
String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8";
|
|
65
67
|
jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret);
|
|
66
|
-
|
|
68
|
+
|
|
69
|
+
SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry());
|
|
70
|
+
|
|
71
|
+
tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
|
|
67
72
|
ReflectionTestUtils.setField(tokenProvider, "key", Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret)));
|
|
68
73
|
|
|
69
74
|
ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", 60000);
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
Copyright 2013-2021 the original author or authors from the JHipster project.
|
|
3
|
+
|
|
4
|
+
This file is part of the JHipster project, see https://www.jhipster.tech/
|
|
5
|
+
for more information.
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
18
|
+
-%>
|
|
19
|
+
package <%= packageName %>.security.jwt;
|
|
20
|
+
|
|
21
|
+
import <%= packageName %>.security.AuthoritiesConstants;
|
|
22
|
+
import <%= packageName %>.management.SecurityMetersService;
|
|
23
|
+
|
|
24
|
+
import io.jsonwebtoken.Jwts;
|
|
25
|
+
import io.jsonwebtoken.SignatureAlgorithm;
|
|
26
|
+
import io.jsonwebtoken.io.Decoders;
|
|
27
|
+
import io.jsonwebtoken.security.Keys;
|
|
28
|
+
|
|
29
|
+
import io.micrometer.core.instrument.Counter;
|
|
30
|
+
import io.micrometer.core.instrument.MeterRegistry;
|
|
31
|
+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
|
32
|
+
|
|
33
|
+
import org.junit.jupiter.api.BeforeEach;
|
|
34
|
+
import org.junit.jupiter.api.Test;
|
|
35
|
+
|
|
36
|
+
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
37
|
+
import org.springframework.security.core.Authentication;
|
|
38
|
+
import org.springframework.security.core.GrantedAuthority;
|
|
39
|
+
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
40
|
+
import org.springframework.test.util.ReflectionTestUtils;
|
|
41
|
+
import tech.jhipster.config.JHipsterProperties;
|
|
42
|
+
|
|
43
|
+
import java.security.Key;
|
|
44
|
+
import java.util.ArrayList;
|
|
45
|
+
import java.util.Collection;
|
|
46
|
+
import java.util.Date;
|
|
47
|
+
|
|
48
|
+
import static org.assertj.core.api.Assertions.assertThat;
|
|
49
|
+
|
|
50
|
+
class TokenProviderSecurityMetersTests {
|
|
51
|
+
|
|
52
|
+
private static final long ONE_MINUTE = 60000;
|
|
53
|
+
private static final String INVALID_TOKENS_METER_EXPECTED_NAME = "security.authentication.invalid-tokens";
|
|
54
|
+
|
|
55
|
+
private MeterRegistry meterRegistry;
|
|
56
|
+
|
|
57
|
+
private TokenProvider tokenProvider;
|
|
58
|
+
|
|
59
|
+
@BeforeEach
|
|
60
|
+
public void setup() {
|
|
61
|
+
JHipsterProperties jHipsterProperties = new JHipsterProperties();
|
|
62
|
+
String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8";
|
|
63
|
+
jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret);
|
|
64
|
+
|
|
65
|
+
meterRegistry = new SimpleMeterRegistry();
|
|
66
|
+
|
|
67
|
+
SecurityMetersService securityMetersService = new SecurityMetersService(meterRegistry);
|
|
68
|
+
|
|
69
|
+
tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
|
|
70
|
+
Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret));
|
|
71
|
+
|
|
72
|
+
ReflectionTestUtils.setField(tokenProvider, "key", key);
|
|
73
|
+
ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", ONE_MINUTE);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@Test
|
|
77
|
+
public void testValidTokenShouldNotCountAnything() {
|
|
78
|
+
Collection<Counter> counters = meterRegistry.find(INVALID_TOKENS_METER_EXPECTED_NAME).counters();
|
|
79
|
+
|
|
80
|
+
assertThat(aggregate(counters)).isEqualTo(0);
|
|
81
|
+
|
|
82
|
+
String validToken = createValidToken();
|
|
83
|
+
|
|
84
|
+
tokenProvider.validateToken(validToken);
|
|
85
|
+
|
|
86
|
+
assertThat(aggregate(counters)).isEqualTo(0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@Test
|
|
90
|
+
public void testTokenExpiredCount() {
|
|
91
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
92
|
+
.tag("cause", "expired")
|
|
93
|
+
.counter().count()).isEqualTo(0);
|
|
94
|
+
|
|
95
|
+
String expiredToken = createExpiredToken();
|
|
96
|
+
|
|
97
|
+
tokenProvider.validateToken(expiredToken);
|
|
98
|
+
|
|
99
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
100
|
+
.tag("cause", "expired")
|
|
101
|
+
.counter().count()).isEqualTo(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@Test
|
|
105
|
+
void testTokenUnsupportedCount() {
|
|
106
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
107
|
+
.tag("cause", "unsupported")
|
|
108
|
+
.counter().count()).isEqualTo(0);
|
|
109
|
+
|
|
110
|
+
String unsupportedToken = createUnsupportedToken();
|
|
111
|
+
|
|
112
|
+
tokenProvider.validateToken(unsupportedToken);
|
|
113
|
+
|
|
114
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
115
|
+
.tag("cause", "unsupported")
|
|
116
|
+
.counter().count()).isEqualTo(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@Test
|
|
120
|
+
public void testTokenSignatureInvalidCount() {
|
|
121
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
122
|
+
.tag("cause", "invalid-signature")
|
|
123
|
+
.counter().count()).isEqualTo(0);
|
|
124
|
+
|
|
125
|
+
String tokenWithDifferentSignature = createTokenWithDifferentSignature();
|
|
126
|
+
|
|
127
|
+
tokenProvider.validateToken(tokenWithDifferentSignature);
|
|
128
|
+
|
|
129
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
130
|
+
.tag("cause", "invalid-signature")
|
|
131
|
+
.counter().count()).isEqualTo(1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@Test
|
|
135
|
+
public void testTokenMalformedCount() {
|
|
136
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
137
|
+
.tag("cause", "malformed")
|
|
138
|
+
.counter().count()).isEqualTo(0);
|
|
139
|
+
|
|
140
|
+
String malformedToken = createMalformedToken();
|
|
141
|
+
|
|
142
|
+
tokenProvider.validateToken(malformedToken);
|
|
143
|
+
|
|
144
|
+
assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME)
|
|
145
|
+
.tag("cause", "malformed")
|
|
146
|
+
.counter().count()).isEqualTo(1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private String createValidToken() {
|
|
150
|
+
Authentication authentication = createAuthentication();
|
|
151
|
+
|
|
152
|
+
return tokenProvider.createToken(authentication, false);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private String createExpiredToken() {
|
|
156
|
+
ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", -ONE_MINUTE);
|
|
157
|
+
|
|
158
|
+
Authentication authentication = createAuthentication();
|
|
159
|
+
|
|
160
|
+
return tokenProvider.createToken(authentication, false);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private Authentication createAuthentication() {
|
|
164
|
+
Collection<GrantedAuthority> authorities = new ArrayList<>();
|
|
165
|
+
authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
|
|
166
|
+
return new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private String createUnsupportedToken() {
|
|
170
|
+
Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key");
|
|
171
|
+
|
|
172
|
+
return Jwts.builder().setPayload("payload").signWith(key, SignatureAlgorithm.HS256).compact();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private String createMalformedToken() {
|
|
176
|
+
String validToken = createValidToken();
|
|
177
|
+
|
|
178
|
+
return "X" + validToken;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private String createTokenWithDifferentSignature() {
|
|
182
|
+
Key otherKey = Keys.hmacShaKeyFor(
|
|
183
|
+
Decoders.BASE64.decode("Xfd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8")
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
return Jwts
|
|
187
|
+
.builder()
|
|
188
|
+
.setSubject("anonymous")
|
|
189
|
+
.signWith(otherKey, SignatureAlgorithm.HS512)
|
|
190
|
+
.setExpiration(new Date(new Date().getTime() + ONE_MINUTE))
|
|
191
|
+
.compact();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private double aggregate(Collection<Counter> counters) {
|
|
195
|
+
return counters.stream().mapToDouble(Counter::count).sum();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
}
|
package/generators/server/templates/src/test/java/package/security/jwt/TokenProviderTest.java.ejs
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
package <%= packageName %>.security.jwt;
|
|
20
20
|
|
|
21
21
|
import <%= packageName %>.security.AuthoritiesConstants;
|
|
22
|
+
import <%= packageName %>.management.SecurityMetersService;
|
|
22
23
|
|
|
23
24
|
import java.security.Key;
|
|
24
25
|
import java.util.*;
|
|
@@ -31,6 +32,8 @@ import org.springframework.security.core.GrantedAuthority;
|
|
|
31
32
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
32
33
|
import org.springframework.test.util.ReflectionTestUtils;
|
|
33
34
|
|
|
35
|
+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
|
36
|
+
|
|
34
37
|
import tech.jhipster.config.JHipsterProperties;
|
|
35
38
|
import io.jsonwebtoken.Jwts;
|
|
36
39
|
import io.jsonwebtoken.SignatureAlgorithm;
|
|
@@ -53,7 +56,10 @@ class TokenProviderTest {
|
|
|
53
56
|
JHipsterProperties jHipsterProperties = new JHipsterProperties();
|
|
54
57
|
String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8";
|
|
55
58
|
jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret);
|
|
56
|
-
|
|
59
|
+
|
|
60
|
+
SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry());
|
|
61
|
+
|
|
62
|
+
tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
|
|
57
63
|
key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret));
|
|
58
64
|
|
|
59
65
|
ReflectionTestUtils.setField(tokenProvider, "key", key);
|
|
@@ -111,7 +117,9 @@ class TokenProviderTest {
|
|
|
111
117
|
JHipsterProperties jHipsterProperties = new JHipsterProperties();
|
|
112
118
|
jHipsterProperties.getSecurity().getAuthentication().getJwt().setSecret(secret);
|
|
113
119
|
|
|
114
|
-
|
|
120
|
+
SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry());
|
|
121
|
+
|
|
122
|
+
TokenProvider tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
|
|
115
123
|
|
|
116
124
|
Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key");
|
|
117
125
|
assertThat(key).isNotNull().isEqualTo(Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)));
|
|
@@ -123,7 +131,9 @@ class TokenProviderTest {
|
|
|
123
131
|
JHipsterProperties jHipsterProperties = new JHipsterProperties();
|
|
124
132
|
jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret);
|
|
125
133
|
|
|
126
|
-
|
|
134
|
+
SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry());
|
|
135
|
+
|
|
136
|
+
TokenProvider tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
|
|
127
137
|
|
|
128
138
|
Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key");
|
|
129
139
|
assertThat(key).isNotNull().isEqualTo(Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret)));
|
|
@@ -50,6 +50,7 @@ import java.util.List;
|
|
|
50
50
|
import java.util.Map;
|
|
51
51
|
import java.util.Optional;
|
|
52
52
|
|
|
53
|
+
import static org.junit.jupiter.api.Assertions.fail;
|
|
53
54
|
import static org.mockito.ArgumentMatchers.*;
|
|
54
55
|
import static org.mockito.Mockito.*;
|
|
55
56
|
|
|
@@ -179,6 +180,20 @@ class AuthorizationHeaderUtilTest {
|
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
private OAuth2AuthorizedClient getTestOAuth2AuthorizedClient(boolean accessTokenExpired) {
|
|
183
|
+
Instant issuedAt = Instant.now();
|
|
184
|
+
Instant expiresAt;
|
|
185
|
+
if (accessTokenExpired) {
|
|
186
|
+
expiresAt = issuedAt.plus(Duration.ofNanos(1));
|
|
187
|
+
try {
|
|
188
|
+
Thread.sleep(1);
|
|
189
|
+
} catch (Exception e) {
|
|
190
|
+
fail("Error in Thread.sleep(1) : " + e.getMessage());
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
expiresAt = issuedAt.plus(Duration.ofMinutes(3));
|
|
194
|
+
}
|
|
195
|
+
OAuth2AccessToken token = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "tokenVal", issuedAt, expiresAt);
|
|
196
|
+
|
|
182
197
|
return new OAuth2AuthorizedClient(
|
|
183
198
|
ClientRegistration.withRegistrationId(VALID_REGISTRATION_ID)
|
|
184
199
|
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
|
@@ -189,8 +204,7 @@ class AuthorizationHeaderUtilTest {
|
|
|
189
204
|
.tokenUri("https://localhost:8080/auth/realms/master/protocol/openid-connect/token")
|
|
190
205
|
.build(),
|
|
191
206
|
"sub",
|
|
192
|
-
|
|
193
|
-
accessTokenExpired ? Instant.now() : Instant.now().plus(Duration.ofMinutes(3))),
|
|
207
|
+
token,
|
|
194
208
|
new OAuth2RefreshToken("refreshVal", Instant.now()));
|
|
195
209
|
}
|
|
196
210
|
|
|
@@ -50,6 +50,9 @@ class CustomClaimConverterIT {
|
|
|
50
50
|
private static final String USERNAME = "admin";
|
|
51
51
|
private static final String NAME = "John";
|
|
52
52
|
private static final String FAMILY_NAME = "Doe";
|
|
53
|
+
private static final String FULL_NAME = NAME + " " + FAMILY_NAME;
|
|
54
|
+
private static final String NAME_SUFFIX = "Sr.";
|
|
55
|
+
private static final String EMAIL = "john.doe@gmail.com";
|
|
53
56
|
|
|
54
57
|
private final ObjectMapper mapper = new ObjectMapper();
|
|
55
58
|
|
|
@@ -161,4 +164,64 @@ class CustomClaimConverterIT {
|
|
|
161
164
|
.doesNotContainKeys("given_name", "family_name");
|
|
162
165
|
}).doesNotThrowAnyException();
|
|
163
166
|
}
|
|
167
|
+
|
|
168
|
+
@Test
|
|
169
|
+
void testConvert_withName() {
|
|
170
|
+
// GIVEN
|
|
171
|
+
Map<String, Object> claims = new HashMap<>();
|
|
172
|
+
claims.put("sub", "123");
|
|
173
|
+
// AND
|
|
174
|
+
ObjectNode user = mapper.createObjectNode();
|
|
175
|
+
user.put("preferred_username", USERNAME);
|
|
176
|
+
user.put("name", FULL_NAME);
|
|
177
|
+
mockHttpGetUserInfo(user);
|
|
178
|
+
|
|
179
|
+
assertThatCode(() -> {
|
|
180
|
+
Map<String, Object> convertedClaims = customClaimConverter.convert(claims);
|
|
181
|
+
assertThat(convertedClaims)
|
|
182
|
+
.containsEntry("preferred_username", USERNAME)
|
|
183
|
+
.containsEntry("given_name", NAME)
|
|
184
|
+
.containsEntry("family_name", FAMILY_NAME);
|
|
185
|
+
}).doesNotThrowAnyException();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@Test
|
|
189
|
+
void testConvert_withLastNameMultipleWords() {
|
|
190
|
+
// GIVEN
|
|
191
|
+
Map<String, Object> claims = new HashMap<>();
|
|
192
|
+
claims.put("sub", "123");
|
|
193
|
+
// AND
|
|
194
|
+
ObjectNode user = mapper.createObjectNode();
|
|
195
|
+
user.put("preferred_username", USERNAME);
|
|
196
|
+
user.put("name", FULL_NAME + " " + NAME_SUFFIX);
|
|
197
|
+
mockHttpGetUserInfo(user);
|
|
198
|
+
|
|
199
|
+
assertThatCode(() -> {
|
|
200
|
+
Map<String, Object> convertedClaims = customClaimConverter.convert(claims);
|
|
201
|
+
System.out.println(convertedClaims);
|
|
202
|
+
assertThat(convertedClaims)
|
|
203
|
+
.containsEntry("preferred_username", USERNAME)
|
|
204
|
+
.containsEntry("given_name", NAME)
|
|
205
|
+
.containsEntry("family_name", FAMILY_NAME + " " + NAME_SUFFIX);
|
|
206
|
+
}).doesNotThrowAnyException();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@Test
|
|
210
|
+
void testConvert_withEmail() {
|
|
211
|
+
// GIVEN
|
|
212
|
+
Map<String, Object> claims = new HashMap<>();
|
|
213
|
+
claims.put("sub", "123");
|
|
214
|
+
// AND
|
|
215
|
+
ObjectNode user = mapper.createObjectNode();
|
|
216
|
+
user.put("preferred_username", USERNAME);
|
|
217
|
+
user.put("email", EMAIL);
|
|
218
|
+
mockHttpGetUserInfo(user);
|
|
219
|
+
|
|
220
|
+
assertThatCode(() -> {
|
|
221
|
+
Map<String, Object> convertedClaims = customClaimConverter.convert(claims);
|
|
222
|
+
assertThat(convertedClaims)
|
|
223
|
+
.containsEntry("preferred_username", USERNAME)
|
|
224
|
+
.containsEntry("email", EMAIL);
|
|
225
|
+
}).doesNotThrowAnyException();
|
|
226
|
+
}
|
|
164
227
|
}
|