Общие сведения

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

Управление процедурами входа осуществляется в разделе Процедуры входа консоли управления Blitz Identity Provider.

Экран настроек процедур входа)

Создание процедуры входа включает в себя следующие шаги:

    1. Указание базовых параметров процедуры:
  • идентификатор процесса (процедуры);

  • описание процедуры;

  • приложения – перечень приложений, для которых будет применяться данная процедура.

Для каждого приложения может быть создана только одна процедура. Если для данного приложения не создано процедуры, к нему будет применяться стандартная процедура входа (процедура входа по умолчанию). Если процедура создана без указания приложений, то она заменит стандартную процедуру входа. При создании новой процедуры в окне будет отображена стандартная процедура.


Экран создания новой процедуры входа)

    2. Написание исходного кода процедуры. Для успешной работы процедуры входа необходимо написать на языке Java класс, реализующий необходимый интерфейс Strategy. Вся контекстная информация о пользователе, о текущем состоянии процедуры аутентификации и т.д. доступна в объекте Context. Процедура состоит из двух блоков, которые определяют:
  • действия, предпринимаемые на начальном этапе процесса аутентификации. В этом блоке, например, можно определить, при каких условиях осуществлять переход в приложение в режиме SSO (если пользователь ранее был аутентифицирован);

  • действия, предпринимаемые после первичной аутентификации пользователя. В этом блоке, например, можно определить, какие методы двухфакторной аутентификации при каких условиях использовать.

    Чтобы было удобнее вести разработку процедуры, Blitz Identity Provider позволяет загрузить из консоли управления JAR-файл для использования разработчиками в IDE среде разработки. Для этого нужно нажать кнопку «Загрузить Blitz Development Kit».

  1. После написания кода необходимо нажать на кнопку «Компилировать». При наличии ошибок некорректные фрагменты кода будут выделены цветом и подписаны ошибки.
  2. Если компиляция прошла успешно, можно активировать процедуру (кнопка «Активировать» в шапке соответствующей процедуры).
  3. Если необходимо отредактировать процедуру, ее необходимо сначала деактивировать.

Экран редактирования исходного кода процедуры входа (фрагмент)

Примеры процедур входа

В поставку входят несколько готовых процедур, которые могут быть при необходимости изменены:

  • принудительная двухфакторная аутентификация в приложение (Require2ndFactor);

  • ограничение перечня доступных методов первого фактора при входе в приложение (FFmethods);

  • предоставление доступа к приложению только при определенном значении атрибута (AccessByAttribute).

Далее приводятся листинги этих процедур. Для удобства отладки можно выводить информацию о состоянии аутентификации в лог, воспользовавшись функцией logger.debug(). Например, следующая команда выведет в лог заданный уровень аутентификации для пользователя:

logger.debug("requiredFactor="+ctx.userProps("requiredFactor"));

Принудительная двухфакторная аутентификация в приложение

Эта процедура требует двухфакторной аутентификации для доступа к приложению. Если пользователь переходит в приложение в рамках единой сессии, то при наличии одного пройденного фактора у него будет дополнительно проверен второй фактор, т.е. SSO в этом случае не сработает.

    @Override public StrategyState begin(final Context ctx) {
        if(ctx.claims("subjectId") != null){

// if the user is already authenticated, then we check the number of factors passed

            if (ctx.sessionTrack().split(",").length < 2)
                return StrategyState.MORE(new String[]{});
            else
                return StrategyState.ENOUGH;
        }

// if he is not authenticated or passed less than 2 factors, then we require passing the next level of authentication

        else
            return StrategyState.MORE(new String[]{});
    }

    @Override public StrategyState next(final Context ctx) {

// if the user has passed one authentication factor, then we require a second one; if more than one - we sign in to the application

        if(ctx.justCompletedFactor() == 1)
            return StrategyState.MORE(new String[]{});
        else
            return StrategyState.ENOUGH;
    }

Ограничение перечня доступных методов первого фактора при входе в приложение

Данная процедура позволяет при входе показывать только те методы первого фактора, которые необходимы для данного приложения (аналогичную процедуру, но с другим перечнем методов, можно назначить другому приложению). В частности, доступны для отображения следующие методы, при условии, что они сконфигурированы в консоли управления:

  • password – вход по логину и паролю;

  • x509 – вход по электронной подписи;

  • externalIdps – вход через внешние поставщики идентификации (социальные сети, ЕСИА);

  • spnego – вход по сеансу операционной системы;

  • sms – вход по коду подтверждения в SMS-сообщении.

