add ldap support
Project: http://git-wip-us.apache.org/repos/asf/helix/repo Commit: http://git-wip-us.apache.org/repos/asf/helix/commit/d60d51b2 Tree: http://git-wip-us.apache.org/repos/asf/helix/tree/d60d51b2 Diff: http://git-wip-us.apache.org/repos/asf/helix/diff/d60d51b2 Branch: refs/heads/master Commit: d60d51b24c20b73a9b3fba906674479f4fba17e0 Parents: e94b82a Author: Vivo Xu <[email protected]> Authored: Fri Mar 9 15:18:01 2018 -0800 Committer: Vivo Xu <[email protected]> Committed: Wed Aug 8 15:39:33 2018 -0700 ---------------------------------------------------------------------- helix-front/client/app/app.component.html | 2 +- helix-front/client/app/app.component.ts | 41 +++++++++++++++++++- helix-front/client/app/core/user.service.ts | 10 +++++ .../input-dialog/input-dialog.component.html | 14 +++++-- helix-front/package.json | 1 + helix-front/server/config.ts | 6 +++ helix-front/server/controllers/user.ts | 36 ++++++++++++++++- 7 files changed, 104 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/helix/blob/d60d51b2/helix-front/client/app/app.component.html ---------------------------------------------------------------------- diff --git a/helix-front/client/app/app.component.html b/helix-front/client/app/app.component.html index d30b162..b199228 100644 --- a/helix-front/client/app/app.component.html +++ b/helix-front/client/app/app.component.html @@ -5,7 +5,7 @@ <span class="helix-title">Helix</span> </a> <span fxFlex="1 1 auto"></span> - <a mat-button> + <a mat-button (click)="login()"> <mat-icon>person</mat-icon> {{ currentUser | async }} </a> http://git-wip-us.apache.org/repos/asf/helix/blob/d60d51b2/helix-front/client/app/app.component.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/app.component.ts b/helix-front/client/app/app.component.ts index 31de982..13d7426 100644 --- a/helix-front/client/app/app.component.ts +++ b/helix-front/client/app/app.component.ts @@ -7,11 +7,14 @@ import { NavigationCancel, NavigationError } from '@angular/router'; +import { MatDialog } from '@angular/material'; import { Angulartics2Piwik } from 'angulartics2'; import { environment } from '../environments/environment'; import { UserService } from './core/user.service'; +import { InputDialogComponent } from './shared/dialog/input-dialog/input-dialog.component'; +import { HelperService } from './shared/helper.service'; @Component({ selector: 'hi-root', @@ -30,7 +33,9 @@ export class AppComponent implements OnInit { protected route: ActivatedRoute, protected router: Router, protected angulartics: Angulartics2Piwik, - protected service: UserService + protected dialog: MatDialog, + protected service: UserService, + protected helper: HelperService ) { router.events.subscribe(event => { if (event instanceof NavigationStart) { @@ -57,4 +62,38 @@ export class AppComponent implements OnInit { } }); } + + login() { + this.dialog + .open(InputDialogComponent, { + data: { + title: 'Login', + message: 'Please enter your LDAP username and password to continue:', + values: { + username: { + label: 'Username' + }, + password: { + label: 'Password', + type: 'password' + } + } + } + }) + .afterClosed() + .subscribe(result => { + if (result && result.username.value && result.password.value) { + this.service + .login(result.username.value, result.password.value) + .subscribe( + isAuthroized => { + if (isAuthroized) { + location.reload(); + } + }, + error => this.helper.showError(error) + ); + } + }); + } } http://git-wip-us.apache.org/repos/asf/helix/blob/d60d51b2/helix-front/client/app/core/user.service.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/core/user.service.ts b/helix-front/client/app/core/user.service.ts index 3336c1f..21676af 100644 --- a/helix-front/client/app/core/user.service.ts +++ b/helix-front/client/app/core/user.service.ts @@ -20,6 +20,16 @@ export class UserService { .catch(_ => _); } + public login(username: string, password: string): Observable<boolean> { + return this.http + .post( + `${ Settings.userAPI }/login`, + { username: username, password: password }, + { headers: this.getHeaders() } + ) + .map(response => response.json()); + } + protected getHeaders() { let headers = new Headers(); headers.append('Accept', 'application/json'); http://git-wip-us.apache.org/repos/asf/helix/blob/d60d51b2/helix-front/client/app/shared/dialog/input-dialog/input-dialog.component.html ---------------------------------------------------------------------- diff --git a/helix-front/client/app/shared/dialog/input-dialog/input-dialog.component.html b/helix-front/client/app/shared/dialog/input-dialog/input-dialog.component.html index bf4cd78..153dda3 100644 --- a/helix-front/client/app/shared/dialog/input-dialog/input-dialog.component.html +++ b/helix-front/client/app/shared/dialog/input-dialog/input-dialog.component.html @@ -4,8 +4,8 @@ <section> {{ message }} </section> - <section *ngFor="let name of getKeys(values)"> - <section *ngIf="values[name].type === 'boolean'"> + <section *ngFor="let name of getKeys(values)" [ngSwitch]="values[name].type"> + <section *ngSwitchCase="'boolean'"> {{ values[name].label }}: <mat-slide-toggle [name]="name" @@ -13,7 +13,15 @@ {{ values[name].value ? 'True' : 'False' }} </mat-slide-toggle> </section> - <mat-form-field *ngIf="values[name].type !== 'boolean'"> + <mat-form-field *ngSwitchCase="'password'"> + <input matInput + type="password" + [name]="name" + [(ngModel)]="values[name].value" + [placeholder]="values[name].label" + required> + </mat-form-field> + <mat-form-field *ngSwitchDefault> <input matInput [name]="name" [(ngModel)]="values[name].value" http://git-wip-us.apache.org/repos/asf/helix/blob/d60d51b2/helix-front/package.json ---------------------------------------------------------------------- diff --git a/helix-front/package.json b/helix-front/package.json index 846ff78..844980b 100644 --- a/helix-front/package.json +++ b/helix-front/package.json @@ -44,6 +44,7 @@ "express": "^4.15.3", "express-session": "^1.15.6", "hammerjs": "^2.0.8", + "ldap-client": "^3.1.3", "lodash": "^4.17.4", "moment": "^2.22.2", "morgan": "^1.8.2", http://git-wip-us.apache.org/repos/asf/helix/blob/d60d51b2/helix-front/server/config.ts ---------------------------------------------------------------------- diff --git a/helix-front/server/config.ts b/helix-front/server/config.ts index 1f49dd2..1a4265b 100644 --- a/helix-front/server/config.ts +++ b/helix-front/server/config.ts @@ -14,6 +14,12 @@ export const SSL = { cafiles: [] }; +export const LDAP = { + uri: 'ldap://example.com', + base: 'DC=example,DC=com', + principalSuffix: '@example.com' +}; + export function CheckAdmin(username: string, callback: (boolean) => void) { callback(username === 'root'); } http://git-wip-us.apache.org/repos/asf/helix/blob/d60d51b2/helix-front/server/controllers/user.ts ---------------------------------------------------------------------- diff --git a/helix-front/server/controllers/user.ts b/helix-front/server/controllers/user.ts index 84d2c11..609b9f8 100644 --- a/helix-front/server/controllers/user.ts +++ b/helix-front/server/controllers/user.ts @@ -1,13 +1,15 @@ import { Request, Response, Router } from 'express'; import * as request from 'request'; +import * as LdapClient from 'ldap-client'; -import { CheckAdmin } from '../config'; +import { LDAP, CheckAdmin } from '../config'; export class UserCtrl { constructor(router: Router) { router.route('/user/authorize').get(this.authorize); + router.route('/user/login').post(this.login.bind(this)); router.route('/user/current').get(this.current); router.route('/user/can').get(this.can); } @@ -37,4 +39,36 @@ export class UserCtrl { protected can(req: Request, res: Response) { res.json(req.session.isAdmin ? true : false); } + + protected login(req: Request, res: Response) { + const credential = req.body; + if (!credential.username || !credential.password) { + res.status(401).json(false); + return; + } + + // check LDAP + const ldap = new LdapClient({ uri: LDAP.uri, base: LDAP.base }, err => { + if (err) { + res.status(500).json(err); + } + }); + + ldap.bind({ + binddn: credential.username + LDAP.principalSuffix, + password: credential.password + }, err => { + if (err) { + res.status(401).json(false); + } else { + // authroized + req.session.username = credential.username; + CheckAdmin(req.session.username, (isAdmin: boolean) => { + req.session.isAdmin = isAdmin; + res.json(true); + }); + } + }); + } + }
