Содержание


Использование модуля Liberty JAAS для единого входа в Bluemix

Мощная комбинация упрощает процесс входа и проверки подлинности

Comments

Платформа Java Authentication and Authorization Services (JAAS) предоставляет API для проверки подлинности и авторизации пользователей. JAAS отделяет код приложения от механизма проверки подлинности и авторизации пользователей, так что можно легко настраивать различные модули входа, не изменяя код самого приложения.

Проверка подлинности в традиционном веб-приложении Liberty

В традиционном веб-приложении Liberty проверка подлинности предполагает получение учетных данных пользователя, проверку объекта Subject в кэше, вызов службы JAAS для выполнения проверки подлинности по указанному реестру и создание объекта Subject, если он отсутствует в кэше. Этот процесс также создает HTTP-объект Session для идентификации пользователя в рамках нескольких запросов.

Проверка подлинности в веб-приложении Bluemix Liberty

Веб-приложение, работающее на облачной платформе IBM Bluemix со средой исполнения Java Liberty, использует для проверки подлинности и авторизации службу единого входа (Single Sign On - SSO) и не имеет доступа к учетным данным пользователя, так как проверкой подлинности управляет протокол OAuth2. Сервер Liberty не участвует в процессе проверки подлинности в веб-приложении Bluemix Liberty и, следовательно, не создает никаких объектов Subject и HTTP Session для идентификации пользователя. В этом случае приложение должно взять идентификацию пользователя на себя, а код должен учитывать нижележащий механизм входа, потому что HTTP-объекты API Servlet (Session и Principal) не создаются. Bluemix выполняет SSO с помощью службы Bluemix User Account and Authentication Service (UAA), которой требуется OAuth clientID и секретный ключ клиента.

В этом руководстве показано, как добавить в приложение процесс аутентификации, ориентированный на Liberty. Мы покажем, как пример приложения использует службу Bluemix SSO для управления входом пользователя. После успешной проверки подлинности сервер Liberty создает все необходимые объекты (Subject, Principal, Session). Код приложения отделен от механизм входа и несет нагрузку по идентификации пользователя в Liberty.

Как это работает

Специальный модуль входа JAAS выполняет проверку подлинности с помощью службы Bluemix SSO и создает объект Subject со специальными реквизитами доступа (имя пользователя и маркер доступа). Сервер создает объект Session. Специальные реквизиты доступа и учетные записи извлекаются с помощью последующего кода с использованием API Subject. Этот модуль входа заменяет модули по умолчанию Liberty из конфигурации system.WEB_INBOUND. Решение предполагает:

  • что в приложение Liberty добавлен экземпляр службы Bluemix SSO;
  • имеются данные конфигурации клиента SSO (такие как clientID и clientSecret).

Модуль входа JAAS настроен с использованием данных конфигурации клиента SSO. Приложение Liberty взаимодействует с этим модулем входа и службой SSO посредством двух REST API (/dashboard и /sso_dashboard).

Следующие пункты соответствуют номерам на рисунке.

  1. Пользователь вызывает API /dashboard, чтобы инициировать процесс login.
  2. API инициирует последовательность действий OAuth с использованием службы SSO, обратившись по URL-адресу конечной точки /authorize с указанием идентификатора клиента, состояния (для предотвращения кросс-сайтового подлога запроса) и REST API ответного вызова.
  3. После успешного выполнения последовательности OAuth...
  4. Служба SSO вызывает API обратного вызова (/sso_dashboard) с указанием временного кода аутентификации и значения state.
  5. REST API обратного вызова вызывает специальный модуль входа JAAS и передает ему код аутентификации.
  6. Модуль входа запрашивает маркер доступа.
  7. Модуль входа получает маркер доступа от службы SSO.
  8. Модуль входа также получает имя пользователя.
  9. Модуль входа создает объект Subject с использованием объекта Principal и учетных данных.
  10. API /sso_dashboard (или любой последующий код) может обращаться к информации из API Subject или API Servlet (HttpServlet.getUserPrincipal()). Таким образом, сервер Liberty в курсе этого процесса входа в систему и определяет аутентифицированного пользователя по кэшу Subject.