@Override public StrategyState begin(final Context ctx) {
        if(ctx.claims("subjectId") != null)
            return StrategyState.ENOUGH;
        else
            return StrategyState.MORE(new String[]{"password","x509"});

        /**
         * This procedure by default enables only username/password methods and digital signatures as the first factor. You can change the available methods by editing the list ("password","x509") by adding or deleting methods. You can use the following method names:
         *     password - username and password
         *     x509 - digital signature
         *     externalIdps - social networks
         *     spnego - domain authentication
         * E.g. if you want the user to log in using username/password and social networks, then change the line with StrategyState.MORE in the following way:
         *
         *     return StrategyState.MORE(new String[]{"password","externalIdps"});
         *
         * After the change you should assign this procedure to the application. If the listed methods are not configured, they are not displayed.
         *
         */

    }

    @Override public StrategyState next(final Context ctx) {
        String reqFactor = ctx.userProps("requiredFactor");
        if(reqFactor == null)
          return StrategyState.ENOUGH;
        else {
          if(Integer.valueOf(reqFactor) == ctx.justCompletedFactor())
            return StrategyState.ENOUGH;
          else
            return StrategyState.MORE(new String[]{});
        }
    }

Разрешить вход только при определенном значении некоторого атрибута у пользователя

Приведенная ниже процедура использует атрибут appList для принятия решения о доступе пользователя к приложению. Для работы этой процедуры необходимо создать атрибут appList в виде массива (Array of strings). В качестве значений элементов этого массива следует использовать идентификаторы приложений. В результате доступ к приложению будет предоставлен, если среди значений appList у данного пользователя будет идентификатор этого приложения. Такая архитектура процедуры позволяет назначить ее сразу нескольким приложениям и регулировать доступ к ним при помощи одного атрибута.

@Override public StrategyState begin(final Context ctx) {
        if(ctx.claims("subjectId") != null){

// if the user is already authenticated, then check his attribute access

            int appListIdx = 0;
            boolean hasAccess = false;
            while (appListIdx > -1) {
                String app = ctx.claims("appList.[" + appListIdx + "]");
                logger.debug("app [" + appListIdx + "] = " + app);
                if (app == null){ appListIdx = -1; }
                else if (app.equals(ctx.appId())) { appListIdx = -1; hasAccess = true; }
                else { appListIdx ++; logger.debug("AppList index = " + appListIdx); }
            }

            if(hasAccess)
                return StrategyState.ENOUGH;
            else
                return StrategyState.DENY;
        }

// if user has not been authenticated, then we ask him to pass the first factor of authentication

        else
            return StrategyState.MORE(new String[]{});
    }


    @Override public StrategyState next(final Context ctx) {

// after primary authentication, we check his attribute appList, if it is correct, then we analyze the requiredFactor parameter of the user (the required level of authentication) and depending on this require the second factor

        int appListIdx = 0;
        boolean hasAccess = false;
        while (appListIdx > -1) {
            String app = ctx.claims("appList.[" + appListIdx + "]");
            logger.debug("app [" + appListIdx + "] = " + app);
            if (app == null){ appListIdx = -1; }
            else if (app.equals(ctx.appId())) { appListIdx = -1; hasAccess = true; }
            else { appListIdx ++; logger.debug("AppList index = " + appListIdx); }
        }

        if(!hasAccess)
            return StrategyState.DENY;
        String reqFactor = ctx.userProps("requiredFactor");
        if(reqFactor == null)
            return StrategyState.ENOUGH;
        else {
            if(Integer.valueOf(reqFactor) == ctx.justCompletedFactor())
                return StrategyState.ENOUGH;
            else
                return StrategyState.MORE(new String[]{});
        }
    }

Упрощенный вариант процедуры (не входит в поставку Blitz Identity Provider) – допуск пользователя в приложение при условии, что адрес его электронной почты равен ivanov@company.ru.

     @Override public StrategyState begin(final Context ctx) {
      if(ctx.claims("subjectId") != null){

// если пользователь уже аутентифицирован, то проверяем его email

            if("ivanov@company.ru".equals(ctx.claims("mail"))) 
            return StrategyState.ENOUGH;
            else    
            return StrategyState.DENY;
      }

// если не аутентифицирован, то просим его пройти первый фактор аутентификации

        else
            return StrategyState.MORE(new String[]{});
    }


     @Override public StrategyState next(final Context ctx) {

// после первичной аутентификации проверяем его email, если он верный, то просим анализируем параметр requiredFactor пользователя (требуемый уровень аутентификации) и в зависимости от этого просим пройти второй фактор

      if(!"ivanov@reaxoft.ru".equals(ctx.claims("mail")))   
        return StrategyState.DENY;  
      String reqFactor = ctx.userProps("requiredFactor");
            if(reqFactor == null)
                return StrategyState.ENOUGH;
            else {
                if(Integer.valueOf(reqFactor) == ctx.justCompletedFactor())
                    return StrategyState.ENOUGH;
                else
                    return StrategyState.MORE(new String[]{});
            }
        }