Аутентификация LTPA с помощью Worklight
Я пытаюсь перейти от AdapterAuthentication для использования LTPA, откладывая userRegistry до контейнера Websphere.
Я следовал конфигурации "Начало работы" здесь, переполнение стека здесь. Я считаю, что вариант 2 является правильным подходом из этой документации.
Я установил автономный экземпляр Worklight на основе профиля Liberty (с использованием 6.2). Я изменил authenticationConfig.xml для использования LTPA:
<customSecurityTest name="LTPASecurityTest">
<test realm="wl_directUpdateRealm" step="1" />
<test realm="WASLTPARealm" isInternalUserID="true" />
</customSecurityTest>
<realm name="WASLTPARealm" loginModule="WASLTPAModule">
<className>
com.worklight.core.auth.ext.WebSphereFormBasedAuthenticator</className>
<parameter name="login-page" value="conf/login.html" />
<parameter name="error-page" value="conf/loginError.html" />
</realm>
<loginModule name="WASLTPAModule">
<className>
com.worklight.core.auth.ext.WebSphereLoginModule</className>
</loginModule>
Я подтвердил (и перестроил).war, чтобы иметь login.html и loginError.html как на корневом уровне, так и в каталоге conf/. (документация здесь "Эти HTML-файлы должны быть добавлены в корневой каталог в WAR-файле Worklight Server" действительно должна рассказать пользователям, как это сделать в Worklight Studio)
Я изменил адаптеры для использования LTPA Realm:
<procedure name="profile" securityTest="LTPASecurityTest"> </procedure>
Я изменил server.xml профиля Liberty в соответствии с документацией, чтобы добавить appSecurity (на скриншоте только показано, как это сделать с помощью Websphere Console) и привязать к ldapRegistry.
<feature>appSecurity-2.0</feature>
<feature>ldapRegistry-3.0</feature>
Однако из журналов сервера, когда клиент запускает приложение, регистрируется более 40 экземпляров трассировки стека. Со стороны клиента кажется, что исходные вызовы для подключения к Worklight отклоняются. Я предполагаю, что это потому, что у них нет токена LTPA.
Я ожидаю, что как только сервер определит, что пользователь запрашивает защищенный ресурс, будет выдан вызов. Похоже, что вместо вызова проблемы создается исключение WorkLightAuthenticationException.
Нужно ли добавлять дополнительные статические ресурсы? Есть ли дополнительные изменения конфигурации? Login.html никогда не возвращается конечному пользователю.
console.log:
[ERROR ] FWLSE0059E: Login into realm 'WASLTPAModule' failed. null. [project postal]
com.worklight.server.auth.api.WorkLightAuthenticationException
[ERROR ] FWLSE0117E: Error code: 4, error description: AUTHENTICATION_ERROR, error message: An error occurred while performing authentication using loginModule WASLTPAModule, User Identity {wl_directUpdateRealm=null, SubscribeServlet=null, wl_authenticityRealm=null, AdapterAuthRealm=null, wl_remoteDisableRealm=null, wl_antiXSRFRealm=(name:q0a052t5g02f833ocv0o48e4sv, loginModule:WLAntiXSRFLoginModule), wl_deviceAutoProvisioningRealm=null, wl_deviceNoProvisioningRealm=null, myserver=(name:df680b07-3057-4339-8d94-96a050ff99ed, loginModule:WeakDummy), WASLTPARealm=null, wl_anonymousUserRealm=(name:df680b07-3057-4339-8d94-96a050ff99ed, loginModule:WeakDummy)}. [project XYZ] [project XYZ]
[ERROR ] SRVE0777E: Exception thrown by application class 'com.worklight.core.auth.impl.AuthenticationContext.checkAuthentication:548'
com.worklight.server.auth.api.WorkLightAuthenticationException
at com.worklight.core.auth.impl.AuthenticationContext.checkAuthentication(AuthenticationContext.java:548)
at com.worklight.core.auth.impl.AuthenticationContext.login(AuthenticationContext.java:701)
at com.worklight.core.auth.impl.AuthenticationServiceBean.login(AuthenticationServiceBean.java:120)
at com.worklight.gadgets.serving.handler.LoginOnDemandHandler.doPost(LoginOnDemandHandler.java:68)
at com.worklight.gadgets.serving.GadgetAPIServlet.doGetOrPost(GadgetAPIServlet.java:144)
at com.worklight.gadgets.serving.GadgetAPIServlet.doPost(GadgetAPIServlet.java:107)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1240)
at [internal classes]
at com.worklight.core.auth.impl.AuthenticationFilter$1.execute(AuthenticationFilter.java:204)
at com.worklight.core.auth.impl.AuthenticationServiceBean.accessResource(AuthenticationServiceBean.java:76)
at com.worklight.core.auth.impl.AuthenticationFilter.doFilter(AuthenticationFilter.java:208)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:194)
at [internal classes]
[ERROR ] FWLSE0020E: Ajax request exception: Environment identity is null or not proven for realm WASLTPARealm [project XYZ]
[ERROR ] FWLSE0117E: Error code: 1, error description: INTERNAL_ERROR, error message: FWLSE0069E: An internal error occurred during gadget request [project XYZ]Environment identity is null or not proven for realm WASLTPARealm, User Identity Not available. [project XYZ]
редактировать
Чтобы ответить на вопросы Дэвида / Саймона:
Я явно вызываю wl.client.connect во время загрузки приложения (не используя connectOnStartup), но на данный момент я не жду onSuccess / onFailure. Это в моем запасе вещей, чтобы исправить; но я подозреваю, что это работает для AdapterAuth, это должно работать для LTPA.
Я начал с AdapterAuth (он работает), переключился на LDAPLoginModule (и он работает); чтобы вывести конечную точку LDAP, мы переключаем LTPA. Основываясь на этом; предупреждаю, что код на стороне клиента немного сложнее, чем хотелось бы.
Вот обработчик вызова на стороне клиента. Предположим, что заводской код рабочего света срабатывает практически сразу после запуска приложения; и затем следует вызов адаптера, который запускает код обработчика вызова.
...
angular.module(
'XYZ',
[ 'ionic', 'XYZ.controllers', 'XYZ.services', 'worklight' ])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
if (window.StatusBar) {
window.StatusBar.styleDefault();
}
});
})
.constant("authenticationRealm" , "WASLTPARealm");
// .constant("authenticationRealm" , "AdapterAuthRealm");
...
// Provide the Worklight object as an Angular service.
angular.module('worklight', [])
.factory('worklight', ['$window', function($window) {
//for unit testing, these aren't defined. only attempt to connect if we're in a worklight container
if (($window.WL)&& ($window.WL.Client)&&($window.WL.Client.connect)){
$window.WL.Client.connect();
}
return $window.WL;
}])
.factory('worklightAuthenticator', ['worklight', 'authenticationRealm', function(worklight, authenticationRealm){
var authenticator = {};
/* public apis */
authenticator.initLogin = function(){
worklight.Client.login(authenticationRealm);
};
authenticator.setAuthRequiredCallback = function(callback){
this.authRequiredCallback = callback;
};
authenticator.setLoginCompleteCallback = function(callback){
this.loginCompleteCallback = callback;
};
authenticator.setLoginCompleteCallback = function(callback){
this.loginCompleteCallback = callback;
};
// This will need to change as we get closer to USA
authenticator.getFriendlyRealmName= function(){
return (authenticationRealm !== "AdapterAuthRealm")? "Active Directory" : "local";
};
//Failing real abstraction going to assign functions based on what realm is defined
authenticator.submitLogin = (authenticationRealm !== "AdapterAuthRealm") ? function(username, password) {
var reqURL = '/j_security_check';
var options = {};
options.parameters = {
j_username : username,
j_password : password
};
options.headers = {};
authenticator.realmChallengeHandler.submitLoginForm(reqURL, options, authenticator.realmChallengeHandler.handleChallenge);
} : function(username, password) {
var options = {
parameters : [username, password],
adapter : "Security",
procedure : "submitAuthentication"
};
authenticator.realmChallengeHandler
.submitAdapterAuthentication(options, {onSuccess: function(r){window.alert(r);}, onFailure: function(z){console.log(z);}});
}
this._realmChallengeHandler = worklight.Client.createChallengeHandler(authenticationRealm);
this._submitLoginFormCallback = function(response){
var isLoginFormResponse = this._isCustomResponse(response);
if (isLoginFormResponse){
authenticator.handleChallenge(response);
} else {
authenticator.realmChallengeHandler.submitSuccess();
authenticator.loginCompleteCallback();
}
}
//Failing real abstraction going to assign functions based on what realm is defined
this._isCustomResponse = (authenticationRealm !== "AdapterAuthRealm") ? function(response) {
console.log("Challenge Required...", response);
var idx =response.responseText.indexOf("j_security_check") >= 0;
return idx;
} : function(response) {
console.log("Challenge Required...", response);
if (!response || !response.responseJSON || response.responseText === null) {
return false;
}
if (typeof (response.responseJSON.authRequired) !== 'undefined') {
return true;
} else {
return false;
}
} ;
//Failing real abstraction going to assign functions based on what realm is defined
this._handleChallenge = (authenticationRealm !== "AdapterAuthRealm") ? function(response) {
console.log("Handle Challenge", response);
var authRequired = response.responseText.indexOf("j_security_check") >= 0;
if (authRequired === true) {
authenticator.authRequiredCallback(response.responseText);
} else if (authRequired === false) {
console.log("Challenge Not Required");
authenticator.realmChallengeHandler.submitSuccess();
authenticator.loginCompleteCallback();
return false;
}
} : function(response) {
console.log("Handle Challenge", response);
var authRequired = response.responseJSON.authRequired;
if (authRequired === true) {
authenticator.authRequiredCallback(response.responseJSON);
} else if (authRequired === false) {
console.log("Challenge Not Required");
authenticator.realmChallengeHandler.submitSuccess();
authenticator.loginCompleteCallback();
return false;
}
};
this._realmChallengeHandler.isCustomResponse = this._isCustomResponse;
this._realmChallengeHandler.handleChallenge = this._handleChallenge;
this._realmChallengeHandler.submitLoginFormCallback = this._submitLoginFormCallback;
authenticator.realmChallengeHandler = this._realmChallengeHandler;
return authenticator;
}])
;
1 ответ
Вы объявляете ChallengeHandler в своем клиенте? Используете ли вы connectOnStartup:true? WL.Client.connect? Можете ли вы рассказать больше о том, что именно делает клиент?
Эта веб-страница https://pic.dhe.ibm.com/infocenter/wrklight/v6r1m0/index.jsp?topic=%2Fcom.ibm.worklight.deploy.doc%2Fadmin%2Fc_security_ltpa_overview.html описывает этот процесс и На втором шаге "Сервер запрашивает у пользователя вход в систему, поскольку ресурс защищен", и вы получаете HTTP 401 в журнале консоли. Можете ли вы показать нам, что на самом деле происходит через провод на этом этапе?
Одна мысль, я заметил, что в определении вашего теста безопасности у вас есть wl_directUpdateRealm, помеченный как шаг 1, но ни один шаг не отмечен для WASLTPARealm. Я не уверен, что произойдет в этой ситуации, но вы можете попробовать пометить WASLTPARealm как один шаг после прямой проверки обновления:
<customSecurityTest name="LTPASecurityTest">
<test realm="wl_directUpdateRealm" step="1" />
<test realm="WASLTPARealm" isInternalUserID="true" step="2" />
</customSecurityTest>
или вообще удалить шаги (чтобы все происходило за один шаг), или даже не использовать прямое обновление, пока не заработает сторона LTPA.
-simon