OpenID в Web-приложениях на Java: Часть 2. Создание провайдера OpenID для обеспечения единой аутентификации

В этой серии рассказывается о защите Web-приложений, написанных на Java, от неаутентифицированных пользователей при помощи протокола OpenID. Во второй статье автор серии Стив Перри демонстрирует использование библиотеки openid4java для создания провайдера OpenID, обеспечивающего единую аутентификацию. Наделив одно приложение замкнутой программной системы функциями провайдера OpenID, вы сможете предоставить пользователям возможность единой аутентификации для нескольких приложений. Прочитав эту статью, вы также узнаете о том, как использовать расширение Attribute Exchange (AX) для организации специализированного обмена данными между клиентами и провайдерами OpenID.

Дж. Стивен Перри, главный консультант, Makoto Consulting Group, Inc.

Photo of J Steven PerryДж. Стивен Перри (J. Steven Perry) – независимый консультант по вопросам разработки программного обеспечения, профессионально занимающийся созданием ПО с 1991 г. Стив увлекается программированием, получает удовольствие от написания статей и книг на эту тему, а также от консультирования других разработчиков. Он является автором книг Java Management Extensions и Log4j (обе книги выпущены издательством O'Reilly) и статьи Время Йоды, опубликованной на сайте IBM developerWorks. Свое свободное время он проводит с тремя детьми, катается на велосипеде и преподает йогу. Стив является владельцем и главным консультантом компании Makoto Consulting Group, расположенной в городе Литтл Рок, штат Арканзас.



03.11.2010

OpenID постепенно завоевывает все большее признание в качестве надежного средства идентификации и аутентификации пользователей, позволяющего им обращаться к Web-сайтам и другим online-ресурсам, способным распознавать их идентификаторы. В предыдущей статье серии было приведено введение в спецификацию аутентификации OpenID, а также рассказывалось о том, как ее можно интегрировать в Web-приложения на Java при помощи библиотеки openid4java.

На протяжении большей части предыдущей статьи основное внимание уделялось клиентам OpenID (OpenID Relying Party или RP), которые представляют собой online-ресурсы, например, Web-сайты или файлы MP3, использующие OpenID для регистрации и аутентификации пользователей. Другим компонентом спецификации аутентификации OpenID являются провайдеры (OpenID Provider или OP). Они предоставляют пользователям идентификаторы и позволяют аутентифицироваться для обращения к Web-ресурсам, поддерживающим OpenID.

В настоящее время существует множество провайдеров OpenID (например, myOpenID, который мы использовали при регистрации в демонстрационном приложении в предыдущей статье), поэтому, как правило, нет необходимости изобретать велосипед.

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

В этой статье мы рассмотрим вопросы создания провайдера OpenID для обеспечения безопасного доступа к множеству приложений замкнутой системы. Вначале будут рассмотрены преимущества и структура единой системы аутентификации, а затем – реализация простого провайдера OpenID. Как и в предыдущей статье, мы будем использовать библиотеку openid4java реализации основных функций системы аутентификации. Это гарантирует, что наш провайдер будет соответствовать спецификации OpenID.

Единая аутентификация

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

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

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

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

Клиент OpenID (OpenID Relying Party или RP)

Как вы помните, клиенты OpenID – это Web-сайты или другие online-ресурсы, которые требуют защищенного доступа к своему содержимому. Клиенты выполняют аутентификацию пользователей, используя провайдеры OpenID (OP). Они также могут использовать расширения Simple Registration (SReg) или Attribute Exchange (AX) для запрашивания регистрации или получения информации о пользователях (см. раздел Ресурсы). Клиенты выполняют запросы при помощи SReg или AX в момент направления пользователя к OP для аутентификации, например при помощи библиотеки openid4java.

Немного о SReg

В демонстрационном приложении, рассмотренном в предыдущей статье под названием OpenID в Web-приложениях на Java. Часть 1, использовалось расширение Simple Registration для запрашивания информации о пользователе у провайдера. Обратитесь к ней, если вас интересует более подробная информация об этом расширении. В приложении, обсуждаемом ниже, используется другое расширение – Attribute Exchange (AX), поддерживающее более сложные сценарии обмена данными с провайдером.

Провайдер OpenID (OP)

Провайдер OpenID предоставляет сервис для аутентификации всем приложениям кластера. После того как пользователь успешно аутентифицирован при помощи библиотеки openid4java, OP обрабатывает все запросы к расширениям SReg и AX, полученные от RP. Как будет показано ниже, OP занимает центральное место в системе единой аутентификации программных кластеров.

Создание провайдера OpenID

В предыдущей статье было продемонстрировано использование библиотеки openid4java для включения возможностей RP в Web-приложение, написанное на Java. В этой статье применяется аналогичный подход к разработке провайдера. Библиотека openid4java превращает процесс создания OP, удовлетворяющего спецификации OpenID, в легкое упражнение, позволяя пользоваться всеми преимуществами готовой инфраструктуры OpenID.

Демонстрационное приложение

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

  1. Пользователь предпринимает попытку обращения к защищенному ресурсу.
  2. RP обращается к OP с запросом на аутентификацию пользователя.
  3. OP аутентифицирует пользователя, если тот ранее не выполнил вход в систему.
  4. RP определяет, имеет ли аутентифицированный пользователь право на обращение к ресурсу.

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

Примеры кода демонстрационного приложения

В примерах кода, приведенных ниже, показаны вызовы методов API библиотеки openid4java, выполняемые провайдером и клиентами OpenID. Обратите внимание, насколько небольшой объем кода требуется данному приложению, другими словами, насколько сильно openid4java облегчает жизнь разработчикам. При этом клиентский код аналогичен тому, который рассматривался в первой статье, поэтому обратитесь к ней, если вас интересуют детали реализации RP. Мы же остановимся только на нескольких моментах, связанных с AX (это расширение не использовалось в предыдущей статье).

Аналогично предыдущему приложению, интерфейс также создан с использованием библиотеки Wicket. Чтобы минимизировать зависимость приложения от Wicket, код провайдера, обращающийся к openid4java, был вынесен в отдельный класс OpenIdProviderService в пакете com.makotogroup.sample.model.

Класс OpenIdProviderService содержит ряд методов, использующих разные возможности библиотеки openid4java:

  • getServerManager() настраивает и возвращает ссылку на класс ServerManager библиотеки openid4java;
  • getOpEndpointUrl() возвращает URL конечной точки, в которую должны поступать запросы от клиентов OpenID;
  • processAssociationRequest() использует openid4java для обработки запроса на установку соединения с клиентом OpenID;
  • sendDiscoveryResponse() отправляет клиенту отклик на запрос обнаружения;
  • createAuthResponse() создает сообщение типа AuthResponse, отправляемое клиенту в ответ на запрос на аутентификацию;
  • buildAuthResponse() - центральный метод, обрабатывающий запросы к расширениям SReg и AX.

Для запуска приложения выполните команду Ant [REF], соберите WAR-архив, скопируйте его в директорию webapps в Tomcat, а затем запустите сам Tomcat.

Аутентификация OpenID: шаг за шагом

После того как пользователь обратился к защищенному ресурсу внутри клиента OpenID, тому необходимо удостовериться, что пользователь является именно тем, за кого себя выдает (т.е. аутентифицировать), а затем решить, следует ли предоставлять ему доступ (т.е. авторизовать). В этой статье основное внимание уделяется аутентификации, поэтому если пользователь был успешно аутентифицирован провайдером OpenID, ему будет предоставлен доступ к ресурсу. В реальной системе RP, как правило, выполнит проверку прав доступа.

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

  1. Запрос на доступ к защищенному ресурсу: пользователь пытается обратиться к ресурсу на сайте RP.
  2. Обнаружение провайдера: RP посылает провайдеру запрос на обнаружение с целью установки соединения для дальнейшего взаимодействия.
  3. Отклик на запрос обнаружения: OP откликается на запрос, отправляя клиенту ответ в формате XRDS (eXtensible Resource Descriptor Sequence) при помощи расширений SReg, AX или политики аутентификации OP (OpenID Provider Authentication Policy). Последнее расширение не рассматривается в этой статье - для получения более подробной информации обратитесь к разделу Ресурсы. XRDS-отклик подтверждает, что OP является корректным провайдером для аутентификации данного пользователя.
  4. Запрос на аутентификацию пользователя: RP проверяет, может ли пользователь быть аутентифицирован данным провайдером. В случае успешной аутентификации RP запрашивает у провайдера информацию о пользователе при помощи расширений SReg, AX (или обоих).
  5. Аутентификация пользователя: если пользователь ранее не выполнил вход в систему или его сессия устарела, то провайдер запросит параметры его учетной записи. Если аутентификация прошла успешно, провайдер уведомляет RP и передает ему всю информацию, ранее запрошенную через SReg/AX.
  6. Предоставление доступа: RP открывает пользователю доступ к защищенному ресурсу. В реальных приложениях RP также выполняет авторизацию перед тем, как предоставить доступ.

Далее мы подробно рассмотрим каждый из шагов.

Зачем нужно расширение AX?

Возможно, вы заметили, что демонстрационное приложение использует два расширения (SReg и AX) для обмена данными между провайдером и клиентом OpenID (см. раздел Ресурсы). Оба этих расширения нужны для эффективного взаимодействия OP и RP. При этом SReg поддерживает только обмен значениями ограниченного числа атрибутов, в то время как AX может использоваться для обмена фактически любой информацией, которая может быть описана в виде атрибутов как на стороне OP, так и RP. В программных кластерах, подобных нашему, может случиться так, что каждое приложение-клиент будет использовать собственное специализированное расширение OpenID (vendor extension). Это еще один способ реализации взаимодействия между провайдером и клиентами. Подробнее AX обсуждается в последующих разделах статьи.

Запрос на доступ к защищенному ресурсу

Демонстрационное приложение включает единственный защищенный ресурс. Если после запуска приложения обратиться к RP по адресу http://localhost:8080/openid-provider-sample-app/, то вы увидите страницу, показанную на рисунке 1.

Рисунок 1. Главная страница демонстрационного приложения
Screenshot of the sample application's main page showing a link to a protected resource.

При нажатии на ссылку будет выполнен код, приведенный в листинге 1.

Листинг 1. Класс главной страницы приложения, содержащего защищенный ресурс
package com.makotogroup.sample.wicket;
. . .
public class OleMainPage extends WebPage {
  public OleMainPage() {
    add(new OleMainForm("form"));
  }
  public class OleMainForm extends Form {
    public OleMainForm(String id) {
      super(id);
      add(new PageLink("openIdRegistrationPage", new IPageLink() {
        public Page getPage() {
          return new OpenIdRegistrationPage();
        }
        public Class<? extends WebPage> getPageIdentity() {
          return OpenIdRegistrationPage.class;
        }
      }));
    }
  }
}

Обратите особое внимание на строки, выделенные жирным шрифтом в листинге 1. После нажатия на ссылку Wicket перенаправляет пользователя к ресурсу OpenIdRegistrationPage. В этот момент вызывается конструктор класса OpenIdRegistrationPage, который выполняет следующие функции:

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

При первоначальном вызове класса он не получает на вход никаких параметров (PageParameters) от Wicket. Это означает, что пользователь должен быть направлен к провайдеру для аутентификации.

Обнаружение провайдера клиентом

Перед тем как начать взаимодействие, RP должен выполнить операцию обнаружения провайдера. С точки зрения разработчика, в этом нет ничего сложного (благодаря openid4java), но этот шаг весьма важен, поэтому имеет смысл рассмотреть его поэтапно.

Ниже показан фрагмент кода RP для отправки запроса на обнаружение. Он находится в конструкторе класса OpenIdRegistrationPage.

  DiscoveryInformation discoveryInformation =
    RegistrationService.performDiscoveryOnUserSuppliedIdentifier(
          OpenIdProviderService.getOpEndpointUrl());

В этом коде можно выделить два момента.

  1. Обнаружение провайдера по URL конечной точки.
  2. Установка соединения (ассоциирование) RP и OP. Детальное рассмотрение обмена ключами по алгоритму Диффи-Хеллмана и других аспектов ассоциирования приведено в первой статье.

Далее настало время перейти к рассмотрению того, как OP обрабатывает запросы на обнаружение со стороны клиентов.

Отклик на запрос обнаружения

Как вы помните, библиотека используется как клиентской частью приложения, так и провайдером. Вследствие этого в процессе обнаружения RP посылает пустой запрос по URL конечной точки провайдера. Конечная точка (endpoint) – это URL, по которому OP принимает все клиентские запросы и, разумеется, он должен включать обработчик запроса на обнаружение. Если вы заглянете внутрь метода OpenIdProviderService.getOpEndpointUrl(), то увидите, что в данном приложении адресом конечной точки является http://localhost:8080/openid-provider-sample-app/sample/OpenIdLoginPage.

В момент отправки пустого запроса к провайдеру Wicket создает экземпляр класса OpenIdLoginPage, вызывая его конструктор, показанный в листинге 2.

Листинг 2. Точка входа провайдера
 public OpenIdLoginPage(PageParameters parameters) throws IOException {
    super(parameters);
    if (parameters.isEmpty()) {
      // Пустой запрос расценивается как запрос на обнаружение
      OpenIdProviderService.sendDiscoveryResponse (getResponse());
  . . .

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

Код метода sendDiscoveryRequest() приведен в листинге 3.

Листинг 3. Обработка запроса на обнаружение
  public static void sendDiscoveryResponse (Response response) throws IOException {
    //
    response.setContentType("application/xrds+xml");
    OutputStream outputStream = response.getOutputStream();
    String xrdsResponse = OpenIdProviderService.createXrdsResponse();
    //
    outputStream.write(xrdsResponse.getBytes());
    outputStream.close();
  }

Документ XRDS необходим для корректного функционирования openid4java на стороне RP. Для краткости детали содержимого этого документа опущены; если вас интересуют подробности, загрузите исходный код демонстрационного приложения.

Получив XRDS-документ от OP, клиент OpenID делает вывод, что корректный провайдер для аутентификации данного пользователя найден. Далее RP создает и отправляет провайдеру запрос на аутентификацию.

Запрос на аутентификацию пользователя

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

Листинг 4. Код клиента, перенаправляющий пользователя к OP для аутентификации
  DiscoveryInformation discoveryInformation =
    RegistrationService.performDiscoveryOnUserSuppliedIdentifier(
          OpenIdProviderService.getOpEndpointUrl());
  MakotoOpenIdAwareSession session =
    (MakotoOpenIdAwareSession)getSession();
  session.setDiscoveryInformation(discoveryInformation, true);
  AuthRequest authRequest =
    RegistrationService.createOpenIdAuthRequest(
          discoveryInformation, 
          RegistrationService.getReturnToUrl());
  getRequestCycle().setRedirect(false);
  getResponse().redirect(authRequest.getDestinationUrl(true));

Вначале RP обращается к OP по адресу конечной точки. Этот вызов может выглядеть несколько странно, однако не забывайте, что мы рассматриваем случай программного кластера, в котором в роли провайдера выступает одно из приложений. Таким образом, с точки зрения RP, аутентификация пользователя сводится просто к обнаружению провайдера, после чего openid4java самостоятельно создаст все объекты, необходимые для взаимодействия с ним. Непосредственно процесс аутентификации будет выполняться внутри провайдера.

Далее RP получает ссылку на Wicket-объект типа Session и сохраняет в нем экземпляр DiscoveryInformation, полученный от openid4java, для дальнейшего использования. Я создал специальный класс MakotoOpenIdAwareSession, унаследованный от Session, облегчающий сохранение объектов в сессии.

На следующем шаге RP создает запрос на аутентификацию, используя ранее полученный объект типа DiscoveryInformation. Этот объект необходим для указания Wicket, по какому адресу следует перенаправить пользователя для аутентификации.

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

Итак, на этом этапе RP ожидает ответа от провайдера на свой запрос на аутентификацию. Перед тем как перейти к следующему шагу, следует подробнее рассмотреть роль, которую играет расширение Attribute Exchange в процессе аутентификации пользователя.

Расширение OpenID Attribute Exchange

В предыдущей статье было кратко рассмотрено расширение Simple Registration (SReg), позволяющее клиентам и провайдерам OpenID обмениваться данными, тип которых описывается в спецификации SReg. Однако если вы заглянете внутрь метода createOpenIdAuthRequest(), то заметите, что в данном приложении RP использует другое расширение, а именно OpenID Attribute Exchange (AX), для получения информации от провайдера.

Подобно SReg, AX используется для организации согласованного, стандартного процесса обмена информацией между RP и OP. Однако в отличие от SReg, AX позволяет обеим сторонам передавать друг другу информацию любого типа. Единственное, что необходимо – это поддержка AX со стороны как провайдера, так и клиента.

Если не вдаваться в детали, то процесс взаимодействия заключается в том, что RP запрашивает у OP определенную информацию, и OP пересылает ее виде специального сообщения. Сообщения помещаются в URL, по которому перенаправляется браузер пользователя, но openid4java позволяет работать с их содержимым в виде объектов.

Для выполнения AX-запросов RP использует класс FetchRequest. Получив ссылку на сообщение, клиент добавляет к нему атрибуты, значения которых должны быть получены от провайдера (листинг 5).

Листинг 5. Пример создания экземпляра FetchRequest на стороне RP и установки значений атрибутов
AuthRequest ret = obtainSomehow();
// Создание AX-запроса для получения любимого цвета пользователя
FetchRequest fetchRequest = FetchRequest.createFetchRequest();
fetchRequest.addAttribute("favoriteColor",
       "http://makotogroup.com/schema/1.0/favoriteColor", 
        false); 
ret.addExtension(fetchRequest);

При отправке информации обратно клиенту провайдер использует те же самые конструкции, как показано в листинге 6.

Листинг 6. Пример отправки запрошенных атрибутов клиенту
if (authRequest.hasExtension(AxMessage.OPENID_NS_AX)) {
  MessageExtension extensionRequestObject =
     authRequest.getExtension(AxMessage.OPENID_NS_AX);
  FetchResponse fetchResponse = null;
  Map<String, String> axData = new HashMap<String, String>();
  if (extensionRequestObject instanceof FetchRequest) {
   FetchRequest axRequest = (FetchRequest)extensionRequestObject;
    ParameterList parameters = axRequest.getParameters();
    fetchResponse = FetchResponse.createFetchResponse(
        axRequest, axData);
    if (parameters.hasParameter("type.favoriteColor")) {
       axData.put("favoriteColor", registrationModel.getFavoriteColor());
      fetchResponse.addAttribute("favoriteColor",
          "http://makotogroup.com/schema/1.0/favoriteColor",
          registrationModel.getFavoriteColor());
    }
      authResponse.addExtension(fetchResponse);
  } else {
    // Ошибка
  }
}

Каждый из описанных атрибутов обладает именем и URI. В данном случае именем атрибута является FavoriteColor, а URI - http://makotogroup.com/schema/1.0/favoriteColor.

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

Далее мы продолжим рассмотрение этапов аутентификации пользователей.

Аутентификация пользователя провайдером

Итак, мы остановились на том, что запрос на аутентификацию поступил по адресу конечной точки провайдера. В этот момент провайдер должен проанализировать запрос и определить дальнейшие действия. Вначале он определяет режим (mode) запроса, который может принимать два значения: "association" (ассоциирование) и "authentication" (аутентификация).

Листинг 7. Обработка запроса на ассоциирование провайдером
//Код взят из конструктора класса OpenIdLoginPage

public OpenIdLoginPage(PageParameters parameters) throws IOException {
    super(parameters);
    . . .
    if ("associate".equals(mode)) {
        OpenIdProviderService.processAssociationRequest(getResponse(), requestParameters);
      }
    . . .
}

//Код класса OpenIdProviderService

  public static void processAssociationRequest(Response response, ParameterList request) 
       throws IOException {
    Message message = getServerManager().associationResponse(request);
    sendPlainTextResponse(response, message);
  }
  private static void sendPlainTextResponse(Response response, Message message) 
       throws IOException {
    response.setContentType("text/plain");
    OutputStream os = response.getOutputStream();
    os.write(message.keyValueFormEncoding().getBytes());
    os.close();
  }

В листинге 7 показано, как конструктор класса OpenIdLoginPage, являющийся точкой входа провайдера в демонстрационном приложении, анализирует запрос. Если режим говорит о том, что поступил запрос на ассоциирование, класс обращается к openid4java, которая берет на себя детали этого процесса. При этом обращение к библиотеке происходит через класс-обертку OpenIdProviderService. После этого запрос отправляется обратно на сторону клиента.

После того как RP убедился, что ассоциирование выполнено успешно (а точнее, когда openid4java это проверит), он выполняет следующий запрос к OP. Как и ранее, провайдер анализирует режим запроса. Как правило, вторым поступает запрос на аутентификацию (режим "checkid_authentication").

Код конструктора класса OpenIdLoginPage приведен в листинге 8.

Листинг 8. Разбор запроса с режимом checkid_authentication при помощи openid4java
  public OpenIdLoginPage(PageParameters parameters) throws IOException {
    super(parameters);
     . . .
      else if ("checkid_immediate".equals(mode)
    		  ||
    		   "checkid_setup".equals(mode)
    		  ||
    		   "check_authentication".equals(mode)) {
        if (((MakotoOpenIdAwareSession)getSession()).isLoggedIn()) {
          // Создание объекта AuthResponse на основе данных в сессии
         sendSuccessfulResponse();
        }
    add(new OpenIdLoginForm("form"));
    . . 
  }

Вновь обратите внимание на выделенные строки. В первой из них класс OpenIdLoginPage возвращает положительный ответ на запрос. Вначале он при помощи класса Session проверяет, выполнил ли пользователь вход в приложение ранее (в этом случае аутентификация не требуется). Если да, то клиенту возвращается ответ с признаком успешной аутентификации. Именно так работает механизм аутентификации в демонстрационном приложении.

Если же пользователь ранее не входил в систему, то Wicket создает форму аутентификации, на которой следует ввести параметры учетной записи (рисунок 2).

Рисунок 2. Страница провайдера с формой входа для неаутентифицированного пользователя
Screenshot of a login form where the user can enter his or her credentials.

Если пользователь успешно прошел аутентификацию, провайдер отправляет клиенту ответ, включающий дополнительную информацию, а именно - объект DiscoveryInformation, который затем сохраняется в сессии. Все эти действия являются частями механизма единой аутентификации.

В этот момент браузер пользователя перенаправляется обратно на страницу RP (URL задан в параметре "return-to"), получая сообщение об успешной аутентификации.

Предоставление доступа

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

Рисунок 3. Страница регистрации, отображающая информацию о пользователе, полученную от провайдера
Screenshot of user registration information.

Заключение

Прочитав эту статью, вы узнали о применении OpenID при реализации механизма единой аутентификации пользователей для кластера из нескольких приложений. Данная архитектура подразумевает, что между приложениями установлены доверительные отношения, а одно из приложений выполняет функции провайдера OpenID (OP).

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

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

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


Загрузка

ОписаниеИмяРазмер
Исходный код приложенияopenid-provider-sample-app.zip4.5 KБ

Ресурсы

Научиться

Получить продукты и технологии

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Open source
ArticleID=569745
ArticleTitle=OpenID в Web-приложениях на Java: Часть 2. Создание провайдера OpenID для обеспечения единой аутентификации
publish-date=11032010