1
0
mirror of https://github.com/bitwarden/directory-connector synced 2025-12-10 21:33:20 +00:00

stub out directory service auth/querying

This commit is contained in:
Kyle Spearrin
2018-04-27 14:13:22 -04:00
parent e7809b405d
commit e7787ea95c
8 changed files with 204 additions and 37 deletions

18
package-lock.json generated
View File

@@ -4572,14 +4572,14 @@
}
},
"googleapis": {
"version": "28.1.0",
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-28.1.0.tgz",
"integrity": "sha512-+kDXcTq5YUGjrzNOjE6eDaSQ/92bpBrDqj5TGz/AwhnXDqNVGMQey6eRQNMPdrJMYYBSZGYHza1CSIxO/LHEeA==",
"version": "29.0.0",
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-29.0.0.tgz",
"integrity": "sha512-qac2RSPObw80AOvSPV9hus8VyRxrdaTnsUmttdO6hO12fBE5jI/R9XytUOuB3Z/4LP+1NpprNyKSHm9xXuJx2w==",
"requires": {
"google-auth-library": "1.4.0",
"pify": "3.0.0",
"qs": "6.5.1",
"string-template": "1.0.0",
"url-template": "2.0.8",
"uuid": "3.2.1"
}
},
@@ -8961,11 +8961,6 @@
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
"dev": true
},
"string-template": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/string-template/-/string-template-1.0.0.tgz",
"integrity": "sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y="
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
@@ -10068,6 +10063,11 @@
"prepend-http": "1.0.4"
}
},
"url-template": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
"integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE="
},
"use": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz",

View File

@@ -96,7 +96,7 @@
"electron-log": "2.2.14",
"electron-store": "1.3.0",
"electron-updater": "2.21.4",
"googleapis": "28.1.0",
"googleapis": "29.0.0",
"keytar": "4.1.0",
"ldapjs": "1.0.2",
"lunr": "2.1.6",

View File

@@ -1,3 +1,7 @@
<i class="fa fa-rocket"></i>
The dashboard!!
<button (click)="gsuite()">G Suite</button>
<button (click)="ldap()">LDAP</button>
<button (click)="azuread()">Azure AD</button>

View File

