Аутентификация 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) и выполнить привязку к ldapRegistry.

   <feature>appSecurity-2.0</feature>
   <feature>ldapRegistry-3.0</feature>

Однако из журналов сервера, когда клиент запускает приложение, сообщается о 40+ экземплярах трассировки стека. Со стороны клиента кажется, что первоначальные вызовы для подключения к Worklight отклоняются. Я предполагаю, что это потому, что у них нет токена LTPA.

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

Нужно ли добавлять дополнительные статические ресурсы? Есть ли дополнительные изменения конфигурации? Login.html никогда не возвращается конечному пользователю.

консоль.лог:

Консоль браузера.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. Основываясь на этом; предупреждаю, что код на стороне клиента немного сложнее, чем хотелось бы.

Вот обработчик вызовов на стороне клиента. Предположим, что код фабрики Worklight запускается почти сразу после запуска приложения; и затем следует вызов адаптера, который запускает код обработчика вызова.

...
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;
}])

;


person kwv    schedule 02.09.2014    source источник
comment
Вы не упоминаете свою реализацию ChallengeHandler. Кроме того, вызываете ли вы явно WL.Client.connect (и ждете, пока это завершится успешно) перед вызовом адаптера? Вы определили тест безопасности для среды в своем дескрипторе приложения? В любом случае вы можете попробовать переключить WASLTPARealm на использование com.worklight.core.auth.ext.FormBasedAuthenticator. Это устраняет необходимость переупаковывать файл WAR.   -  person David Dhuyveter    schedule 03.09.2014
comment
Есть ли какие-либо преимущества в определении теста безопасности в среде в дескрипторе приложения?   -  person kwv    schedule 03.09.2014


Ответы (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>

или вообще удалить шаги (чтобы все происходило за один шаг), или вообще не использовать Direct Update, пока не заработаете на стороне LTPA.

-саймон

person SimonK    schedule 03.09.2014
comment
Я не уверен, что понимаю последствия указания нескольких областей. Я думаю, что step='1' появился при переходе с 6.1 на 6.2. При поиске; Думаю, это стало понятнее. Я предположил, указав wl_directUpdateRealm, который позволит обрабатывать запросы на обновление Worklight. Однако этот фрагмент кода заставляет меня задаться вопросом, должен ли каждый мир иметь свой собственный обработчик вызовов для управления клиентским опытом? - person kwv; 03.09.2014