Add static json adapter to serve user groups
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 { Group, GroupsJson, GroupsResponse, IdentityApiAdapter } from './types';
|
||||
import fs from 'fs-extra';
|
||||
import express from 'express';
|
||||
import path from 'path';
|
||||
|
||||
const GROUPS_JSON_FILE = path.join(__dirname, 'data', 'userGroups.json');
|
||||
|
||||
export class StaticJsonAdapter implements IdentityApiAdapter {
|
||||
private readonly groups: Group[];
|
||||
|
||||
constructor() {
|
||||
const groupsJson: GroupsJson = fs.readJsonSync(GROUPS_JSON_FILE, {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
this.groups = groupsJson.groups;
|
||||
}
|
||||
|
||||
getUserGroups(
|
||||
req: express.Request,
|
||||
res: express.Response,
|
||||
): express.Response<GroupsResponse> {
|
||||
const user = req.params.user;
|
||||
const type = req.query.type?.toString() ?? '';
|
||||
|
||||
const userGroups = this._getUserGroups(this.groups, user);
|
||||
const groups = this.filterGroupsByType(userGroups, type);
|
||||
return res.json({ groups });
|
||||
}
|
||||
|
||||
_getUserGroups(groups: Group[], user: string) {
|
||||
const userGroups: Set<Group> = new Set();
|
||||
groups.forEach(group => {
|
||||
if (this.isUserInGroup(group, user)) {
|
||||
userGroups.add(group);
|
||||
}
|
||||
|
||||
if (group.children) {
|
||||
const userSubGroups = this._getUserGroups(group.children, user) ?? [];
|
||||
const isUserInSubGroup = Boolean(userSubGroups.length);
|
||||
if (isUserInSubGroup) {
|
||||
userGroups.add(group);
|
||||
}
|
||||
userSubGroups.forEach(subGroup => userGroups.add(subGroup));
|
||||
}
|
||||
});
|
||||
return Array.from(userGroups);
|
||||
}
|
||||
|
||||
private filterGroupsByType = (userGroups: Group[], type: string) => {
|
||||
const groups = type
|
||||
? userGroups
|
||||
.filter((group: Group) => group.type === type)
|
||||
.map(group => ({ name: group.name, type: group.type }))
|
||||
: userGroups.map(group => ({
|
||||
name: group.name,
|
||||
type: group.type,
|
||||
}));
|
||||
return groups;
|
||||
};
|
||||
|
||||
private isUserInGroup = (group: Group, user: string): boolean => {
|
||||
if (group.members) {
|
||||
const groupMembers = group.members;
|
||||
const groupsWithUser = groupMembers.filter(
|
||||
member => member.name === user,
|
||||
);
|
||||
return Boolean(groupsWithUser.length);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"groups": [
|
||||
{
|
||||
"name": "engineering",
|
||||
"type": "org",
|
||||
"children": [
|
||||
{
|
||||
"name": "authentication",
|
||||
"type": "team",
|
||||
"members": [{ "name": "kent" }, { "name": "dobbs" }]
|
||||
},
|
||||
{
|
||||
"name": "checkout",
|
||||
"type": "team",
|
||||
"members": [{ "name": "don" }, { "name": "abramev" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
export * from './StaticJsonAdapter';
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 express from 'express';
|
||||
|
||||
export type User = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type Group = {
|
||||
name: string;
|
||||
type: string;
|
||||
members?: User[];
|
||||
children?: Group[];
|
||||
};
|
||||
|
||||
export type GroupsJson = {
|
||||
groups: Group[];
|
||||
};
|
||||
|
||||
export type GroupsResponse = {
|
||||
groups: Group[];
|
||||
};
|
||||
|
||||
export interface IdentityApiAdapter {
|
||||
getUserGroups(
|
||||
req: express.Request,
|
||||
res: express.Response,
|
||||
): express.Response<GroupsResponse>;
|
||||
}
|
||||
@@ -17,21 +17,25 @@
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { Logger } from 'winston';
|
||||
import { StaticJsonAdapter } from '../adapters';
|
||||
import { IdentityApiAdapter } from '../adapters/types';
|
||||
|
||||
export interface RouterOptions {
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
const makeRouter = (adapter: IdentityApiAdapter): express.Router => {
|
||||
const router = Router();
|
||||
router.get('/users/:user/groups', adapter.getUserGroups.bind(adapter));
|
||||
return router;
|
||||
};
|
||||
|
||||
export async function createRouter(
|
||||
options: RouterOptions,
|
||||
): Promise<express.Router> {
|
||||
const router = Router();
|
||||
const logger = options.logger;
|
||||
|
||||
router.use('/ping', (_, res) => {
|
||||
logger.info('heartbeat for identity service');
|
||||
res.send('pong');
|
||||
});
|
||||
|
||||
return router;
|
||||
logger.info('Initializing identity provider');
|
||||
const adapter = new StaticJsonAdapter();
|
||||
return makeRouter(adapter);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user