Skip to content

Commit

Permalink
Merge pull request #24632 from mshima/sync-user
Browse files Browse the repository at this point in the history
add syncUserWithIdp option
  • Loading branch information
DanielFran authored Dec 21, 2023
2 parents b276039 + c19a766 commit f53ad5b
Show file tree
Hide file tree
Showing 28 changed files with 132 additions and 1,827 deletions.
27 changes: 0 additions & 27 deletions generators/angular/__snapshots__/generator.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1195,15 +1195,6 @@ exports[`generator - angular gateway-oauth2-withAdminUi(true)-skipJhipsterDepend
"clientRoot/src/main/webapp/app/entities/simple/update/simple-update.component.ts": {
"stateCleared": "modified",
},
"clientRoot/src/main/webapp/app/entities/user/user.model.ts": {
"stateCleared": "modified",
},
"clientRoot/src/main/webapp/app/entities/user/user.service.spec.ts": {
"stateCleared": "modified",
},
"clientRoot/src/main/webapp/app/entities/user/user.service.ts": {
"stateCleared": "modified",
},
"clientRoot/src/main/webapp/app/home/home.component.html": {
"stateCleared": "modified",
},
Expand Down Expand Up @@ -2522,15 +2513,6 @@ exports[`generator - angular microservice-oauth2-withAdminUi(true)-skipJhipsterD
"src/main/webapp/app/entities/simple/update/simple-update.component.ts": {
"stateCleared": "modified",
},
"src/main/webapp/app/entities/user/user.model.ts": {
"stateCleared": "modified",
},
"src/main/webapp/app/entities/user/user.service.spec.ts": {
"stateCleared": "modified",
},
"src/main/webapp/app/entities/user/user.service.ts": {
"stateCleared": "modified",
},
"src/main/webapp/app/home/home.component.html": {
"stateCleared": "modified",
},
Expand Down Expand Up @@ -4206,15 +4188,6 @@ exports[`generator - angular monolith-oauth2-withAdminUi(false)-skipJhipsterDepe
"src/main/webapp/app/entities/simple/update/simple-update.component.ts": {
"stateCleared": "modified",
},
"src/main/webapp/app/entities/user/user.model.ts": {
"stateCleared": "modified",
},
"src/main/webapp/app/entities/user/user.service.spec.ts": {
"stateCleared": "modified",
},
"src/main/webapp/app/entities/user/user.service.ts": {
"stateCleared": "modified",
},
"src/main/webapp/app/home/home.component.html": {
"stateCleared": "modified",
},
Expand Down
8 changes: 6 additions & 2 deletions generators/app/__snapshots__/generator.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Options:
--jhipster-dependencies-version <value> jhipster-dependencies version to use, this option is not persisted (env: JHIPSTER_DEPENDENCIES_VERSION)
--application-type <value> Application type to generate (choices: "monolith", "gateway", "microservice")
--feign-client Generate a feign client
--sync-user-with-idp Allow relationships with User for oauth2 applications
--with-generated-flag Add a GeneratedByJHipster annotation to all generated java classes and interfaces
--dev-database-type <value> Development database
--client-framework <value> Provide client framework for the application (choices: "angular", "react", "vue", "no")
Expand Down Expand Up @@ -737,6 +738,7 @@ exports[`generator - app with default config should match snapshot 1`] = `
"srcTestJava": "src/test/java/",
"srcTestJavascript": "src/test/javascript/",
"srcTestResources": "src/test/resources/",
"syncUserWithIdp": undefined,
"temporaryDir": "target/",
"testFrameworks": [],
"testJavaDir": "src/test/java/",
Expand Down Expand Up @@ -1307,6 +1309,7 @@ exports[`generator - app with gateway should match snapshot 1`] = `
"srcTestJava": "src/test/java/",
"srcTestJavascript": "src/test/javascript/",
"srcTestResources": "src/test/resources/",
"syncUserWithIdp": undefined,
"temporaryDir": "target/",
"testFrameworks": [],
"testJavaDir": "src/test/java/",
Expand Down Expand Up @@ -1584,8 +1587,8 @@ exports[`generator - app with microservice should match snapshot 1`] = `
"gatewayServerPort": undefined,
"gatlingTests": false,
"generateAuthenticationApi": false,
"generateBuiltInAuthorityEntity": false,
"generateBuiltInUserEntity": false,
"generateBuiltInAuthorityEntity": undefined,
"generateBuiltInUserEntity": undefined,
"generateInMemoryUserCredentials": false,
"generateUserManagement": false,
"gradleEnterpriseHost": undefined,
Expand Down Expand Up @@ -1820,6 +1823,7 @@ exports[`generator - app with microservice should match snapshot 1`] = `
"srcTestJava": "src/test/java/",
"srcTestJavascript": "src/test/javascript/",
"srcTestResources": "src/test/resources/",
"syncUserWithIdp": undefined,
"temporaryDir": "target/",
"testFrameworks": [],
"testJavaDir": "src/test/java/",
Expand Down
7 changes: 2 additions & 5 deletions generators/app/support/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export const loadAppConfig = ({
'skipUserManagement',
'blueprints',
'testFrameworks',
'syncUserWithIdp',
]),
{
jhipsterVersion: packageJson.version,
Expand Down Expand Up @@ -182,11 +183,7 @@ export const loadDerivedAppConfig = ({ application }: { application: any }) => {
!application.skipUserManagement && application.databaseType !== NO_DATABASE && authenticationApiWithUserManagement;
application.generateInMemoryUserCredentials = !application.generateUserManagement && authenticationApiWithUserManagement;

// TODO make UserEntity optional on relationships for microservices and oauth2
// TODO check if we support syncWithIdp using jwt authentication
// Used for relationships and syncWithIdp
const usesSyncWithIdp = application.authenticationType === OAUTH2 && application.databaseType !== NO_DATABASE;
application.generateBuiltInUserEntity = application.generateUserManagement || usesSyncWithIdp;
application.generateBuiltInUserEntity = application.generateUserManagement || application.syncUserWithIdp;

application.generateBuiltInAuthorityEntity = application.generateBuiltInUserEntity && application.databaseType !== CASSANDRA;
};
12 changes: 11 additions & 1 deletion generators/base-application/support/relationship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,22 @@ export const loadEntitiesAnnotations = (entities: Entity[]) => {
}
};

export const loadEntitiesOtherSide = (entities: Entity[]): ValidationResult => {
export const loadEntitiesOtherSide = (entities: Entity[], { application }: { application?: any } = {}): ValidationResult => {
const result: { warning: string[] } = { warning: [] };
for (const entity of entities) {
for (const relationship of entity.relationships ?? []) {
const otherEntity = findEntityInEntities(upperFirst(relationship.otherEntityName), entities);
if (!otherEntity) {
if (upperFirst(relationship.otherEntityName) === 'User') {
const errors: string[] = [];
if (!application || application.authenticationTypeOauth2) {
errors.push("oauth2 applications with database and '--sync-user-with-idp' option");
}
if (!application || !application.authenticationTypeOauth2) {
errors.push('jwt and session authentication types in monolith or gateway applications with database');
}
throw new Error(`Error at entity ${entity.name}: relationships with built-in User entity is supported in ${errors}.`);
}
throw new Error(`Error at entity ${entity.name}: could not find the entity ${relationship.otherEntityName}`);
}
otherEntity.otherRelationships = otherEntity.otherRelationships || [];
Expand Down
1 change: 1 addition & 0 deletions generators/base-application/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export type CommonClientServerApplication = BaseApplication &
dockerServices?: string[];
prettierExtensions?: string;

skipUserManagement?: boolean;
generateUserManagement?: boolean;
generateBuiltInUserEntity?: boolean;
generateBuiltInAuthorityEntity?: boolean;
Expand Down
4 changes: 2 additions & 2 deletions generators/bootstrap-application-base/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator {
(application as any).user = user;
}
},
loadingEntities({ entitiesToLoad }) {
loadingEntities({ application, entitiesToLoad }) {
for (const { entityName, entityStorage } of entitiesToLoad) {
if (this.sharedData.hasEntity(entityName)) {
const existingEntity = this.sharedData.getEntity(entityName);
Expand All @@ -250,7 +250,7 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator {

const entities = this.sharedData.getEntities().map(({ entity }) => entity);
loadEntitiesAnnotations(entities);
this.validateResult(loadEntitiesOtherSide(entities));
this.validateResult(loadEntitiesOtherSide(entities, { application }));

for (const entity of entities) {
for (const relationship of entity.relationships) {
Expand Down
1 change: 1 addition & 0 deletions generators/jdl/__snapshots__/generator.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ Options:
--jhipster-dependencies-version <value> jhipster-dependencies version to use, this option is not persisted (env: JHIPSTER_DEPENDENCIES_VERSION)
--application-type <value> Application type to generate (choices: "monolith", "gateway", "microservice")
--feign-client Generate a feign client
--sync-user-with-idp Allow relationships with User for oauth2 applications
--with-generated-flag Add a GeneratedByJHipster annotation to all generated java classes and interfaces
--dev-database-type <value> Development database
--client-framework <value> Provide client framework for the application (choices: "angular", "react", "vue", "no")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ _%>
<%_ }) _%>
<%_ relFieldNames.forEach(rel => { _%>
<%_ if (rel.persistableRelationship && !rel.collection) { _%>
<%= rel.relationshipFieldName %>: <%= rel.otherEntityNamePlural %>.find(it => it.<%= rel.otherEntity.primaryKey.name %>.toString() === values.<%= rel.relationshipFieldName %>.toString()),
<%= rel.relationshipFieldName %>: <%= rel.otherEntityNamePlural %>.find(it => it.<%= rel.otherEntity.primaryKey.name %>.toString() === values.<%= rel.relationshipFieldName %>?.toString()),
<%_ } _%>
<%_ }) _%>
}
Expand Down
12 changes: 12 additions & 0 deletions generators/server/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,18 @@ const command: JHipsterCommandDefinition = {
},
default: false,
},
syncUserWithIdp: {
description: 'Allow relationships with User for oauth2 applications',
cli: {
type: Boolean,
},
prompt: gen => ({
type: 'confirm',
message: 'Do you want to allow relationships with User entity?',
when: ({ authenticationType }) => (authenticationType ?? gen.jhipsterConfigWithDefaults.authenticationType) === 'oauth2',
}),
default: false,
},
},
import: [GENERATOR_COMMON, GENERATOR_JAVA, GENERATOR_LIQUIBASE, GENERATOR_SPRING_DATA_RELATIONAL],
};
Expand Down
21 changes: 20 additions & 1 deletion generators/server/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,31 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator {
if (
feignClient === undefined &&
this.isJhipsterVersionLessThan('8.0.1') &&
reactive &&
!reactive &&
applicationType === APPLICATION_TYPE_MICROSERVICE
) {
this.jhipsterConfig.feignClient = true;
}
},
syncUserWithIdp() {
if (this.jhipsterConfig.syncUserWithIdp === undefined && this.jhipsterConfig.authenticationType === OAUTH2) {
if (this.jhipsterConfig.databaseType === NO_DATABASE) {
this.jhipsterConfig.syncUserWithIdp = false;
} else if (this.isJhipsterVersionLessThan('8.1.1')) {
this.jhipsterConfig.syncUserWithIdp = true;
} else if (this.jhipsterConfig.applicationType === GATEWAY) {
// For compatibility with v8 microservices allow syncUserWithIdp by default.
// Switch to false at v9.
this.jhipsterConfig.syncUserWithIdp = true;
} else {
this.jhipsterConfig.syncUserWithIdp = this.getExistingEntities().some(entity =>
(entity.definition.relationships ?? []).some(relationship => relationship.otherEntityName.toLowerCase() === 'user'),
);
}
} else if (this.jhipsterConfig.syncUserWithIdp && this.jhipsterConfig.authenticationType !== OAUTH2) {
throw new Error(`syncUserWithIdp is only supported with authenticationType ${OAUTH2}`);
}
},
});
}

Expand Down
9 changes: 7 additions & 2 deletions generators/server/jdl/application-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ import * as _ from 'lodash-es';
import { JDLApplicationConfig, JHipsterOptionDefinition } from '../../../jdl/types/types.js';
import databaseMigrationOption from '../options/database-migration.js';
import messageBrokerOption from '../options/message-broker.js';
import { feignClientDefinition } from '../options/index.js';
import { feignClientDefinition, syncUserWithIdpDefinition } from '../options/index.js';

const { upperCase, snakeCase } = _;

const jdlOptions: JHipsterOptionDefinition[] = [databaseMigrationOption, messageBrokerOption, feignClientDefinition];
const jdlOptions: JHipsterOptionDefinition[] = [
databaseMigrationOption,
messageBrokerOption,
feignClientDefinition,
syncUserWithIdpDefinition,
];

const applicationConfig: JDLApplicationConfig = {
tokenConfigs: jdlOptions.map(option => ({
Expand Down
1 change: 1 addition & 0 deletions generators/server/options/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
export * from './database-migration.js';
export * from './message-broker.js';
export * from './feign-client.js';
export * from './sync-user-with-idp.js';
20 changes: 20 additions & 0 deletions generators/server/options/sync-user-with-idp.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { before, it, describe, expect } from 'esmocha';
import { createImporterFromContent, ImportState } from '../../../jdl/jdl-importer.js';
import { SYNC_USER_WITH_IDP as optionName } from './sync-user-with-idp.js';

describe(`generators - server - jdl - ${optionName}`, () => {
[true, false].forEach(optionValue => {
describe(`with ${optionValue} value`, () => {
let state: ImportState;

before(() => {
const importer = createImporterFromContent(`application { config { ${optionName} ${optionValue} } }`);
state = importer.import();
});

it('should set expected value', () => {
expect(state.exportedApplicationsWithEntities.jhipster.config[optionName]).toBe(optionValue);
});
});
});
});
28 changes: 28 additions & 0 deletions generators/server/options/sync-user-with-idp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright 2013-2023 the original author or authors from the JHipster project.
*
* This file is part of the JHipster project, see https://www.jhipster.tech/
* for more information.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { JHipsterOptionDefinition } from '../../../jdl/types/types.js';

export const SYNC_USER_WITH_IDP = 'syncUserWithIdp';

export const syncUserWithIdpDefinition: JHipsterOptionDefinition = {
name: SYNC_USER_WITH_IDP,
type: 'boolean',
tokenType: 'BOOLEAN',
};
2 changes: 2 additions & 0 deletions generators/server/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ export type SpringBootApplication = JavaApplication &
skipCheckLengthOfIdentifier: boolean;

imperativeOrReactive: string;
generateAuthenticationApi?: boolean;
generateInMemoryUserCredentials?: boolean;

databaseMigration: string;
databaseMigrationLiquibase: boolean;
Expand Down
Loading

0 comments on commit f53ad5b

Please sign in to comment.