В предыдущей статье мы подробно рассказали, как вы можете настроить OAuth с FeathersJs для типичной интеграции провайдеров социальной идентификации, таких как Google, в ваше приложение. Однако предприятиям часто требуются решения, способные интегрироваться с их каталогами за корпоративным брандмауэром.

Преамбула

Идентификация как услуга (IDaaS) - это облачная аутентификация, управляемая сторонним поставщиком. Все большее число компаний выбирают IDaaS для предоставления возможностей федерации, а не локальные решения федерации. Обычно это позволяет организациям использовать единый вход с SAML или OpenID Connect для обеспечения безопасного доступа к их растущему количеству программного обеспечения и приложений SaaS.

В этой статье мы подробно рассказываем, как интегрировать ваше приложение FeathersJS с двумя поставщиками IDaaS: AWS Cognito и OneLogin.

Цель не состоит в том, чтобы подробно описать полную настройку для каждого поставщика, потому что это действительно зависит от потребностей целевого предприятия. Вместо этого мы хотели бы объяснить, как вам нужно настроить приложение FeathersJS для плавной интеграции с ним.

AWS Cognito

Вот основные вещи, которые вам нужно сделать в первую очередь на стороне AWS, документация AWS содержит все, что вам нужно (и даже больше!):

Для клиентского приложения позаботьтесь о том, чтобы правильно настроить URL-адрес обратного вызова вашего бэкэнда (по умолчанию http://your-domain.com/auth/cognito/callback). Затем выберите «Предоставление кода авторизации» в разделе «Разрешенные потоки OAuth». И последнее, но не менее важное: добавьте свой «Пул пользователей Cognito» в качестве одного из «Включенных поставщиков удостоверений», а также внешних поставщиков удостоверений.

Как описано в нашей предыдущей статье, используйте модуль перья-аутентификация и его плагин oauth2, чтобы включить OAuth с поставщиком AWS Cognito и соответствующую стратегию паспорта. Затем измените конфигурацию вашего приложения config/default.json, чтобы интегрировать настройки Cognito следующим образом:

{
  ...
  "authentication": {
    ...
    cognito: {
      clientID: 'xxx',
      clientSecret: 'xxx',
      clientDomain: 'https://your-app.auth.eu-west-1.amazoncognito.com',
      callbackURL: 'https://your-domain.com/auth/cognito/callback',
      successRedirect: 'https://your-domain.com/',
      region: 'eu-west-1'
    }
  }
}

Наконец, настройте приложение для использования стратегии аутентификации Cognito:

...
import configuration from 'feathers-configuration'
import authentication from 'feathers-authentication'
import jwt from 'feathers-authentication-jwt'
import local from 'feathers-authentication-local'
import oauth2 from 'feathers-authentication-oauth2'
import CognitoStrategy from 'passport-oauth2-cognito'
import Verifier from './verifier'
let app = feathers()
// Load app configuration first
app.configure(configuration())
// Set up authentication
const config = app.get('authentication')
app.configure(authentication(config))
app.configure(jwt())
app.configure(local())
app.configure(oauth2({
  name: 'cognito',
  Strategy: CognitoStrategy,
  Verifier
}))

Как видите, вам нужно будет настроить Verifier, то есть объект, отвечающий за обработку ответа провайдера, чтобы все работало гладко. Действительно, верификатор по умолчанию проверяет возвращенный id в профиле пользователя, но Cognito обрабатывает его, используя вместо этого предметное утверждение токена. Morevoer, верификатор по умолчанию проверяет, вошли ли вы уже в систему со своим провайдером, просматривая существующего пользователя с целевым полем providerId (например, githubId). Если он его находит, он обновляет информацию профиля существующего пользователя, в противном случае создается новый пользователь. Поэтому, если вы хотите однозначно идентифицировать свои учетные записи пользователей по полю email и входить в систему с разными поставщиками, где один и тот же адрес электронной почты используется для разных учетных записей, это в конечном итоге не удастся. Далее вы найдете полный настраиваемый верификатор. В качестве входных данных он берет путь к полю электронной почты в каждом профиле поставщика и преобразует предметное утверждение в идентификатор пользователя, требуемый FeathersJs.

По умолчанию информация каждого профиля поставщика будет храниться во вложенном объекте, ключ которого назван в соответствии с именем поставщика. Вы можете добавить ловушку для «извлечения» и / или «преобразования» соответствующих данных для вашей собственной модели пользователя при первом входе в систему:

function processProfile(provider, user) {
  let profile = user[provider].profile
  // As an example extract the user email
  if (profile.email) {
    user.email = profile.email
  }
  if (profile.name) {
    user.name = profile.name
  }
}
app.service('users').hooks({
  before: {
    create: [ (hook) => processProfile('cognito', hook.data) ],
    update: []
  }
})

OneLogin

Предыдущая настройка аналогичным образом применима для работы вашего приложения с OneLogin с помощью OpenID Connect. Вам просто нужно будет использовать нашу стратегию паспорта OpenID Connect, основанную на форке паспорт-openidconnect. Действительно, исходный модуль оказался в устаревшем режиме, и нам нужно было интегрировать PR, позволяющий передавать учетные данные клиента в заголовках авторизации, а не внутри URL-адреса, как того требует OneLogin, и исправление, чтобы обеспечить бесперебойную работу с Cognito as. Что ж. Конфигурация вашего приложения config/default.json для интеграции настроек OneLogin будет выглядеть следующим образом:

{
  ...
  "authentication": {
    ...
    oidc: {
      clientID: 'xxx',
      clientSecret: 'xxx',
      issuer: 'https://openid-connect-eu.onelogin.com/oidc',
      authorizationURL: 'https://your-app.onelogin.com/oidc/auth',
      tokenURL: 'https://your-app.onelogin.com/oidc/token',
      userInfoURL: 'https://your-app.onelogin.com/oidc/me',
      callbackURL: 'https://your-domain.com/auth/oidc/callback',
      successRedirect: 'https://your-domain.com/',
      state: false,
      sessionKey: 'your-app',
      useAuthorizationHeaderForToken: true,
      scope: ['email', 'profile']
    }
  }
}

По умолчанию стратегия паспорта OpenID Connect управляет состоянием для защиты от атак межсайтового скриптинга с использованием экспресс-сессии. Однако у нас были проблемы с его работой с FeathersJS. К счастью, стратегия позволяет настроить собственное управление состоянием, реализовав свой интерфейс хранилища сеансов:

...
import configuration from 'feathers-configuration'
import authentication from 'feathers-authentication'
import jwt from 'feathers-authentication-jwt'
import local from 'feathers-authentication-local'
import oauth2 from 'feathers-authentication-oauth2'
import OpenIDStrategy from 'passport-openidconnect'
import Verifier from './verifier'
let app = feathers()
// Load app configuration first
app.configure(configuration())
// Set up authentication
const config = app.get('authentication')
app.configure(authentication(config))
app.configure(jwt())
app.configure(local())
app.configure(oauth2({
  name: 'oidc',
  Strategy: OpenIDStrategy,
  Verifier,
  store: {
    store (req, meta, cb) {
      let nonce = generateKey()
      let state = Object.assign({ nonce }, meta)
      req.oidc = state
      return cb(null, nonce)
    },
    verify (req, state, cb) {
      if (req.oidc.nonce !== state) {
        return callback(null, false, { message: 'Invalid authorization request state.' })
      }
      return cb(null, true, req.oidc)
    }
  }
}))

Вывод

Мы надеемся, что теперь вы знаете, как подготовить приложение FeathersJS к корпоративной среде.

Если вам понравилась эта статья, не стесняйтесь взглянуть на наши решения с открытым исходным кодом и насладиться нашими другими статьями о Feathers, команде Kalisio!