обзор
Последний выпуск WSO2 Identity Server (версия 5.0.0) оснащен «структурой аутентификации приложений», которая обеспечивает большую гибкость при аутентификации пользователей от различных поставщиков услуг, которые используют гетерогенные протоколы. Он имеет несколько точек расширения, которые можно использовать для удовлетворения нескольких индивидуальных требований, обычно встречающихся в корпоративных системах. В этом посте я расскажу о том, как использовать одну из таких точек расширения.
Функциональность будет расширена
Когда SAML Single Sign On используется в корпоративных системах, проверяющая сторона узнает, аутентифицирован ли пользователь или нет, с помощью ответа SAML. На этом этапе проверяющая сторона не знает о других атрибутах аутентифицированного пользователя, которые могут ему понадобиться для бизнес-целей и целей авторизации. Чтобы предоставить эти сведения об атрибутах для проверяющей стороны, спецификация SAML также позволяет отправлять атрибуты в ответе SAML. WSO2 Identity Server поддерживает это «из коробки» через графический интерфейс, предоставленный администраторам. Вы можете обратиться к [1] за подробной информацией об этой функции и деталях конфигурации.
Гибкость, обеспечиваемая этим конкретным расширением, оказывается полезной, когда у нас есть требование добавить дополнительные атрибуты в ответ SAML, кроме атрибутов, доступных в подчеркнутом хранилище пользователей. Мы можем искать внешние источники данных, чтобы предоставить все атрибуты, запрашиваемые доверяющими сторонами.
В примере, который я здесь опишу, мы рассмотрим сценарий, в котором система должна предоставить некоторые локальные атрибуты пользователя, которые хранятся в хранилище пользователя, с некоторыми дополнительными атрибутами, которые я ожидаю получить из внешнего источника данных.
Следующий ответ SAML — это то, что нам нужно отправить проверяющей стороне от WSO2 IS.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
< saml2p:Response Destination = "https://localhost:9444/acs" ID = "faibaccbcepemkackalbbjkihlegenhhigcdjbjk" InResponseTo = "kbedjkocfjdaaadgmjeipbegnclbelfffbpbophe" IssueInstant = "2014-07-17T13:15:05.032Z" Version = "2.0" xmlns:saml2p = "urn:oasis:names:tc:SAML:2.0:protocol" < saml2:Issuer Format = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2 = "urn:oasis:names:tc:SAML:2.0:assertion" >localhost </ saml2:Issuer > .......... </ ds:Signature > < saml2p:Status > < saml2p:StatusCode Value = "urn:oasis:names:tc:SAML:2.0:status:Success" /> </ saml2p:Status > < saml2:Assertion ID = "phmbbieedpcfdhcignelnepkemobepgaaipbjjdk" IssueInstant = "2014-07-17T13:15:05.032Z" Version = "2.0" < saml2:Issuer Format = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity" >localhost</ saml2:Issuer > ......... </ ds:Signature > < saml2:Subject > < saml2:NameID Format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" >Administrator</ saml2:NameID > < saml2:SubjectConfirmation Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer" > < saml2:SubjectConfirmationData InResponseTo = "kbedjkocfjdaaadgmjeipbegnclbelfffbpbophe" NotOnOrAfter = "2014-07-17T13:20:05.032Z" </ saml2:SubjectConfirmation > </ saml2:Subject > < saml2:Conditions NotBefore = "2014-07-17T13:15:05.032Z" NotOnOrAfter = "2014-07-17T13:20:05.032Z" > < saml2:AudienceRestriction > < saml2:Audience >carbonServer2</ saml2:Audience > </ saml2:AudienceRestriction > </ saml2:Conditions > < saml2:AuthnStatement AuthnInstant = "2014-07-17T13:15:05.033Z" > < saml2:AuthnContext > < saml2:AuthnContextClassRef >urn:oasis:names:tc:SAML:2.0:ac:classes:Password</ saml2:AuthnContextClassRef > </ saml2:AuthnContext > </ saml2:AuthnStatement > < saml2:AttributeStatement > NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > Internal/carbonServer2,Internal/everyone </ saml2:AttributeValue > </ saml2:Attribute > < saml2:AttributeStatement > NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > E90836W19881010 </ saml2:AttributeValue > </ saml2:Attribute > NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > active </ saml2:AttributeValue > </ saml2:Attribute > </ saml2:AttributeStatement > </ saml2:AttributeStatement > </ saml2:Assertion > </ saml2p:Response > |
В этом ответе у нас есть один локальный атрибут, а именно роль и два дополнительных атрибута: http://pushpalanka.org/claims/keplerNumber и http://pushpalanka.org/claims/status, которые были получены из какого-либо другого метода, который мы можем определить в нашем расширении.
Как?
- Реализуйте настраиваемую логику для получения внешних утверждений. Есть только два факта, которые мы должны отметить в этой работе.
- Пользовательская реализация должна реализовывать интерфейс org.wso2.carbon.identity.application.authentication.framework.handler.claims.ClaimHandler или расширять реализацию интерфейса по умолчанию org.wso2.carbon.identity.application.authentication. framework.handler.claims.impl.DefaultClaimHandler.
- Карта, возвращаемая методом «public Map <String, String> handleClaimMappings», должна содержать все атрибуты, которые мы хотим добавить в ответ SAML.
Ниже приведен пример кода, который я написал, придерживаясь вышесказанного. Внешние утверждения могут быть запрошены из базы данных, прочитаны из файла или с использованием любого другого механизма, как требуется.
01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576public
class
CustomClaimHandler
implements
ClaimHandler {
private
static
Log log = LogFactory.getLog(CustomClaimHandler.
class
);
private
static
volatile
CustomClaimHandler instance;
private
String connectionURL =
null
;
private
String userName =
null
;
private
String password =
null
;
private
String jdbcDriver =
null
;
private
String sql =
null
;
public
static
CustomClaimHandler getInstance() {
if
(instance ==
null
) {
synchronized
(CustomClaimHandler.
class
) {
if
(instance ==
null
) {
instance =
new
CustomClaimHandler();
}
}
}
return
instance;
}
public
Map<String, String> handleClaimMappings(StepConfig stepConfig,
AuthenticationContext context, Map<String, String> remoteAttributes,
boolean
isFederatedClaims)
throws
FrameworkException {
String authenticatedUser =
null
;
if
(stepConfig !=
null
) {
//calling from StepBasedSequenceHandler
authenticatedUser = stepConfig.getAuthenticatedUser();
}
else
{
//calling from RequestPathBasedSequenceHandler
authenticatedUser = context.getSequenceConfig().getAuthenticatedUser();
}
Map<String, String> claims = handleLocalClaims(authenticatedUser, context);
claims.putAll(handleExternalClaims(authenticatedUser));
return
claims;
}
/**
* @param context
* @return
* @throws FrameworkException
*/
protected
Map<String, String> handleLocalClaims(String authenticatedUser,
AuthenticationContext context)
throws
FrameworkException {
....
}
private
Map<String, String> getFilteredAttributes(Map<String, String> allAttributes,
Map<String, String> requestedClaimMappings,
boolean
isStandardDialect) {
....
}
protected
String getDialectUri(String clientType,
boolean
claimMappingDefined) {
....
}
/**
* Added method to retrieve claims from external sources. This results will be merged to the local claims when
* returning final claim list, to be added to the SAML response, that is sent back to the SP.
*
* @param authenticatedUser : The user for whom we require claim values
* @return
*/
private
Map<String, String> handleExternalClaims(String authenticatedUser)
throws
FrameworkException {
Map<String, String> externalClaims =
new
HashMap<String, String>();
return
externalClaims;
}
}
- Удалите скомпилированный OSGI-пакет в IS_HOME / repository / components / dropins. (Мы разработали его как пакет OSGI, так как нам нужно получать локальные заявки, используя RealmService. Вы можете найти полный пакет и исходный код здесь )
- Укажите WSO2 Identity Server, чтобы использовать новую пользовательскую реализацию, которую мы имеем.
В IS_HOME / repository / conf / security / applicationauthentication.xml настройте имя нового обработчика. (в элементе «ApplicationAuthentication.Extensions.ClaimHandler».)
1
|
< ClaimHandler >com.wso2.sample.claim.handler.CustomClaimHandler</ ClaimHandler > |
Теперь, если посмотреть на сгенерированный ответ SAML, мы увидим добавленные внешние атрибуты.
Ура!
[1] — https://docs.wso2.com/display/IS500/Adding+a+Service+Provider.