Что требуется для создания приложения

Запустить приложениеПолучить код

Описание примера приложения

Пример приложения Liberty LoginTestApp (нажмите кнопку Получить код выше) вызывает специальный модуль входа (CustomLoginModule), который выполняет процесс аутентификации JAAS с помощью службы Bluemix SSO. После успешного входа код приложения может запустить любой API, связанный с аутентификацией, например, HttpServletRequest.getUserPrincipal(), независимо от нижележащего механизма проверки подлинности.

При запуске примера приложения отображается HTML-страница со ссылкой на страницу входа JAAS с применением Bluemix SSO. Нажмите на ссылку, чтобы вызвать REST API приложения /dashboard и инициировать процесс аутентификации. Вы увидите страницу входа Bluemix SSO, куда нужно ввести учетные данные Bluemix. После успешной проверки подлинности отобразятся ваш ID Bluemix и ID сеанса Liberty.

Шаг 1. Создание простого приложения JAX-RS Liberty в Bluemix

Напишите небольшое приложение JAX-RS Liberty с двумя REST API (/cloudLogin/dashboard и /cloudLogin/sso_redirect), как показано в приведенном ниже примере кода. API /dashboard, который служит отправной точкой, инициирует процесс проверки подлинности (строки 44-45). Этот API вызывает API авторизации службы SSO с идентификатором клиента OAuth, произвольной строкой (state) и REST API обратного вызова (/sso_redirect).

После успешного выполнения OAuth служба единого входа Bluemix вызывает API /sso_redirect с временным кодом авторизации и произвольной строкой (state). Затем этот API вызывает специальный модуль входа Liberty и передает код авторизации путем вызова метода HttpServletRequest.login(code, client_secret) (строка 63). API проверяет результат входа, вызвав метод getUserPrincipal(). В случае успешного входа сведения о пользователе (имя) и параметры входа (access-token, Session) доступны через Subject. Строка 85 показывает, что сервер Liberty создает объект Session для идентификации пользователя между запросами.

