| import { Response, Router } from 'express'; |
| import * as LdapClient from 'ldapjs'; |
| import * as request from 'request'; |
| import { readFileSync } from 'fs'; |
| |
| import { |
| LDAP, |
| IDENTITY_TOKEN_SOURCE, |
| CUSTOM_IDENTITY_TOKEN_REQUEST_BODY, |
| SSL, |
| } from '../config'; |
| import { HelixRequest, HelixRequestOptions } from './d'; |
| import { TOKEN_EXPIRATION_KEY, TOKEN_RESPONSE_KEY } from '../config'; |
| |
| export class UserCtrl { |
| constructor(router: Router) { |
| // uncomment the following line to use customized login |
| // 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); |
| } |
| |
| // |
| // You may rewrite this function to support your own authorization logic. |
| // Usually it would be helpful to integrate with 3rd party login. |
| // For example: |
| // |
| /* |
| protected authorize(req: HelixRequest, res: Response) { |
| const { isAdmin, username, token } = get_auth_state(); |
| req.session.isAdmin = isAdmin; |
| req.session.username = username; |
| req.session.identityToken = token; |
| res.redirect('/'); |
| } |
| */ |
| |
| protected current(req: HelixRequest, res: Response) { |
| res.json(req.session.username || 'Sign In'); |
| } |
| |
| // |
| // Check the server-side session store, |
| // see if this helix-front ExpressJS server |
| // already knows that the current user is an admin. |
| // |
| protected can(req: HelixRequest, res: Response) { |
| try { |
| return res.json(req.session.isAdmin ? true : false); |
| } catch (err) { |
| throw new Error( |
| `Error from /can logged in admin user session status endpoint: ${err}` |
| ); |
| return false; |
| } |
| } |
| |
| protected login(req: HelixRequest, res: Response) { |
| const credential = req.body; |
| if (!credential.username || !credential.password) { |
| res.status(401).json(false); |
| return; |
| } |
| |
| // check LDAP |
| const ldap = LdapClient.createClient({ url: LDAP.uri }); |
| ldap.bind( |
| credential.username + LDAP.principalSuffix, |
| credential.password, |
| (err) => { |
| if (err) { |
| res.status(401).json(false); |
| } else { |
| // LDAP login success |
| const opts = { |
| filter: |
| '(&(sAMAccountName=' + |
| credential.username + |
| ')(objectcategory=person))', |
| scope: 'sub', |
| }; |
| |
| req.session.username = credential.username; |
| res.set('Username', credential.username); |
| |
| ldap.search(LDAP.base, opts, function (err, result) { |
| let isInAdminGroup = false; |
| result.on('searchEntry', function (entry) { |
| if (entry.object && !err) { |
| const groups = entry.object['memberOf']; |
| for (const group of groups) { |
| const groupName = group.split(',', 1)[0].split('=')[1]; |
| if (groupName == LDAP.adminGroup) { |
| isInAdminGroup = true; |
| |
| // |
| // Get an Identity-Token |
| // if an IDENTITY_TOKEN_SOURCE |
| // is specified in the config |
| // |
| if (IDENTITY_TOKEN_SOURCE) { |
| const body = JSON.stringify({ |
| username: credential.username, |
| password: credential.password, |
| ...CUSTOM_IDENTITY_TOKEN_REQUEST_BODY, |
| }); |
| |
| const options: HelixRequestOptions = { |
| url: IDENTITY_TOKEN_SOURCE, |
| json: '', |
| body, |
| headers: { |
| 'Content-Type': 'application/json', |
| }, |
| agentOptions: { |
| rejectUnauthorized: false, |
| }, |
| }; |
| |
| if (SSL.cafiles.length > 0) { |
| options.agentOptions.ca = readFileSync(SSL.cafiles[0], { |
| encoding: 'utf-8', |
| }); |
| } |
| |
| function callback(error, _res, body) { |
| if (error) { |
| throw new Error( |
| `Failed to get ${IDENTITY_TOKEN_SOURCE} Token: ${error}` |
| ); |
| } else if (body?.error) { |
| throw new Error(body?.error); |
| } else { |
| const parsedBody = JSON.parse(body); |
| req.session.isAdmin = isInAdminGroup; |
| req.session.identityToken = parsedBody; |
| |
| const cookieName = 'helixui_identity.token'; |
| const cookieValue = |
| parsedBody.value[TOKEN_RESPONSE_KEY]; |
| const cookieExpiresDate = new Date( |
| parsedBody.value[TOKEN_EXPIRATION_KEY] |
| ); |
| const cookieOptions = { |
| expires: cookieExpiresDate, |
| }; |
| res.cookie(cookieName, cookieValue, cookieOptions); |
| res.json(isInAdminGroup); |
| |
| return parsedBody; |
| } |
| } |
| request.post(options, callback); |
| } else { |
| req.session.isAdmin = isInAdminGroup; |
| res.json(isInAdminGroup); |
| } |
| // |
| // END Get an Identity-Token |
| // |
| } |
| } |
| } else { |
| req.session.isAdmin = isInAdminGroup; |
| res.json(isInAdminGroup); |
| } |
| }); |
| }); |
| } |
| } |
| ); |
| } |
| } |