@@ -12,6 +12,10 @@ import { I18nService } from 'jslib/abstractions/i18n.service';
import { ModalComponent } from 'jslib/angular/components/modal.component';
import { AzureDirectoryService } from '../../services/azure-directory.service';
import { GSuiteDirectoryService } from '../../services/gsuite-directory.service';
import { LdapDirectoryService } from '../../services/ldap-directory.service';
@Component({
selector: 'app-dashboard',
templateUrl: 'dashboard.component.html',
@@ -21,4 +25,19 @@ export class DashboardComponent {
constructor(analytics: Angulartics2, toasterService: ToasterService,
i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver) { }
gsuite() {
const gsuite = new GSuiteDirectoryService();
const entries = gsuite.getEntries();
}
ldap() {
const gsuite = new LdapDirectoryService();
const entries = gsuite.getEntries();
}
azuread() {
const gsuite = new AzureDirectoryService();
const entries = gsuite.getEntries();
}
}

View File

@@ -1,12 +1,74 @@
import * as graph from '@microsoft/microsoft-graph-client';
import * as https from 'https';
import * as querystring from 'querystring';
import { DirectoryService } from 'src/services/directory.service';
const Key = '';
const ApplicationId = '';
const Tenant = '';
export class AzureDirectoryService implements DirectoryService {
getEntries(force = false) {
private client: graph.Client;
async getEntries(force = false) {
this.client = graph.Client.init({
authProvider: (done) => {
const data = querystring.stringify({
client_id: ApplicationId,
client_secret: Key,
grant_type: 'client_credentials',
scope: 'https://graph.microsoft.com/.default',
});
const req = https.request({
host: 'login.microsoftonline.com',
path: '/' + Tenant + '/oauth2/v2.0/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(data),
},
}, (res) => {
res.setEncoding('utf8');
res.on('data', (chunk: string) => {
const d = JSON.parse(chunk);
if (res.statusCode === 200 && d.access_token != null) {
done(null, d.access_token);
} else if (d.error != null && d.error_description != null) {
done(d.error + ' (' + res.statusCode + '): ' + d.error_description, null);
} else {
done('Unknown error (' + res.statusCode + ').', null);
}
});
}).on('error', (err) => {
done(err, null);
});
req.write(data);
req.end();
},
});
await this.getUsers();
await this.getGroups();
}
private getUsers() {
private async getUsers() {
const request = this.client.api('/users/delta');
const users = await request.get();
console.log(users);
}
private async getGroups() {
const request = this.client.api('/groups/delta');
const groups = await request.get();
console.log(groups);
groups.value.forEach(async (g: any) => {
const membersRequest = this.client.api('/groups/' + g.id + '/members');
const members = await membersRequest.get();
console.log(members);
});
}
}

View File

@@ -1,14 +1,69 @@
import { JWT } from 'google-auth-library';
import { google, GoogleApis } from 'googleapis';
import { Admin } from 'googleapis/build/src/apis/admin/directory_v1';
import { DirectoryService } from 'src/services/directory.service';
const PrivateKey = '';
const ClientEmail = '';
const AdminEmail = '';
const Domain = '';
export class GSuiteDirectoryService implements DirectoryService {
getEntries(force = false) {
private client: JWT;
private service: Admin;
private authParams: any;
constructor() {
this.service = google.admin<Admin>('directory_v1');
}
async getEntries(force = false) {
await this.auth();
await this.getUsers();
await this.getGroups();
}
private async getUsers() {
const service = google.admin<Admin>('directory_v1');
const groups = await service.groups.list();
const response = await this.service.users.list(this.authParams);
console.log(response);
}
private async getGroups() {
const response = await this.service.groups.list(this.authParams);
console.log(response);
if (response.data.groups.length === 0) {
return;
}
response.data.groups.forEach(async (g) => {
const params: any = Object.assign({
groupKey: g.id,
}, this.authParams);
const members = await this.service.members.list(params);
console.log(members);
});
}
private async auth() {
this.client = new google.auth.JWT({
email: ClientEmail,
key: PrivateKey,
subject: AdminEmail,
scopes: [
'https://www.googleapis.com/auth/admin.directory.user.readonly',
'https://www.googleapis.com/auth/admin.directory.group.readonly',
'https://www.googleapis.com/auth/admin.directory.group.member.readonly',
],
});
await this.client.authorize();
this.authParams = {
auth: this.client,
domain: Domain,
};
// TODO: add customer?
}
}

View File

@@ -2,38 +2,64 @@ import * as ldap from 'ldapjs';
import { DirectoryService } from 'src/services/directory.service';
const Url = 'ldap://ldap.forumsys.com:389';
const Username = 'cn=read-only-admin,dc=example,dc=com';
const Password = 'password';
export class LdapDirectoryService implements DirectoryService {
getEntries(force = false) {
private client: ldap.Client;
async getEntries(force = false) {
await this.auth();
await this.getUsers();
}
private getUsers() {
const client = ldap.createClient({
url: 'ldap://127.0.0.1:1389'
});
const options: ldap.SearchOptions = {
filter: '(&(l=Seattle)(email=*@foo.com))',
filter: null,
scope: 'sub',
attributes: ['dn', 'sn', 'cn']
attributes: ['dn', 'sn', 'cn'],
};
client.search('o=example', options, (error, response) => {
if (error != null) {
return new Promise((resolve, reject) => {
this.client.search('dc=example,dc=com', options, (err, res) => {
if (err != null) {
console.error('search error: ' + err);
reject(err);
return;
}
response.on('searchEntry', (entry) => {
console.log('entry: ' + JSON.stringify(entry.object));
res.on('searchEntry', (entry) => {
console.log(entry);
});
response.on('searchReference', (referral) => {
res.on('searchReference', (referral) => {
console.log('referral: ' + referral.uris.join());
});
response.on('error', (err) => {
console.error('error: ' + err.message);
res.on('error', (resErr) => {
console.error('error: ' + resErr.message);
reject(resErr);
});
response.on('end', (result) => {
res.on('end', (result) => {
console.log('status: ' + result.status);
});
resolve();
});
});
}
private async auth() {
return new Promise((resolve, reject) => {
this.client = ldap.createClient({
url: Url,
});
this.client.bind(Username, Password, (err) => {
if (err != null) {
reject(err);
} else {
resolve();
}
});
});
}
}

View File

@@ -46,7 +46,7 @@ const common = {
},
plugins: [],
resolve: {
extensions: ['.tsx', '.ts', '.js'],
extensions: ['.tsx', '.ts', '.js', '.json'],
alias: {
jslib: path.join(__dirname, 'jslib/src')
},
@@ -136,6 +136,7 @@ const renderer = {
filename: '[name].js.map',
include: ['app/main.js']
}),
new webpack.DefinePlugin({ 'global.GENTLY': false }),
extractCss
]
};