auth0-extensions/auth0-sso-dashboard-extension

View on GitHub
server/lib/queries.js

Summary

Maintainability
B
4 hrs
Test Coverage
F
41%
import _ from 'lodash';
import Promise from 'bluebird';
import request from 'superagent';
import memoizer from 'lru-memoizer';
import { managementApi, ValidationError } from 'auth0-extension-tools';

import config from './config';
import logger from './logger';
import multipartRequest from './multipartRequest';


const getAuthorizationApiUrl = () => {
  if (config('AUTHZ_API_DEV_URL')) {
    return config('AUTHZ_API_DEV_URL');
  }

  const publicUrl = config('PUBLIC_WT_URL');

  if (publicUrl[publicUrl.length - 1] === '/') {
    publicUrl[publicUrl.length - 1] = '';
  }

  const authorizationApiUrl = process.env.AUTHZ_API_URL;
  const splittedUrl = publicUrl.split('/');

  splittedUrl[splittedUrl.length - 1] = authorizationApiUrl;

  return splittedUrl.join('/');
};

/*
 * Get authz api access token
 */
const getAuthorizationToken = () =>
  new Promise((resolve, reject) => {
    const body = {
      client_id: config('AUTH0_CLIENT_ID'),
      client_secret: config('AUTH0_CLIENT_SECRET'),
      audience: 'urn:auth0-authz-api',
      grant_type: 'client_credentials'
    };

    request('POST', `https://${config('AUTH0_DOMAIN')}/oauth/token`)
      .send(body)
      .set('Content-Type', 'application/json')
      .end((err, res) => {
        if (err || !res.body || !res.body.access_token) {
          logger.error(res.body);
          return reject(err);
        }

        return resolve(res.body.access_token);
      });
  });

const getAuthorizationTokenCached = Promise.promisify(
  memoizer({
    load: (callback) => {
      getAuthorizationToken()
          .then(accessToken => callback(null, accessToken))
          .catch(err => callback(err));
    },
    hash: () => 'auth0-authz-apiToken',
    max: 100,
    maxAge: 60 * 60000
  }
  ));

export const getGroups = () =>
  new Promise((resolve, reject) =>
    getAuthorizationTokenCached()
      .then((token) => {
        if (!token) {
          return resolve(null);
        }

        return request('GET', `${getAuthorizationApiUrl()}/groups`)
          .set('Content-Type', 'application/json')
          .set('Authorization', `Bearer ${token}`)
          .end((err, res) => {
            if (err) {
              logger.error(res.body);
              return reject(err);
            }

            return resolve(res.body.groups || []);
          });
      })
      .catch(reject)
  );

export const getGroupsForUser = (userId) =>
  new Promise((resolve, reject) =>
    getAuthorizationTokenCached()
      .then((token) => {
        if (!token) {
          return resolve(null);
        }

        if (!userId) {
          return reject(new ValidationError('User ID is required.'));
        }

        return request('GET', `${getAuthorizationApiUrl()}/users/${userId}/groups/calculate`)
          .set('Content-Type', 'application/json')
          .set('Authorization', `Bearer ${token}`)
          .end((err, res) => {
            if (err) {
              logger.error(res.body);
              return reject(err);
            }

            // eslint-disable-next-line no-underscore-dangle
            const groupIDs = _.map(res.body || [], (item) => item._id);

            return resolve(groupIDs);
          });
      })
      .catch(reject)
  );


const getToken = (req) => {
  const isAdministrator = req.user && req.user.access_token &&
    req.user.access_token.length;
  if (isAdministrator) {
    return Promise.resolve(req.user.access_token);
  }

  return managementApi.getAccessTokenCached(
    config('AUTH0_DOMAIN'),
    config('AUTH0_CLIENT_ID'),
    config('AUTH0_CLIENT_SECRET'),
  );
};

const makeRequest = (req, path, method, payload) =>
  new Promise((resolve, reject) => getToken(req).then((token) => {
    request(method, `https://${config('AUTH0_DOMAIN')}/api/v2/${path}`)
      .query(method === 'GET' ? payload : {})
      .send(method === 'GET' ? null : payload || {})
      .set('Content-Type', 'application/json')
      .set('Authorization', `Bearer ${token}`)
      .end((err, res) => {
        if (err) {
          if (res && res.body) {
            logger.error(res.body);
          }

          return reject(err);
        }

        return resolve(res.body);
      });
  }),
);

export const getResourceServer = (req, audience) =>
  multipartRequest(req.auth0, 'resourceServers')
    .then((apis) => {
      const api = apis.filter(item => item.identifier === audience);
      return api.length && api[0];
    });

export const createResourceServer = (req) => {
  const payload = {
    name: config('API_NAME') || 'SSO Dashboard API',
    identifier: config('API_AUDIENCE') || 'urn:auth0-sso-dashboard',
    signing_alg: 'RS256',
    scopes: [
      { value: 'read:applications', description: 'Get applications' },
      { value: 'manage:applications', description: 'Manage applications' }
    ],
    token_lifetime: 86400
  };

  return makeRequest(req, 'resource-servers', 'POST', payload);
};

export const deleteResourceServer = req =>
  getResourceServer(req, 'urn:auth0-sso-dashboard')
    .then((api) => {
      if (api.id) {
        return makeRequest(req, `resource-servers/${api.id}`, 'DELETE');
      }

      return Promise.resolve();
    });

const getGrantId = req =>
  makeRequest(req, 'client-grants', 'GET', { client_id: config('AUTH0_CLIENT_ID'), audience: 'urn:auth0-authz-api' })
    .then(grants => grants.filter(item => (item.client_id === config('AUTH0_CLIENT_ID') && item.audience === 'urn:auth0-authz-api')))
    .then(grants => grants[0] && grants[0].id);


export const addGrant = req =>
  makeRequest(req, 'client-grants', 'POST', {
    client_id: config('AUTH0_CLIENT_ID'),
    audience: 'urn:auth0-authz-api',
    scope: [ 'read:users', 'read:groups' ]
  });

export const removeGrant = req =>
  getGrantId(req)
    .then(id => {
      if (id) {
        return makeRequest(req, `client-grants/${id}`, 'DELETE');
      }

      return Promise.resolve();
    });