43. @GET
44. @Path("/dashboard")
45. public Response dashboard() throws URISyntaxException {
46. 	System.out.println("Dashboard GET request headers: " + headersAsString(request));
47. 	String stateId = "anyUniqueString";
48. 	URI uri = new URI(AUTH_END_POINT + "?state=" + stateId 
49. 			+ "&scope=profile&response_type=code&client_id=" 
50. 			+ CLIENT_ID + "&redirect_uri=" 
51. 			+ buildRESTApiUrlString(SSO_END_POINT_PATH));
52. 	System.out.println("Dashboard GET redirect URI: " + uri);
53. 	return Response.seeOther(uri).build();
54. }
55. @GET
56. @Produces(MediaType.TEXT_HTML)
57. @Path(SSO_END_POINT)
58. public Response ssoDashboard(@QueryParam("code") String code, @QueryParam("state") String state) 
59. 		throws URISyntaxException, UnsupportedEncodingException, WSSecurityException {
60. 	System.out.println("ssoDashboard GET request headers: " + headersAsString(request));		
61. 	try {
62. 		// передача в CustomeLoginModule кода авторизации в качестве имени пользователя 
63. 		request.login(code, code);
64. 	} catch (ServletException e) {
65. 		e.printStackTrace();
66. 	}
67. 		if (request.getUserPrincipal() == null) {
68. 		// вход пользователя не выполнен.
69. 		return Response.status(Status.UNAUTHORIZED).
70. 				type(MediaType.TEXT_HTML).
71. 				entity("You are not authorized.").build();
72. 	}
73. 
74. 	Subject subject = WSSubject.getCallerSubject();
75. 	Set<Object> credentials = subject.getPublicCredentials();
76. 	String userName = request.getUserPrincipal().getName();
77. 	String accessToken = null;
78. 	for (Object obj : credentials) {
79. 		if (obj instanceof HashMap) {
80. 			HashMap<String, String> cred = (HashMap) obj;
81. 			accessToken = cred.get("access-token");
82. 			// создание сеанса приложения с этой информацией.
83. 		}
84. 	}
85. 	String libertySessionId = request.getSession().getId();
86. 	String msg = "<p>Welcome " + userName 
87. 			+ ". You are successfully authenticated using Bluemix SSO service.</p> " 
88. 			+ "<p> Your Liberty session ID :" + libertySessionId +"</p>";
89. 	return Response.status(Status.OK).type(MediaType.TEXT_HTML).entity(msg).build();

Шаг 2. Реализация модуля входа Bluemix SSO

Модулю входа нужно передать в качестве параметров некоторые URL-адреса (конечная точка профиля пользователя, конечная точка маркера, REST API обратного вызова входа), значение clientID OAuth и секретный ключ клиента OAuth. Эти значения хранятся в переменных класса.

44. public void initialize(Subject subject, CallbackHandler callbackHandler, 
       Map sharedState, Map options) {
45. 		this.subject = subject;
46. 		this.callbackHandler = callbackHandler;
47. 		this.sharedState = sharedState;
48. 
49. 		if (options.containsKey("PROFILE_END_POINT")) {
50. 			profileEndPoint = (String) options.get("PROFILE_END_POINT");
51. 		}
52. 
53. 		if (options.containsKey("CLIENT_SECRET")) {
54. 			clientSecret = (String) options.get("CLIENT_SECRET");
55. 		}
56. 
57. 		if (options.containsKey("SSO_END_POINT_PATH")) {
58. 			ssoEndPointPath = (String) options.get("SSO_END_POINT_PATH");
59. 		}
60. 
61. 		if (options.containsKey("CLIENT_ID")) {
62. 			clientId = (String) options.get("CLIENT_ID");
63. 		}
64. 		
65. 		if (options.containsKey("TOKEN_END_POINT")) {
66. 			tokenEndPoint = (String) options.get("TOKEN_END_POINT");
67. 		}
68. 	}

Метод login взаимодействует со службой единого входа Bluemix и выполняет проверку подлинности. Сначала строится временный код авторизации с помощью объекта NameCallback, как показано в строках 76-77.

71. public boolean login() throws LoginException {
72. 		
73. 	System.out.println("Login module invoked");
74. 
75. 	// код авторизации передается как значение параметра имени пользователя.  
76. 	NameCallback nameCallback = new NameCallback("User:");	
77. 	Callback callbacks[] = new Callback[1];
78. 	callbacks[0] = nameCallback;	
79. 
80. 	try {
81. 		callbackHandler.handle(callbacks);
82. 	} catch (IOException e1) {
83. 		e1.printStackTrace();
84. 	} catch (UnsupportedCallbackException e1) {
85. 		e1.printStackTrace();
86. 	}
87. 
88. 	// получение кода авторизации
89. 	String code = nameCallback.getName();
92.    CloudAccessToken accessToken = 
93. 		getAccessToken(clientId,
94. 				clientSecret,
95. 				tokenEndPoint,
96. 				code,
97. 				ssoEndPointPath);
98. 		
99. 	// получение имени пользователя
100. 	HashMap<String, String> headerList = new HashMap<String, String>();
101. 	headerList.put("Authorization", accessToken.getFullAccessToken());
102. 	ASMRestClient restClient = new ASMRestClient();
103. 	ASMRestResponse response = restClient.doGet(profileEndPoint, headerList, null);
104. 	if (response.getStatusCode() != Status.OK.getStatusCode()) {
105. 		System.out.println("User profile end point returned status code: " 
106. 				+ response.getStatusCode());
107. 		return false;
108. 	}
109. 			
110. 	CloudUserInfo userInfo = response.getEntity(CloudUserInfo.class);
111. 	String name = userInfo.getUserDisplayName()[0];
112. 		
113. 	// добавление маркера доступа и информации пользователя в качестве реквизитов доступа субъекта JAAS.
114. 	HashMap<String, String> map = new HashMap<String, String>();		
115. 	map.put("access-token", accessToken.getAccessToken());
116. 	map.put("access-token-type", accessToken.getTokenType());		
117. 			
118. 	subject.getPublicCredentials().add(map);
119. 		
120. 	java.util.Hashtable<String, Object> customProperties = 
121. 			(java.util.Hashtable<String, Object>) sharedState.
122. 			get(AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY);
123. 	customProperties = new java.util.Hashtable<String, Object>();
124. 		
125. 	customProperties.put(AttributeNameConstants.WSCREDENTIAL_UNIQUEID, name);
126. 	customProperties.put(AttributeNameConstants.WSCREDENTIAL_SECURITYNAME, name);
127. 	sharedState.put(AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY,
128. 			customProperties);

Создаются объекты JAAS Subject и Principal, а также реквизиты доступа, как указано выше:

  • строки 92-97: accessToken извлекается посредством HTTP-запроса к конечной точке маркера службы SSO с указанием clientID, clientSecret, кода авторизации и URL-адреса REST API обратного вызова входа;
  • строки 102-111: это значение accessToken используется в качестве заголовка авторизации для запроса к конечной точке профиля с целью получения имени пользователя;
  • строки 114-128: составляются объект JAAS Principal и реквизиты доступа с помощью сведений об авторизованном пользователе, полученных от службы единого входа Bluemix;
  • строки 114-118: к Subject, где содержится маркер доступа и его тип, добавляется открытый ключ;
  • строки 125-128: для создания JAAS Principal хэш-таблица с информацией о пользователе добавляется к переменной общего состояния (передается в метод initialize);
  • строка 127: среда Liberty выполняет поиск значения объекта хэш-таблицы, используя определенный ключ в составе переменной общего состояния, и создает объект Principal.

Шаг 3. Добавление службы единого входа Bluemix и создание конфигурации клиента SSO

Теперь пора перенести пример приложения в Bluemix и привязать к нему службу единого входа. Следуйте инструкциям, содержащимся в документе Начало работы со службой Single Sign On, чтобы создать конфигурацию SSO клиента и передать URL-адрес /sso_redirect в качестве обратного вызова URI.

Запишите clientID и значение секретного ключа клиента – они понадобятся на следующем шаге.

Шаг 4. Настройка специального модуля входа JAAS

Специальный модуль входа настраивается в примере приложения Liberty. Ниже приведен фрагмент файла server.xml, который загружает модуль входа. Библиотека этого модуля входа находится в папке lib сервера и вызывается элементом customLoginLib (строка 25). Модули входа по умолчанию конфигурации sytem.WEB_INBOUND заменяются специальным модулем входа и хэш-таблицей, как показано в строке 30. Строки 33-40 демонстрируют, как загрузить реализацию специального модуля входа и параметры, которых он ожидает (cliendID, client-secret, URL-адрес профиля пользователя, URL-адрес REST API обратного вызова и URL-адрес конечной точки маркера).

24. 	
25. 	<library id="customLoginLib">
26. 		<fileset dir="${server.config.dir}/lib" includes="*.jar"/>
27. 	</library>
28. 	
29. 	
30.   	<jaasLoginContextEntry id="system.WEB_INBOUND" loginModuleRef="custom, hashtable" 
31. 	name="system.WEB_INBOUND"/>
32. 	
33. 	<jaasLoginModule className="login.module.CloudLoginModule" controlFlag="REQUIRED" 
34. 		id="custom" libraryRef="customLoginLib">
35.   		<options CLIENT_ID="${client.id}"
36.   			 CLIENT_SECRET="${client.secret}"
37.   			 PROFILE_END_POINT="${profile.end.point}" 
38.   			 SSO_END_POINT_PATH="${sso.end.point}"
39.   			 TOKEN_END_POINT="${token.end.point}"/>
40.   	</jaasLoginModule>

Шаг 5. Сборка и перенос приложения в Bluemix.

Чтобы собрать и запустить пример приложения:

  1. Создайте приложение Liberty в Bluemix:
    1. Войдите в Bluemix и создайте приложение Liberty:
    2. Добавьте в свое пространство Bluemix службу единого входа, используя команду cf:
      cf create-service SingleSignOn standard sso_service
    3. Привяжите эту службу к своему приложению, используя команду cf:
      >cf bind-service app_name sso_service
    4. Создайте конфигурации клиента SSO:
      1. Введите значение URI Redirect:
        https:<hostname>.mybluemix.net:443/api/cloudlogin/sso_redirect
      2. Запишите значения clientId и client-secret.
  2. Скопируйте этот проект в новый проект JazzHub.
  3. Загрузите пример приложения:
    1. Настройте IDE Eclipse на загрузку этого примера приложения из JazzHub (см. документ Создание локальных клиентов Eclipse для работы с системой управления исходным кодом Jazz).
    2. Импортируйте пример проекта в IDE Eclipse.
    3. Скачайте профиль среды выполнения Liberty (см. Загрузка профиля выполнения Liberty).
    4. Скачайте программу командной строки cf, чтобы перенести приложение в Bluemix (см. Интерфейс командной строки).
    5. Скачайте и настройте плагин Eclipse для профиля Liberty (см. Загрузка профиля Liberty в Eclipse).
    6. Создайте сервер Liberty для развертывания своего приложения из образа сервера Eclipse (например, Liberty\usr\servers\loginapp).
  4. Выполните сборку приложения:
    1. Укажите местоположение среды выполнения Liberty и сервера Liberty в следующих сценариях сборки ant:
      • CustomLoginModule\build.xml
      • LoginTestApp\build.xml
          <property name="Liberty.location" value="C:\Liberty"/>
          <property name="server.name" value="loginapp"/>
    2. Введите значения clientId OAuth и секретного ключа клиента, записанные на шаге настройки клиента SSO, в файл LoginTestApp\Config.xml.
      <server>
        <variable name='client.id' value='YOUR_CLIENT_ID'/>
        <variable name='client.secret' value='YOUR_CLIENT_SECRET'/>
    3. Чтобы собрать проект, выполните сборку LoginTestApp/build.xml в ant. Вы заметите, что ваш каталог сервера (например, Liberty\usr\servers\loginapp) обновился с добавлением зависимостей и конфигураций.
  5. Разверните приложение в Bluemix:
    1. Отредактируйте файл manifest.yml, указав имя приложения, имя хоста и путь к серверу Liberty (например, C:\Liberty\usr\servers\loginapp).
    2. Перенесите свое приложение в Bluemix с помощью команды cf push:
      C:\Program Files (x86)\CloudFoundry>cf push -f c:\manifest.yml

По завершении процесса развертывания можно обращаться к приложению (https://<hostname>.mybluemix.net/).

Шаг 6. Запуск и тестирование примера приложения

Чтобы проверить пример приложения:

  1. Перейдите по URL-адресу приложения (https://<hostname>.mybluemix.net/). Откроется страница с веб-ссылкой JAAS login with Bluemix SSO service.
  2. Появится форма входа от поставщика ваших реквизитов доступа (IBM, Facebook и т.п.), которые нужно ввести.
  3. Служба SSO пришлет по email код безопасного доступа.
  4. Введите код доступа и после успешного входа через Bluemix SSO вы увидите примерно такое сообщение:
    You are successfully authenticated using Bluemix SSO, Session ID :g-IZDSgUdVZXfH8E3NAf4fw

Заключение

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


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Security, Облачные вычисления, Технология Java
ArticleID=1018374
ArticleTitle=Использование модуля Liberty JAAS для единого входа в Bluemix
publish-date=10232015