@chevre/domain 22.11.0-alpha.10 → 22.11.0-alpha.12
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/example/src/chevre/roles/{addAdminInventoryManagerRole.ts → addProjectCreatorRole.ts} +6 -8
- package/example/src/chevre/roles/assignGlobalRoles.ts +72 -0
- package/example/src/chevre/roles/findPermissions.ts +84 -0
- package/example/src/chevre/roles/findRoleNames.ts +117 -0
- package/example/src/idaas/auth0/adminApplications.ts +183 -0
- package/example/src/idaas/auth0/getToken.ts +55 -0
- package/example/src/idaas/auth0/getTokenByPrivateKeyJWT.ts +84 -0
- package/lib/chevre/repo/member.d.ts +22 -4
- package/lib/chevre/repo/member.js +81 -27
- package/lib/chevre/repo/mongoose/schemas/member/global.d.ts +14 -0
- package/lib/chevre/repo/mongoose/schemas/member/global.js +82 -0
- package/lib/chevre/repo/role.d.ts +5 -4
- package/lib/chevre/repo/role.js +35 -32
- package/lib/chevre/service/iam.d.ts +17 -7
- package/lib/chevre/service/iam.js +26 -6
- package/package.json +3 -1
- package/example/src/chevre/searchPermissions.ts +0 -46
package/example/src/chevre/roles/{addAdminInventoryManagerRole.ts → addProjectCreatorRole.ts}
RENAMED
|
@@ -9,13 +9,11 @@ async function main() {
|
|
|
9
9
|
const roleRepo = await chevre.repository.Role.createInstance(mongoose.connection);
|
|
10
10
|
|
|
11
11
|
const roleNames = [
|
|
12
|
-
|
|
12
|
+
'projectCreator'
|
|
13
13
|
];
|
|
14
14
|
const permissions = [
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
-
'admin.sellers.eventSeries.*',
|
|
18
|
-
'admin.sellers.read'
|
|
15
|
+
'aggregations.read',
|
|
16
|
+
'projects.create'
|
|
19
17
|
];
|
|
20
18
|
for (const roleName of roleNames) {
|
|
21
19
|
const existingRoles = await roleRepo.projectFields(
|
|
@@ -26,8 +24,8 @@ async function main() {
|
|
|
26
24
|
);
|
|
27
25
|
if (existingRoles.length === 0) {
|
|
28
26
|
const createResult = await roleRepo.create({
|
|
29
|
-
roleName: roleName,
|
|
30
|
-
member: { typeOf: chevre.factory.
|
|
27
|
+
roleName: <any>roleName,
|
|
28
|
+
member: { typeOf: chevre.factory.personType.Person },
|
|
31
29
|
memberOf: { typeOf: chevre.factory.organizationType.Project },
|
|
32
30
|
permissions: []
|
|
33
31
|
});
|
|
@@ -35,7 +33,7 @@ async function main() {
|
|
|
35
33
|
}
|
|
36
34
|
for (const permission of permissions) {
|
|
37
35
|
const result = await roleRepo.addPermissionIfNotExists({
|
|
38
|
-
roleName: { $eq: roleName },
|
|
36
|
+
roleName: { $eq: <any>roleName },
|
|
39
37
|
permission
|
|
40
38
|
});
|
|
41
39
|
console.log('permission added.', result, roleName);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// tslint:disable:no-console
|
|
2
|
+
import type { CognitoIdentityProvider as CognitoIdentityServiceProvider } from '@aws-sdk/client-cognito-identity-provider';
|
|
3
|
+
import * as mongoose from 'mongoose';
|
|
4
|
+
|
|
5
|
+
import { IGlobalMember } from '../../../../lib/chevre/repo/mongoose/schemas/member/global';
|
|
6
|
+
import { chevre } from '../../../../lib/index';
|
|
7
|
+
|
|
8
|
+
const { PROJECT_CREATOR_SUB } = process.env;
|
|
9
|
+
|
|
10
|
+
let cognitoIdentityServiceProvider: CognitoIdentityServiceProvider | undefined;
|
|
11
|
+
|
|
12
|
+
async function main() {
|
|
13
|
+
if (typeof PROJECT_CREATOR_SUB !== 'string') {
|
|
14
|
+
throw new Error('PROJECT_CREATOR_SUB setting required');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
|
|
18
|
+
|
|
19
|
+
const memberRepo = await chevre.repository.Member.createInstance(mongoose.connection);
|
|
20
|
+
const settingRepo = await chevre.repository.Setting.createInstance(mongoose.connection);
|
|
21
|
+
const setting = await settingRepo.findOne({ project: { id: { $eq: '*' } } }, ['userPoolIdNew']);
|
|
22
|
+
if (typeof setting?.userPoolIdNew !== 'string') {
|
|
23
|
+
throw new chevre.factory.errors.NotFound('setting.userPoolIdNew');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let globalMember: IGlobalMember;
|
|
27
|
+
|
|
28
|
+
if (cognitoIdentityServiceProvider === undefined) {
|
|
29
|
+
const { CognitoIdentityProvider } = await import('@aws-sdk/client-cognito-identity-provider');
|
|
30
|
+
const { fromEnv } = await import('@aws-sdk/credential-providers');
|
|
31
|
+
cognitoIdentityServiceProvider = new CognitoIdentityProvider({
|
|
32
|
+
apiVersion: 'latest',
|
|
33
|
+
region: 'ap-northeast-1',
|
|
34
|
+
credentials: fromEnv()
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const personRepo = await chevre.repository.Person.createInstance({
|
|
38
|
+
userPoolId: setting.userPoolIdNew,
|
|
39
|
+
cognitoIdentityServiceProvider
|
|
40
|
+
});
|
|
41
|
+
const profile = await personRepo.findById({ userId: PROJECT_CREATOR_SUB });
|
|
42
|
+
const memberName = (typeof profile.givenName === 'string' && typeof profile.familyName === 'string')
|
|
43
|
+
? `${profile.givenName} ${profile.familyName}`
|
|
44
|
+
: profile.memberOf?.membershipNumber;
|
|
45
|
+
|
|
46
|
+
globalMember = {
|
|
47
|
+
typeOf: chevre.factory.role.RoleType.OrganizationRole,
|
|
48
|
+
member: {
|
|
49
|
+
typeOf: chevre.factory.personType.Person,
|
|
50
|
+
id: profile.id,
|
|
51
|
+
name: memberName,
|
|
52
|
+
username: profile.memberOf?.membershipNumber,
|
|
53
|
+
hasRole: [{
|
|
54
|
+
typeOf: chevre.factory.role.RoleType.OrganizationRole,
|
|
55
|
+
roleName: <any>'projectCreator'
|
|
56
|
+
}]
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
console.log(profile, globalMember);
|
|
60
|
+
|
|
61
|
+
const existingGlobalMemberRoles = await memberRepo.findGlobalRoleNamesByMember({ member: { id: { $eq: globalMember.member.id } } });
|
|
62
|
+
console.log('existingGlobalMemberRoles:', existingGlobalMemberRoles);
|
|
63
|
+
|
|
64
|
+
// 権限作成
|
|
65
|
+
await memberRepo.createGlobalMember([globalMember]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
main()
|
|
69
|
+
.then(() => {
|
|
70
|
+
console.log('success!');
|
|
71
|
+
})
|
|
72
|
+
.catch(console.error);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// tslint:disable:no-console
|
|
2
|
+
// import * as moment from 'moment';
|
|
3
|
+
import * as mongoose from 'mongoose';
|
|
4
|
+
|
|
5
|
+
import { chevre } from '../../../../lib/index';
|
|
6
|
+
|
|
7
|
+
const formatter = new Intl.NumberFormat('ja-JP');
|
|
8
|
+
|
|
9
|
+
const PROJECT_ID = String(process.env.PROJECT_ID);
|
|
10
|
+
const memberId = 'b3640a78-babd-4da4-81d3-7dcf4881a4a5';
|
|
11
|
+
|
|
12
|
+
async function main() {
|
|
13
|
+
await mongoose.connect(<string>process.env.MONGOLAB_URI);
|
|
14
|
+
|
|
15
|
+
const memberRepo = await chevre.repository.Member.createInstance(mongoose.connection);
|
|
16
|
+
const roleRepo = await chevre.repository.Role.createInstance(mongoose.connection);
|
|
17
|
+
|
|
18
|
+
let startTime: [number, number] = process.hrtime();
|
|
19
|
+
let diff: [number, number] = process.hrtime(startTime);
|
|
20
|
+
let result: any;
|
|
21
|
+
|
|
22
|
+
startTime = process.hrtime();
|
|
23
|
+
result = await (await chevre.service.iam.createService()).findProjectPermissionsByMember({
|
|
24
|
+
project: { id: PROJECT_ID },
|
|
25
|
+
member: {
|
|
26
|
+
id: memberId,
|
|
27
|
+
memberOf: {
|
|
28
|
+
id: PROJECT_ID,
|
|
29
|
+
typeOf: chevre.factory.organizationType.Project
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
})({
|
|
33
|
+
member: memberRepo,
|
|
34
|
+
role: roleRepo
|
|
35
|
+
});
|
|
36
|
+
diff = process.hrtime(startTime);
|
|
37
|
+
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
38
|
+
console.log(result.roleNames.length, 'roleNames found');
|
|
39
|
+
console.log(result.permissions.length, 'permissions found');
|
|
40
|
+
|
|
41
|
+
startTime = process.hrtime();
|
|
42
|
+
result = await (await chevre.service.iam.createService()).findProjectPermissionsByMember({
|
|
43
|
+
project: { id: PROJECT_ID },
|
|
44
|
+
member: {
|
|
45
|
+
id: memberId,
|
|
46
|
+
memberOf: {
|
|
47
|
+
id: PROJECT_ID,
|
|
48
|
+
typeOf: chevre.factory.organizationType.Project
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})({
|
|
52
|
+
member: memberRepo,
|
|
53
|
+
role: roleRepo
|
|
54
|
+
});
|
|
55
|
+
diff = process.hrtime(startTime);
|
|
56
|
+
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
57
|
+
console.log(result.roleNames.length, 'roleNames found');
|
|
58
|
+
console.log(result.permissions.length, 'permissions found');
|
|
59
|
+
|
|
60
|
+
startTime = process.hrtime();
|
|
61
|
+
result = await (await chevre.service.iam.createService()).findProjectPermissionsByMember({
|
|
62
|
+
project: { id: PROJECT_ID },
|
|
63
|
+
member: {
|
|
64
|
+
id: memberId,
|
|
65
|
+
memberOf: {
|
|
66
|
+
id: PROJECT_ID,
|
|
67
|
+
typeOf: chevre.factory.organizationType.Project
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
})({
|
|
71
|
+
member: memberRepo,
|
|
72
|
+
role: roleRepo
|
|
73
|
+
});
|
|
74
|
+
diff = process.hrtime(startTime);
|
|
75
|
+
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
76
|
+
console.log(result.roleNames.length, 'roleNames found');
|
|
77
|
+
console.log(result.permissions.length, 'permissions found');
|
|
78
|
+
|
|
79
|
+
console.log(result);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
main()
|
|
83
|
+
.then(console.log)
|
|
84
|
+
.catch(console.error);
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// tslint:disable:no-console
|
|
2
|
+
// import * as moment from 'moment';
|
|
3
|
+
import * as mongoose from 'mongoose';
|
|
4
|
+
|
|
5
|
+
import { chevre } from '../../../../lib/index';
|
|
6
|
+
|
|
7
|
+
const formatter = new Intl.NumberFormat('ja-JP');
|
|
8
|
+
|
|
9
|
+
const PROJECT_ID = String(process.env.PROJECT_ID);
|
|
10
|
+
const memberId = 'xxx';
|
|
11
|
+
|
|
12
|
+
// tslint:disable-next-line:max-func-body-length
|
|
13
|
+
async function main() {
|
|
14
|
+
await mongoose.connect(<string>process.env.MONGOLAB_URI);
|
|
15
|
+
|
|
16
|
+
const memberRepo = await chevre.repository.Member.createInstance(mongoose.connection);
|
|
17
|
+
|
|
18
|
+
let startTime: [number, number] = process.hrtime();
|
|
19
|
+
let diff: [number, number] = process.hrtime(startTime);
|
|
20
|
+
let result: any;
|
|
21
|
+
|
|
22
|
+
// startTime = process.hrtime();
|
|
23
|
+
// result = await memberRepo.aggregateRoleNames({
|
|
24
|
+
// project: { id: { $eq: PROJECT_ID } },
|
|
25
|
+
// member: {
|
|
26
|
+
// id: { $eq: memberId },
|
|
27
|
+
// memberOf: {
|
|
28
|
+
// id: { $eq: PROJECT_ID },
|
|
29
|
+
// typeOf: { $eq: chevre.factory.organizationType.Project }
|
|
30
|
+
// }
|
|
31
|
+
// }
|
|
32
|
+
// });
|
|
33
|
+
// diff = process.hrtime(startTime);
|
|
34
|
+
// console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
35
|
+
// console.log(result.length, 'result found');
|
|
36
|
+
|
|
37
|
+
// startTime = process.hrtime();
|
|
38
|
+
// result = await memberRepo.aggregateRoleNames({
|
|
39
|
+
// project: { id: { $eq: PROJECT_ID } },
|
|
40
|
+
// member: {
|
|
41
|
+
// id: { $eq: memberId },
|
|
42
|
+
// memberOf: {
|
|
43
|
+
// id: { $eq: PROJECT_ID },
|
|
44
|
+
// typeOf: { $eq: chevre.factory.organizationType.Project }
|
|
45
|
+
// }
|
|
46
|
+
// }
|
|
47
|
+
// });
|
|
48
|
+
// diff = process.hrtime(startTime);
|
|
49
|
+
// console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
50
|
+
// console.log(result.length, 'result found');
|
|
51
|
+
|
|
52
|
+
// startTime = process.hrtime();
|
|
53
|
+
// result = await memberRepo.aggregateRoleNames({
|
|
54
|
+
// project: { id: { $eq: PROJECT_ID } },
|
|
55
|
+
// member: {
|
|
56
|
+
// id: { $eq: memberId },
|
|
57
|
+
// memberOf: {
|
|
58
|
+
// id: { $eq: PROJECT_ID },
|
|
59
|
+
// typeOf: { $eq: chevre.factory.organizationType.Project }
|
|
60
|
+
// }
|
|
61
|
+
// }
|
|
62
|
+
// });
|
|
63
|
+
// diff = process.hrtime(startTime);
|
|
64
|
+
// console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
65
|
+
// console.log(result.length, 'result found');
|
|
66
|
+
// console.log(result);
|
|
67
|
+
|
|
68
|
+
startTime = process.hrtime();
|
|
69
|
+
result = await memberRepo.findRoleNamesByMember({
|
|
70
|
+
project: { id: { $eq: PROJECT_ID } },
|
|
71
|
+
member: {
|
|
72
|
+
id: { $eq: memberId },
|
|
73
|
+
memberOf: {
|
|
74
|
+
id: { $eq: PROJECT_ID },
|
|
75
|
+
typeOf: { $eq: chevre.factory.organizationType.Project }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
diff = process.hrtime(startTime);
|
|
80
|
+
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
81
|
+
console.log(result.length, 'result found');
|
|
82
|
+
|
|
83
|
+
startTime = process.hrtime();
|
|
84
|
+
result = await memberRepo.findRoleNamesByMember({
|
|
85
|
+
project: { id: { $eq: PROJECT_ID } },
|
|
86
|
+
member: {
|
|
87
|
+
id: { $eq: memberId },
|
|
88
|
+
memberOf: {
|
|
89
|
+
id: { $eq: PROJECT_ID },
|
|
90
|
+
typeOf: { $eq: chevre.factory.organizationType.Project }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
diff = process.hrtime(startTime);
|
|
95
|
+
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
96
|
+
console.log(result.length, 'result found');
|
|
97
|
+
|
|
98
|
+
startTime = process.hrtime();
|
|
99
|
+
result = await memberRepo.findRoleNamesByMember({
|
|
100
|
+
project: { id: { $eq: PROJECT_ID } },
|
|
101
|
+
member: {
|
|
102
|
+
id: { $eq: memberId },
|
|
103
|
+
memberOf: {
|
|
104
|
+
id: { $eq: PROJECT_ID },
|
|
105
|
+
typeOf: { $eq: chevre.factory.organizationType.Project }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
diff = process.hrtime(startTime);
|
|
110
|
+
console.log('diff:', [diff[0], formatter.format(diff[1])]);
|
|
111
|
+
console.log(result.length, 'result found');
|
|
112
|
+
console.log(result);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
main()
|
|
116
|
+
.then(console.log)
|
|
117
|
+
.catch(console.error);
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// tslint:disable:no-implicit-dependencies no-console no-magic-numbers
|
|
2
|
+
import { ManagementClient } from 'auth0';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import * as moment from 'moment';
|
|
5
|
+
// import * as crypto from 'crypto'; // client_secret 生成用 (PKJWTなしの場合)
|
|
6
|
+
// import { JWK, importPKCS8, generateKeyPair, SignJWT } from 'jose'; // Private Key JWT 用
|
|
7
|
+
|
|
8
|
+
const PUBLIC_KEY_FILE_PATH = `${__dirname}/../../samplePublicKey.pem`;
|
|
9
|
+
const { AUTH0_DOMAIN, AUTH0_MGMT_CLIENT_ID, AUTH0_MGMT_CLIENT_SECRET, AUTH0_MGMT_API_AUDIENCE, AUTH0_AUDIENCE } = process.env;
|
|
10
|
+
|
|
11
|
+
if (typeof AUTH0_DOMAIN !== 'string'
|
|
12
|
+
|| typeof AUTH0_MGMT_CLIENT_ID !== 'string'
|
|
13
|
+
|| typeof AUTH0_MGMT_CLIENT_SECRET !== 'string'
|
|
14
|
+
|| typeof AUTH0_MGMT_API_AUDIENCE !== 'string'
|
|
15
|
+
|| typeof AUTH0_AUDIENCE !== 'string'
|
|
16
|
+
) {
|
|
17
|
+
throw new Error('set envs!');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// --- Auth0 ManagementClient の初期化 ---
|
|
21
|
+
const management = new ManagementClient({
|
|
22
|
+
domain: AUTH0_DOMAIN,
|
|
23
|
+
clientId: AUTH0_MGMT_CLIENT_ID,
|
|
24
|
+
clientSecret: AUTH0_MGMT_CLIENT_SECRET,
|
|
25
|
+
audience: AUTH0_MGMT_API_AUDIENCE
|
|
26
|
+
// scope: 'read:clients create:clients' // 必要なスコープを明示
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
async function sleep(waitInSeconds: number) {
|
|
30
|
+
await new Promise<void>((resolve) => {
|
|
31
|
+
setTimeout(
|
|
32
|
+
() => {
|
|
33
|
+
resolve();
|
|
34
|
+
},
|
|
35
|
+
waitInSeconds
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* アプリケーションを検索し、存在しなければ作成します。
|
|
42
|
+
* Private Key JWT 認証を使用する前提。
|
|
43
|
+
*/
|
|
44
|
+
async function findOrCreateServiceAccount(
|
|
45
|
+
appName: string,
|
|
46
|
+
projectId: string,
|
|
47
|
+
roles: string[],
|
|
48
|
+
audience: string
|
|
49
|
+
) {
|
|
50
|
+
try {
|
|
51
|
+
console.log('getting organization...');
|
|
52
|
+
const getOrganizationResponse = await management.organizations.getByName({
|
|
53
|
+
name: projectId
|
|
54
|
+
});
|
|
55
|
+
const organization = getOrganizationResponse.data;
|
|
56
|
+
console.log('organization exists.', organization);
|
|
57
|
+
|
|
58
|
+
const newClient = (await management.clients.create({
|
|
59
|
+
name: appName,
|
|
60
|
+
app_type: 'non_interactive', // Machine to Machine アプリケーション
|
|
61
|
+
jwt_configuration: { // Private Key JWT の設定
|
|
62
|
+
alg: 'RS256' // 署名アルゴリズム
|
|
63
|
+
},
|
|
64
|
+
// token_endpoint_auth_method: 'client_secret_post',
|
|
65
|
+
client_authentication_methods: {
|
|
66
|
+
private_key_jwt: {
|
|
67
|
+
credentials: [{
|
|
68
|
+
alg: 'RS256',
|
|
69
|
+
/**
|
|
70
|
+
* Credential type. Supported types: public_key.
|
|
71
|
+
*
|
|
72
|
+
*/
|
|
73
|
+
credential_type: 'public_key',
|
|
74
|
+
// name?: string;
|
|
75
|
+
pem: readFileSync(PUBLIC_KEY_FILE_PATH, 'utf8')
|
|
76
|
+
|
|
77
|
+
}]
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
grant_types: ['client_credentials'],
|
|
81
|
+
organization_usage: 'require', // 組織での利用を許可
|
|
82
|
+
default_organization: {
|
|
83
|
+
organization_id: organization.id,
|
|
84
|
+
flows: ['client_credentials']
|
|
85
|
+
},
|
|
86
|
+
oidc_conformant: true,
|
|
87
|
+
client_metadata: {
|
|
88
|
+
roles: JSON.stringify(roles)
|
|
89
|
+
}
|
|
90
|
+
})).data;
|
|
91
|
+
console.log(`Successfully created new application: ${newClient.client_id} (${newClient.name})`);
|
|
92
|
+
|
|
93
|
+
console.log(`checking clientGrant... ${newClient.client_id} (${newClient.name})`);
|
|
94
|
+
await sleep(3000);
|
|
95
|
+
|
|
96
|
+
let clientGrant = (await management.clientGrants.getAll({
|
|
97
|
+
audience,
|
|
98
|
+
client_id: newClient.client_id
|
|
99
|
+
})).data.shift();
|
|
100
|
+
if (clientGrant === undefined) {
|
|
101
|
+
clientGrant = (await management.clientGrants.create({
|
|
102
|
+
client_id: newClient.client_id,
|
|
103
|
+
audience,
|
|
104
|
+
organization_usage: 'require',
|
|
105
|
+
allow_any_organization: false,
|
|
106
|
+
scope: ['iam.members.me.read']
|
|
107
|
+
})).data;
|
|
108
|
+
console.log(`clientGrant created. ${newClient.client_id} (${newClient.name})`);
|
|
109
|
+
} else {
|
|
110
|
+
console.log(`clientGrant already exists. ${newClient.client_id} (${newClient.name})`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log(`checking organizationClientGrant... ${newClient.client_id} (${newClient.name})`);
|
|
114
|
+
await sleep(3000);
|
|
115
|
+
const organizationClientGrant = (await management.organizations.getOrganizationClientGrants({
|
|
116
|
+
id: organization.id,
|
|
117
|
+
audience: 'https://development.apis.smart-theater.com',
|
|
118
|
+
client_id: newClient.client_id
|
|
119
|
+
})).data.shift();
|
|
120
|
+
if (organizationClientGrant === undefined) {
|
|
121
|
+
await management.organizations.postOrganizationClientGrants(
|
|
122
|
+
{
|
|
123
|
+
id: organization.id
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
grant_id: clientGrant.id
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
console.log(`organizationClientGrant created. ${newClient.client_id} (${newClient.name})`);
|
|
130
|
+
} else {
|
|
131
|
+
console.log(`organizationClientGrant already exists. ${newClient.client_id} (${newClient.name})`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 1. アプリケーションを検索 (名前で検索するのが一般的)
|
|
135
|
+
console.log('searching for applications...');
|
|
136
|
+
await sleep(3000);
|
|
137
|
+
|
|
138
|
+
await searchClients({ organization });
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error(`Error finding or creating application: ${error.message}`);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function searchClients(params: {
|
|
146
|
+
organization: { id: string };
|
|
147
|
+
}) {
|
|
148
|
+
const existingApps = await management.clients.getAll({
|
|
149
|
+
include_totals: true,
|
|
150
|
+
// app_type: 'non_interactive',
|
|
151
|
+
// is_global: false,
|
|
152
|
+
// page: 0,
|
|
153
|
+
// per_page: 50,
|
|
154
|
+
// q: `name:"${appName}"`, // 名前で検索
|
|
155
|
+
q: `client_grant.organization_id:"${params.organization.id}"`,
|
|
156
|
+
// from: undefined,
|
|
157
|
+
take: 50
|
|
158
|
+
// is_client_credentials: true // Machine to Machine アプリケーションに絞る
|
|
159
|
+
});
|
|
160
|
+
const clients = existingApps.data.clients;
|
|
161
|
+
console.log(clients.length, 'existingApps exist.', clients);
|
|
162
|
+
console.log(clients.length, 'clients found.');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function run() {
|
|
166
|
+
if (typeof AUTH0_AUDIENCE !== 'string') {
|
|
167
|
+
throw new Error('set envs!');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
await findOrCreateServiceAccount(
|
|
172
|
+
`sampleServiceAccount-${moment()
|
|
173
|
+
.format('YYYY-MM-DDTHH:mm:ss')}`,
|
|
174
|
+
'cinerino',
|
|
175
|
+
['inventoryManager', 'user'],
|
|
176
|
+
AUTH0_AUDIENCE
|
|
177
|
+
);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.error('Failed to run provisioning script:', error);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
run();
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// tslint:disable:no-implicit-dependencies no-console
|
|
2
|
+
interface IAuth0Config {
|
|
3
|
+
auth0Domain: string;
|
|
4
|
+
clientId: string;
|
|
5
|
+
clientSecret: string;
|
|
6
|
+
audience: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// 環境変数から機密情報を取得することを強く推奨します
|
|
10
|
+
const config: IAuth0Config = {
|
|
11
|
+
auth0Domain: String(process.env.AUTH0_DOMAIN),
|
|
12
|
+
clientId: String(process.env.AUTH0_CLIENT_ID),
|
|
13
|
+
clientSecret: String(process.env.AUTH0_CLIENT_SECRET),
|
|
14
|
+
audience: String(process.env.AUTH0_AUDIENCE)
|
|
15
|
+
// scopes: process.env.OKTA_SCOPES || 'api_access_scope openid', // 必要なスコープを指定
|
|
16
|
+
// authServerId: 'aussd9v86wlIar3cX697', // デフォルト承認サーバーを使用する場合はコメントアウトまたは指定しない
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
async function getToken() {
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(
|
|
22
|
+
`https://${config.auth0Domain}/oauth/token`,
|
|
23
|
+
{
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: { 'content-type': 'application/json' },
|
|
26
|
+
body: JSON.stringify({
|
|
27
|
+
client_id: config.clientId,
|
|
28
|
+
client_secret: config.clientSecret,
|
|
29
|
+
audience: config.audience,
|
|
30
|
+
grant_type: 'client_credentials'
|
|
31
|
+
// organization: 'org_zuMP9ng42QSgZ5Kn'
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
console.log(await response.json());
|
|
37
|
+
throw new Error('Network response was not ok');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
console.log(data);
|
|
42
|
+
|
|
43
|
+
return data;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('Error fetching token:', error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function main() {
|
|
50
|
+
const token = await getToken();
|
|
51
|
+
console.log(token);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
main()
|
|
55
|
+
.catch(console.error);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// tslint:disable:no-implicit-dependencies no-console
|
|
2
|
+
import * as crypto from 'crypto';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import { SignJWT } from 'jose';
|
|
5
|
+
import * as uuid from 'uuid';
|
|
6
|
+
|
|
7
|
+
const PRIVATE_KEY_FILE_PATH = `${__dirname}/../../samplePrivateKey.pem`;
|
|
8
|
+
|
|
9
|
+
interface IAuth0Config {
|
|
10
|
+
auth0Domain: string;
|
|
11
|
+
clientId: string;
|
|
12
|
+
privateKeyContent: string; // PEM形式の秘密鍵の内容 (例: fs.readFileSync('private_key.pem', 'utf8'))
|
|
13
|
+
audience: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 環境変数から機密情報を取得することを強く推奨します
|
|
17
|
+
const auth0config: IAuth0Config = {
|
|
18
|
+
auth0Domain: String(process.env.AUTH0_DOMAIN),
|
|
19
|
+
clientId: String(process.env.AUTH0_CLIENT_ID),
|
|
20
|
+
// keyId: 'xxx',
|
|
21
|
+
privateKeyContent: readFileSync(PRIVATE_KEY_FILE_PATH, 'utf8'), // 秘密鍵の内容を読み込む
|
|
22
|
+
audience: String(process.env.AUTH0_AUDIENCE)
|
|
23
|
+
// scopes: process.env.OKTA_SCOPES || 'api_access_scope openid', // 必要なスコープを指定
|
|
24
|
+
// authServerId: 'aussd9v86wlIar3cX697', // デフォルト承認サーバーを使用する場合はコメントアウトまたは指定しない
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
async function generateJwtAssertion(config: IAuth0Config) {
|
|
28
|
+
const privateKeyPEM = crypto.createPrivateKey(readFileSync(PRIVATE_KEY_FILE_PATH, 'utf8'));
|
|
29
|
+
|
|
30
|
+
return new SignJWT({})
|
|
31
|
+
.setProtectedHeader({
|
|
32
|
+
alg: 'RS256' // or RS384 or PS256
|
|
33
|
+
// kid: '(OPTIONAL) KID_GENERATED_BY_AUTH0'
|
|
34
|
+
})
|
|
35
|
+
.setIssuedAt()
|
|
36
|
+
.setIssuer(config.clientId)
|
|
37
|
+
.setSubject(config.clientId)
|
|
38
|
+
.setAudience(`https://${config.auth0Domain}/`)
|
|
39
|
+
.setExpirationTime('1m')
|
|
40
|
+
.setJti(uuid.v4())
|
|
41
|
+
.sign(privateKeyPEM);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function getToken() {
|
|
45
|
+
try {
|
|
46
|
+
const jwtAssertion = await generateJwtAssertion(auth0config);
|
|
47
|
+
console.log('jwtAssertion:', jwtAssertion);
|
|
48
|
+
|
|
49
|
+
const body = new URLSearchParams({
|
|
50
|
+
grant_type: 'client_credentials',
|
|
51
|
+
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
|
|
52
|
+
client_assertion: jwtAssertion,
|
|
53
|
+
audience: auth0config.audience
|
|
54
|
+
// scope: config.scopes,
|
|
55
|
+
}).toString();
|
|
56
|
+
const response = await fetch(
|
|
57
|
+
`https://${auth0config.auth0Domain}/oauth/token`,
|
|
58
|
+
{
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
61
|
+
body: body
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
console.log(await response.json());
|
|
66
|
+
throw new Error('Network response was not ok');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const data = await response.json();
|
|
70
|
+
console.log(data);
|
|
71
|
+
|
|
72
|
+
return data;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error('Error fetching token:', error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function main() {
|
|
79
|
+
const token = await getToken();
|
|
80
|
+
console.log(token);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
main()
|
|
84
|
+
.catch(console.error);
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Connection, FilterQuery } from 'mongoose';
|
|
2
2
|
import * as factory from '../factory';
|
|
3
|
+
import { IGlobalMember } from './mongoose/schemas/member/global';
|
|
3
4
|
type IKeyOfProjection = keyof factory.iam.IMember;
|
|
4
5
|
export type ICustomerMember = Pick<factory.iam.IMemberOfRole, 'hasRole' | 'id' | 'name' | 'memberOf'>;
|
|
5
6
|
/**
|
|
6
7
|
* IAMメンバーリポジトリ
|
|
7
8
|
*/
|
|
8
9
|
export declare class MemberRepo {
|
|
10
|
+
private readonly globalMemberModel;
|
|
9
11
|
private readonly memberModel;
|
|
10
12
|
constructor(connection: Connection);
|
|
11
13
|
static CREATE_MONGO_CONDITIONS(params: factory.iam.ISearchConditions): FilterQuery<factory.iam.IMember>[];
|
|
@@ -37,7 +39,10 @@ export declare class MemberRepo {
|
|
|
37
39
|
}): Promise<{
|
|
38
40
|
member: ICustomerMember;
|
|
39
41
|
}[]>;
|
|
40
|
-
|
|
42
|
+
/**
|
|
43
|
+
* distinctコマンドを使用して、プロジェクトメンバーのロールを検索する
|
|
44
|
+
*/
|
|
45
|
+
findRoleNamesByMember(params: {
|
|
41
46
|
project: {
|
|
42
47
|
id: {
|
|
43
48
|
$eq: string;
|
|
@@ -56,9 +61,7 @@ export declare class MemberRepo {
|
|
|
56
61
|
};
|
|
57
62
|
};
|
|
58
63
|
};
|
|
59
|
-
}): Promise<
|
|
60
|
-
roleName: string;
|
|
61
|
-
}[]>;
|
|
64
|
+
}): Promise<string[]>;
|
|
62
65
|
deleteByProject(params: {
|
|
63
66
|
project: {
|
|
64
67
|
id: string;
|
|
@@ -163,6 +166,21 @@ export declare class MemberRepo {
|
|
|
163
166
|
filter: any;
|
|
164
167
|
$unset: any;
|
|
165
168
|
}): Promise<import("mongoose").UpdateWriteOpResult>;
|
|
169
|
+
/**
|
|
170
|
+
* グローバルメンバー作成
|
|
171
|
+
* 2025-07-21~
|
|
172
|
+
*/
|
|
173
|
+
createGlobalMember(params: IGlobalMember[]): Promise<void>;
|
|
174
|
+
/**
|
|
175
|
+
* distinctコマンドを使用して、グローバルメンバーのロールを検索する
|
|
176
|
+
*/
|
|
177
|
+
findGlobalRoleNamesByMember(params: {
|
|
178
|
+
member: {
|
|
179
|
+
id: {
|
|
180
|
+
$eq: string;
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
}): Promise<string[]>;
|
|
166
184
|
private projectFields;
|
|
167
185
|
}
|
|
168
186
|
export {};
|
|
@@ -13,16 +13,19 @@ exports.MemberRepo = void 0;
|
|
|
13
13
|
const factory = require("../factory");
|
|
14
14
|
const settings_1 = require("../settings");
|
|
15
15
|
const member_1 = require("./mongoose/schemas/member");
|
|
16
|
+
const global_1 = require("./mongoose/schemas/member/global");
|
|
16
17
|
const AVAILABLE_PROJECT_FIELDS = [
|
|
17
18
|
'project',
|
|
18
19
|
'typeOf',
|
|
19
20
|
'member'
|
|
20
21
|
];
|
|
22
|
+
const ANY_PROJECT_ID = '*';
|
|
21
23
|
/**
|
|
22
24
|
* IAMメンバーリポジトリ
|
|
23
25
|
*/
|
|
24
26
|
class MemberRepo {
|
|
25
27
|
constructor(connection) {
|
|
28
|
+
this.globalMemberModel = connection.model(global_1.modelName, (0, global_1.createSchema)());
|
|
26
29
|
this.memberModel = connection.model(member_1.modelName, (0, member_1.createSchema)());
|
|
27
30
|
}
|
|
28
31
|
// tslint:disable-next-line:cyclomatic-complexity max-func-body-length
|
|
@@ -112,7 +115,7 @@ class MemberRepo {
|
|
|
112
115
|
throw new factory.errors.ArgumentNull('project.id');
|
|
113
116
|
}
|
|
114
117
|
const filterQueries = MemberRepo.CREATE_MONGO_CONDITIONS({
|
|
115
|
-
project: { id: { $in: [params.project.id,
|
|
118
|
+
project: { id: { $in: [params.project.id, ANY_PROJECT_ID] } }, // 全プロジェクトで利用可能なクライアントを考慮(2025-01-11~)
|
|
116
119
|
member: {
|
|
117
120
|
typeOf: { $eq: factory.creativeWorkType.WebApplication },
|
|
118
121
|
memberOf: { typeOf: { $eq: factory.organizationType.Project } }, // プロジェクトメンバーのはず
|
|
@@ -163,32 +166,55 @@ class MemberRepo {
|
|
|
163
166
|
.exec();
|
|
164
167
|
});
|
|
165
168
|
}
|
|
166
|
-
|
|
169
|
+
// migrate to findRoleNamesByMember(2025-07-21~)
|
|
170
|
+
// public async aggregateRoleNames(params: {
|
|
171
|
+
// project: { id: { $eq: string } };
|
|
172
|
+
// member: {
|
|
173
|
+
// id: { $eq: string };
|
|
174
|
+
// memberOf: {
|
|
175
|
+
// id: { $eq: string };
|
|
176
|
+
// typeOf: { $eq: factory.organizationType.Corporation | factory.organizationType.Project };
|
|
177
|
+
// };
|
|
178
|
+
// };
|
|
179
|
+
// }): Promise<{ roleName: string }[]> {
|
|
180
|
+
// const matchStages: IMatchStage[] = [
|
|
181
|
+
// { $match: { 'project.id': { $eq: params.project.id.$eq } } },
|
|
182
|
+
// { $match: { 'member.id': { $eq: params.member.id.$eq } } },
|
|
183
|
+
// { $match: { 'member.memberOf.id': { $eq: params.member.memberOf.id.$eq } } },
|
|
184
|
+
// { $match: { 'member.memberOf.typeOf': { $eq: params.member.memberOf.typeOf.$eq } } }
|
|
185
|
+
// ];
|
|
186
|
+
// const aggregate = this.memberModel.aggregate([
|
|
187
|
+
// // ...(typeof params.sort?.productID === 'number')
|
|
188
|
+
// // ? [{ $sort: { productID: params.sort.productID } }]
|
|
189
|
+
// // : [],
|
|
190
|
+
// ...matchStages,
|
|
191
|
+
// {
|
|
192
|
+
// $unwind: {
|
|
193
|
+
// path: '$member.hasRole'
|
|
194
|
+
// }
|
|
195
|
+
// },
|
|
196
|
+
// {
|
|
197
|
+
// $project: {
|
|
198
|
+
// _id: 0,
|
|
199
|
+
// roleName: '$member.hasRole.roleName'
|
|
200
|
+
// }
|
|
201
|
+
// }
|
|
202
|
+
// ]);
|
|
203
|
+
// return aggregate.option({ maxTimeMS: MONGO_MAX_TIME_MS })
|
|
204
|
+
// .exec();
|
|
205
|
+
// }
|
|
206
|
+
/**
|
|
207
|
+
* distinctコマンドを使用して、プロジェクトメンバーのロールを検索する
|
|
208
|
+
*/
|
|
209
|
+
findRoleNamesByMember(params) {
|
|
167
210
|
return __awaiter(this, void 0, void 0, function* () {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// ...(typeof params.sort?.productID === 'number')
|
|
176
|
-
// ? [{ $sort: { productID: params.sort.productID } }]
|
|
177
|
-
// : [],
|
|
178
|
-
...matchStages,
|
|
179
|
-
{
|
|
180
|
-
$unwind: {
|
|
181
|
-
path: '$member.hasRole'
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
$project: {
|
|
186
|
-
_id: 0,
|
|
187
|
-
roleName: '$member.hasRole.roleName'
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
]);
|
|
191
|
-
return aggregate.option({ maxTimeMS: settings_1.MONGO_MAX_TIME_MS })
|
|
211
|
+
return this.memberModel.distinct('member.hasRole.roleName', {
|
|
212
|
+
'project.id': { $eq: params.project.id.$eq },
|
|
213
|
+
'member.id': { $eq: params.member.id.$eq },
|
|
214
|
+
'member.memberOf.id': { $eq: params.member.memberOf.id.$eq },
|
|
215
|
+
'member.memberOf.typeOf': { $eq: params.member.memberOf.typeOf.$eq }
|
|
216
|
+
})
|
|
217
|
+
.setOptions({ maxTimeMS: settings_1.MONGO_MAX_TIME_MS })
|
|
192
218
|
.exec();
|
|
193
219
|
});
|
|
194
220
|
}
|
|
@@ -293,7 +319,9 @@ class MemberRepo {
|
|
|
293
319
|
if (typeof params.page !== 'number') {
|
|
294
320
|
throw new factory.errors.ArgumentNull('page');
|
|
295
321
|
}
|
|
296
|
-
const matchStages = [
|
|
322
|
+
const matchStages = [
|
|
323
|
+
{ $match: { 'member.id': { $eq: params.member.id } } }
|
|
324
|
+
];
|
|
297
325
|
if (typeof ((_b = (_a = params.project) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.$eq) === 'string') {
|
|
298
326
|
matchStages.push({ $match: { 'project.id': { $eq: params.project.id.$eq } } });
|
|
299
327
|
}
|
|
@@ -343,6 +371,32 @@ class MemberRepo {
|
|
|
343
371
|
.exec();
|
|
344
372
|
});
|
|
345
373
|
}
|
|
374
|
+
/**
|
|
375
|
+
* グローバルメンバー作成
|
|
376
|
+
* 2025-07-21~
|
|
377
|
+
*/
|
|
378
|
+
createGlobalMember(params) {
|
|
379
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
380
|
+
if (params.length > 0) {
|
|
381
|
+
yield this.globalMemberModel.insertMany(params.map(({ typeOf, member }) => ({ typeOf, member })));
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
// no op
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* distinctコマンドを使用して、グローバルメンバーのロールを検索する
|
|
390
|
+
*/
|
|
391
|
+
findGlobalRoleNamesByMember(params) {
|
|
392
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
393
|
+
return this.globalMemberModel.distinct('member.hasRole.roleName', {
|
|
394
|
+
'member.id': { $eq: params.member.id.$eq }
|
|
395
|
+
})
|
|
396
|
+
.setOptions({ maxTimeMS: settings_1.MONGO_MAX_TIME_MS })
|
|
397
|
+
.exec();
|
|
398
|
+
});
|
|
399
|
+
}
|
|
346
400
|
projectFields(params, inclusion) {
|
|
347
401
|
return __awaiter(this, void 0, void 0, function* () {
|
|
348
402
|
const conditions = MemberRepo.CREATE_MONGO_CONDITIONS(params);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { IndexDefinition, IndexOptions, Model, Schema, SchemaDefinition } from 'mongoose';
|
|
2
|
+
import * as factory from '../../../../factory';
|
|
3
|
+
type IMemberOfRole = Pick<factory.iam.IMemberOfRole, 'hasRole' | 'id' | 'image' | 'name' | 'typeOf' | 'username'>;
|
|
4
|
+
type IGlobalMember = Pick<factory.iam.IMember, 'typeOf'> & {
|
|
5
|
+
member: IMemberOfRole;
|
|
6
|
+
};
|
|
7
|
+
type IDocType = IGlobalMember;
|
|
8
|
+
type IModel = Model<IDocType>;
|
|
9
|
+
type ISchemaDefinition = SchemaDefinition<IDocType>;
|
|
10
|
+
type ISchema = Schema<IDocType, IModel, {}, {}, {}, {}, ISchemaDefinition, IDocType>;
|
|
11
|
+
declare const modelName = "Member.Global";
|
|
12
|
+
declare const indexes: [d: IndexDefinition, o: IndexOptions][];
|
|
13
|
+
declare function createSchema(): ISchema;
|
|
14
|
+
export { createSchema, IGlobalMember, IModel, indexes, modelName };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.modelName = exports.indexes = void 0;
|
|
4
|
+
exports.createSchema = createSchema;
|
|
5
|
+
const mongoose_1 = require("mongoose");
|
|
6
|
+
const writeConcern_1 = require("../../writeConcern");
|
|
7
|
+
const settings_1 = require("../../../../settings");
|
|
8
|
+
const modelName = 'Member.Global';
|
|
9
|
+
exports.modelName = modelName;
|
|
10
|
+
const schemaDefinition = {
|
|
11
|
+
// globalロール管理なのでprojectは不要
|
|
12
|
+
// project: {
|
|
13
|
+
// type: SchemaTypes.Mixed,
|
|
14
|
+
// required: true
|
|
15
|
+
// },
|
|
16
|
+
typeOf: {
|
|
17
|
+
type: String,
|
|
18
|
+
required: true
|
|
19
|
+
},
|
|
20
|
+
member: {
|
|
21
|
+
type: mongoose_1.SchemaTypes.Mixed,
|
|
22
|
+
required: true
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const schemaOptions = {
|
|
26
|
+
autoIndex: settings_1.MONGO_AUTO_INDEX,
|
|
27
|
+
autoCreate: false,
|
|
28
|
+
collection: 'members.global',
|
|
29
|
+
id: true,
|
|
30
|
+
read: settings_1.MONGO_READ_PREFERENCE,
|
|
31
|
+
writeConcern: writeConcern_1.writeConcern,
|
|
32
|
+
strict: true,
|
|
33
|
+
strictQuery: false,
|
|
34
|
+
timestamps: false,
|
|
35
|
+
versionKey: false,
|
|
36
|
+
toJSON: {
|
|
37
|
+
getters: false,
|
|
38
|
+
virtuals: false,
|
|
39
|
+
minimize: false,
|
|
40
|
+
versionKey: false
|
|
41
|
+
},
|
|
42
|
+
toObject: {
|
|
43
|
+
getters: false,
|
|
44
|
+
virtuals: true,
|
|
45
|
+
minimize: false,
|
|
46
|
+
versionKey: false
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const indexes = [
|
|
50
|
+
[
|
|
51
|
+
{ 'member.id': 1 },
|
|
52
|
+
{
|
|
53
|
+
name: 'uniqueIAMMember',
|
|
54
|
+
unique: true
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
{ 'member.hasRole.roleName': 1, 'member.id': 1 },
|
|
59
|
+
{
|
|
60
|
+
name: 'searchByMemberHasRoleRoleName',
|
|
61
|
+
partialFilterExpression: {
|
|
62
|
+
'member.hasRole.roleName': { $exists: true }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
];
|
|
67
|
+
exports.indexes = indexes;
|
|
68
|
+
/**
|
|
69
|
+
* グロバールIAMメンバースキーマ
|
|
70
|
+
*/
|
|
71
|
+
let schema;
|
|
72
|
+
function createSchema() {
|
|
73
|
+
if (schema === undefined) {
|
|
74
|
+
schema = new mongoose_1.Schema(schemaDefinition, schemaOptions);
|
|
75
|
+
if (settings_1.MONGO_AUTO_INDEX) {
|
|
76
|
+
indexes.forEach((indexParams) => {
|
|
77
|
+
schema === null || schema === void 0 ? void 0 : schema.index(...indexParams);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return schema;
|
|
82
|
+
}
|
|
@@ -11,13 +11,14 @@ export declare class RoleRepo {
|
|
|
11
11
|
constructor(connection: Connection);
|
|
12
12
|
static CREATE_MONGO_CONDITIONS(params: factory.role.organizationRole.ISearchConditions): FilterQuery<IDocType>[];
|
|
13
13
|
projectFields(params: factory.role.organizationRole.ISearchConditions, inclusion: IKeyOfProjection[]): Promise<IRole[]>;
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* distinctコマンドを使用して、ロールから権限を検索する
|
|
16
|
+
*/
|
|
17
|
+
findUniquePermissionsByRoleName(params: {
|
|
15
18
|
roleName: {
|
|
16
19
|
$in: string[];
|
|
17
20
|
};
|
|
18
|
-
}): Promise<
|
|
19
|
-
_id: string;
|
|
20
|
-
}[]>;
|
|
21
|
+
}): Promise<string[]>;
|
|
21
22
|
addPermissionIfNotExists(params: {
|
|
22
23
|
roleName: {
|
|
23
24
|
$eq: factory.role.organizationRole.RoleName;
|
package/lib/chevre/repo/role.js
CHANGED
|
@@ -77,39 +77,42 @@ class RoleRepo {
|
|
|
77
77
|
.exec();
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
// migrate to findDistinctPermissionsByRoleName(2025-07-21~)
|
|
81
|
+
// public async aggregatePermissions(params: {
|
|
82
|
+
// roleName: { $in: string[] };
|
|
83
|
+
// }): Promise<{ _id: string }[]> {
|
|
84
|
+
// const matchStages: IMatchStage[] = [
|
|
85
|
+
// { $match: { roleName: { $in: params.roleName.$in } } }
|
|
86
|
+
// ];
|
|
87
|
+
// const aggregate = this.roleModel.aggregate([
|
|
88
|
+
// ...matchStages,
|
|
89
|
+
// {
|
|
90
|
+
// $unwind: {
|
|
91
|
+
// path: '$permissions'
|
|
92
|
+
// }
|
|
93
|
+
// },
|
|
94
|
+
// {
|
|
95
|
+
// $project: {
|
|
96
|
+
// _id: 0,
|
|
97
|
+
// permission: '$permissions'
|
|
98
|
+
// }
|
|
99
|
+
// },
|
|
100
|
+
// {
|
|
101
|
+
// $group: {
|
|
102
|
+
// _id: '$permission'
|
|
103
|
+
// }
|
|
104
|
+
// }
|
|
105
|
+
// ]);
|
|
106
|
+
// return aggregate.option({ maxTimeMS: MONGO_MAX_TIME_MS })
|
|
107
|
+
// .exec();
|
|
108
|
+
// }
|
|
109
|
+
/**
|
|
110
|
+
* distinctコマンドを使用して、ロールから権限を検索する
|
|
111
|
+
*/
|
|
112
|
+
findUniquePermissionsByRoleName(params) {
|
|
81
113
|
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
];
|
|
85
|
-
const aggregate = this.roleModel.aggregate([
|
|
86
|
-
// ...(typeof params.sort?.productID === 'number')
|
|
87
|
-
// ? [{ $sort: { productID: params.sort.productID } }]
|
|
88
|
-
// : [],
|
|
89
|
-
...matchStages,
|
|
90
|
-
{
|
|
91
|
-
$unwind: {
|
|
92
|
-
path: '$permissions'
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
$project: {
|
|
97
|
-
_id: 0,
|
|
98
|
-
permission: '$permissions'
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
$group: {
|
|
103
|
-
_id: '$permission'
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
]);
|
|
107
|
-
// if (typeof params.limit === 'number' && params.limit > 0) {
|
|
108
|
-
// const page: number = (typeof params.page === 'number' && params.page > 0) ? params.page : 1;
|
|
109
|
-
// aggregate.limit(params.limit * page)
|
|
110
|
-
// .skip(params.limit * (page - 1));
|
|
111
|
-
// }
|
|
112
|
-
return aggregate.option({ maxTimeMS: settings_1.MONGO_MAX_TIME_MS })
|
|
114
|
+
return this.roleModel.distinct('permissions', { roleName: { $in: params.roleName.$in } })
|
|
115
|
+
.setOptions({ maxTimeMS: settings_1.MONGO_MAX_TIME_MS })
|
|
113
116
|
.exec();
|
|
114
117
|
});
|
|
115
118
|
}
|
|
@@ -8,7 +8,7 @@ export type IPermission = string;
|
|
|
8
8
|
/**
|
|
9
9
|
* プロジェクトメンバーの権限を検索する
|
|
10
10
|
*/
|
|
11
|
-
export declare function
|
|
11
|
+
export declare function findProjectPermissionsByMember(params: {
|
|
12
12
|
project: {
|
|
13
13
|
id: string;
|
|
14
14
|
};
|
|
@@ -23,10 +23,20 @@ export declare function searchPermissions(params: {
|
|
|
23
23
|
member: MemberRepo;
|
|
24
24
|
role: RoleRepo;
|
|
25
25
|
}) => Promise<{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
roleNames: string[];
|
|
27
|
+
permissions: string[];
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* グローバル権限を検索する
|
|
31
|
+
*/
|
|
32
|
+
export declare function findGloablPermissionsByMember(params: {
|
|
33
|
+
member: {
|
|
34
|
+
id: string;
|
|
35
|
+
};
|
|
36
|
+
}): (repos: {
|
|
37
|
+
member: MemberRepo;
|
|
38
|
+
role: RoleRepo;
|
|
39
|
+
}) => Promise<{
|
|
40
|
+
roleNames: string[];
|
|
41
|
+
permissions: string[];
|
|
32
42
|
}>;
|
|
@@ -9,14 +9,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
12
|
+
exports.findProjectPermissionsByMember = findProjectPermissionsByMember;
|
|
13
|
+
exports.findGloablPermissionsByMember = findGloablPermissionsByMember;
|
|
13
14
|
/**
|
|
14
15
|
* プロジェクトメンバーの権限を検索する
|
|
15
16
|
*/
|
|
16
|
-
function
|
|
17
|
+
function findProjectPermissionsByMember(params) {
|
|
17
18
|
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
18
19
|
let permissions = [];
|
|
19
|
-
const hasRole =
|
|
20
|
+
// const hasRole = await repos.member.aggregateRoleNames({
|
|
21
|
+
const roleNames = yield repos.member.findRoleNamesByMember({
|
|
20
22
|
project: { id: { $eq: params.project.id } },
|
|
21
23
|
member: {
|
|
22
24
|
id: { $eq: params.member.id },
|
|
@@ -26,9 +28,27 @@ function searchPermissions(params) {
|
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
});
|
|
29
|
-
if (
|
|
30
|
-
permissions =
|
|
31
|
+
if (roleNames.length > 0) {
|
|
32
|
+
// permissions = await repos.role.aggregatePermissions({ roleName: { $in: hasRole.map((r) => r.roleName) } });
|
|
33
|
+
permissions = yield repos.role.findUniquePermissionsByRoleName({ roleName: { $in: roleNames } });
|
|
31
34
|
}
|
|
32
|
-
return {
|
|
35
|
+
return { roleNames, permissions };
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* グローバル権限を検索する
|
|
40
|
+
*/
|
|
41
|
+
function findGloablPermissionsByMember(params) {
|
|
42
|
+
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
let permissions = [];
|
|
44
|
+
const roleNames = yield repos.member.findGlobalRoleNamesByMember({
|
|
45
|
+
member: {
|
|
46
|
+
id: { $eq: params.member.id }
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
if (roleNames.length > 0) {
|
|
50
|
+
permissions = yield repos.role.findUniquePermissionsByRoleName({ roleName: { $in: roleNames } });
|
|
51
|
+
}
|
|
52
|
+
return { roleNames, permissions };
|
|
33
53
|
});
|
|
34
54
|
}
|
package/package.json
CHANGED
|
@@ -49,10 +49,12 @@
|
|
|
49
49
|
"@types/sinon-mongoose": "^1.3.11",
|
|
50
50
|
"@types/uniqid": "^4.1.3",
|
|
51
51
|
"@types/uuid": "^3.4.10",
|
|
52
|
+
"auth0": "4.27.0",
|
|
52
53
|
"coveralls": "^3.1.0",
|
|
53
54
|
"csvtojson": "^2.0.10",
|
|
54
55
|
"eslint": "9.16.0",
|
|
55
56
|
"googleapis": "^85.0.0",
|
|
57
|
+
"jose": "6.0.12",
|
|
56
58
|
"json2csv": "4.5.4",
|
|
57
59
|
"mocha": "10.6.0",
|
|
58
60
|
"mongoose": "8.0.4",
|
|
@@ -113,5 +115,5 @@
|
|
|
113
115
|
"postversion": "git push origin --tags",
|
|
114
116
|
"prepublishOnly": "npm run clean && npm run build && npm test && npm run doc"
|
|
115
117
|
},
|
|
116
|
-
"version": "22.11.0-alpha.
|
|
118
|
+
"version": "22.11.0-alpha.12"
|
|
117
119
|
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// tslint:disable:no-console
|
|
2
|
-
import * as moment from 'moment';
|
|
3
|
-
import * as mongoose from 'mongoose';
|
|
4
|
-
|
|
5
|
-
import { chevre } from '../../../lib/index';
|
|
6
|
-
|
|
7
|
-
const PROJECT_ID = String(process.env.PROJECT_ID);
|
|
8
|
-
const memberId = 'xxx';
|
|
9
|
-
|
|
10
|
-
async function main() {
|
|
11
|
-
await mongoose.connect(<string>process.env.MONGOLAB_URI);
|
|
12
|
-
|
|
13
|
-
const memberRepo = await chevre.repository.Member.createInstance(mongoose.connection);
|
|
14
|
-
const roleRepo = await chevre.repository.Role.createInstance(mongoose.connection);
|
|
15
|
-
|
|
16
|
-
let now: Date;
|
|
17
|
-
|
|
18
|
-
now = new Date();
|
|
19
|
-
const searchPermissionsResult = await (await chevre.service.iam.createService()).searchPermissions({
|
|
20
|
-
project: { id: PROJECT_ID },
|
|
21
|
-
member: {
|
|
22
|
-
id: memberId,
|
|
23
|
-
memberOf: {
|
|
24
|
-
id: PROJECT_ID,
|
|
25
|
-
typeOf: chevre.factory.organizationType.Project
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
})({
|
|
29
|
-
member: memberRepo,
|
|
30
|
-
role: roleRepo
|
|
31
|
-
});
|
|
32
|
-
console.log('time cost:', moment()
|
|
33
|
-
.diff(now));
|
|
34
|
-
|
|
35
|
-
console.log(searchPermissionsResult);
|
|
36
|
-
console.log(searchPermissionsResult.permissions.length);
|
|
37
|
-
|
|
38
|
-
// console.log(aggregateRoleNamesResult);
|
|
39
|
-
// console.log(aggregateRoleNamesResult.length);
|
|
40
|
-
// console.log(aggregatePermissionsResult);
|
|
41
|
-
// console.log(aggregatePermissionsResult.length);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
main()
|
|
45
|
-
.then(console.log)
|
|
46
|
-
.catch(console.error);
|