Javascript 在Nativescript ios平台中使用ntlm身份验证

Javascript 在Nativescript ios平台中使用ntlm身份验证,javascript,ios,nativescript,ntlm,des,Javascript,Ios,Nativescript,Ntlm,Des,我正在构建一个应用程序,通过使用NTLM身份验证的sharepoint网站对用户进行身份验证。我在这里找到了为nativescript修补的ntlm.js 我已经设法让它在android平台上工作,但在ios上失败,显示401错误。据我所知,不同之处在于这一部分: Ntlm.setCredentials = function(domain, username, password) { var magic = 'KGS!@#$%'; // Create LM password hash.

我正在构建一个应用程序,通过使用NTLM身份验证的sharepoint网站对用户进行身份验证。我在这里找到了为nativescript修补的ntlm.js

我已经设法让它在android平台上工作,但在ios上失败,显示401错误。据我所知,不同之处在于这一部分:

Ntlm.setCredentials = function(domain, username, password) {
    var magic = 'KGS!@#$%'; // Create LM password hash.
    var lmPassword = password.toUpperCase().substr(0, 14);
    while (lmPassword.length < 14) lmPassword += '\0';
    var key1 = Ntlm.createKey(lmPassword);
    var key2 = Ntlm.createKey(lmPassword.substr(7));
    var lmHashedPassword = des(key1, magic, 1, 0) + des(key2, magic, 1, 0);
    var ntPassword = ''; // Create NT password hash.
    for (var i = 0; i < password.length; i++)
        ntPassword += password.charAt(i) + '\0';
    var ntHashedPassword = str_md4(ntPassword);
    Ntlm.domain = domain;
    Ntlm.username = username;
    Ntlm.lmHashedPassword = lmHashedPassword;
    Ntlm.ntHashedPassword = ntHashedPassword;
};
如果可能相关,我也改变了提出请求的方式。当用户单击登录时,将调用以下承诺:

Ntlm.login('url')
            .then(() => {
                console.log('Success');
                appSettings.setString('token', 'abc123');
                this.router.navigate(['/ilt']);
            })
            .catch(error => {
                console.log('Failed');
                appSettings.remove('token');
                alert('Failed! ' + error );
            })
我在ntlm.js文件中创建了一个新的登录函数:

Ntlm.login = function(url) {

    return new Promise((resolve, reject) => {
        if (!Ntlm.domain || !Ntlm.username || !Ntlm.lmHashedPassword || !Ntlm.ntHashedPassword) {

            Ntlm.error('No NTLM credentials specified. Use Ntlm.setCredentials(...) before making calls.');
        }
        var hostname = Ntlm.getLocation(url).hostname;
        var msg1 = Ntlm.createMessage1(hostname);
        var request = new XMLHttpRequest();

        request.onload = function() {
            var response = request.getResponseHeader('WWW-Authenticate');
            var challenge = Ntlm.getChallenge(response);

            var msg3 = Ntlm.createMessage3(challenge, hostname);
            request.open('GET', url, false);
            var authorization = 'NTLM ' + msg3.toBase64();
            request.setRequestHeader('Authorization', authorization);

            request.onload = function() {
                if (request.readyState == 4 && request.status == 200) {
                    resolve(request.status);
                }
                else if (request.readyState == 4 && request.status != 200) {
                    reject(request.status);
                }
            };
            request.send(null);
        };
        request.open('GET', url, false);
        request.setRequestHeader('Authorization', 'NTLM ' + msg1.toBase64());
        request.send(null);   
    })

};
这一切在Android版本上都很好,只是不明白为什么它不在ios上。非常令人沮丧!如果有人能理解这一点,我将永远感激。我意识到这是一个大量的代码和相当利基领域

非常感谢,


更新

我认为console.log在Android和iOS中的行为方式可能有所不同,这可以解释一些缺少的字符。我创建了一个新的测试帐户(testuser/testing),并记录了各种点,以尝试一步一步地确定NTLM过程中发生了什么。以下是android的日志:

NTLM WALKTHROUGH ON ANDROID

Step 1: Creates a cryptographic hash of the users password:
lmHashedPassword = -UE}{}*ªÓ´5µî
ntHashedPassword = |SÏ¥ê}�;�� ûQ£õ

Step 2: Sends first request to the server, with the following Authorisation header:
NTLM TlRMTVNTUAABAAAAA7IAAAUABQBEAAAAJAAkACAAAABHQVRFV0FZLlNUUEFVTFNDQVRIT0xJQ0NPTExFR0UuQ08uVUtBRE1JTg==

Step 3: Server sends a challenge back to client:
¡2@�³Q%Ï

Step 4: Client encrypts this challenge with the hash of the users password and sends back to server (response).
The Authorization header is: NTLM TlRMTVNTUAADAAAAGAAYAKQAAAAYABgAvAAAAAoACgBAAAAAEgASAEoAAABIAEgAXAAAAAAAAADUAAAAAYIAAEEARABNAEkATgB0AGUAcwB0AHMAdABhAGYAZgBHAEEAVABFAFcAQQBZAC4AUwBUAFAAQQBVAEwAUwBDAEEAVABIAE8ATABJAEMAQwBPAEwATABFAEcARQAuAEMATwAuAFUASwBsEslcvTQhhY3+RgKtqufBzFrmufFKNkAHXJRcA6ThOAU105+NJBGnsn2ri6Ziuv8=

Step 5: Now the server has sent the username, challenge and response to the Domain Controller.
The DC compares and returns status of: 200
以下是iOS的日志:

NTLM WALKTHROUGH ON IOS

Step 1: Creates a cryptographic hash of the users password:
lmHashedPassword = -UE}{}*ªÓ´5µî
ntHashedPassword = |SÏ¥ê}�;�� ûQ£õ

Step 2: Sends the first request to the server, with the following Authorisation header:
NTLM TlRMTVNTUAABAAAAA7IAAAUABQBEAAAAJAAkACAAAABHQVRFV0FZLlNUUEFVTFNDQVRIT0xJQ0NPTExFR0UuQ08uVUtBRE1JTg==

Step 3: Server sends a challenge back to client:
q�v¹,

Step 4: Client encrypts this challenge with the hash of the users password and sends back to server (response).
The Authorization header is: NTLM TlRMTVNTUAADAAAAGAAYAKQAAAAYABgAvAAAAAoACgBAAAAAEgASAEoAAABIAEgAXAAAAAAAAADUAAAAAYIAAEEARABNAEkATgB0AGUAcwB0AHMAdABhAGYAZgBHAEEAVABFAFcAQQBZAC4AUwBUAFAAQQBVAEwAUwBDAEEAVABIAE8ATABJAEMAQwBPAEwATABFAEcARQAuAEMATwAuAFUASwAP9HN5WjPCs9hMRrmttnYHieFrThwyUAWanKWtVdzOqDOJ2isUdQeV0ISmv9TT0ek=

Step 5: Now the server has sent the username, challenge and response to the Domain Controller.
The DC compares returns status of: 401

似乎凭据的计算方法相同,然后从服务器返回的质询是随机的。但在iOS上,挑战似乎是缺少字符-可能是由于字符类型。然后,客户端使用散列密码加密质询,并将其发送回服务器。我想这可能是iOS上不正确的部分

正如您所说,区别似乎在于
des
。它有点长,所以多调试一点将有助于确定Android和iOS之间的差异。例如,检查循环
在(m
时的遍历次数是否相同(给定iOS的返回值和行
return result+tempresult;
)。Android的返回值是多少?我做了检查,while循环循环了相同的次数。每次在
Ntlm.buildResponse()
函数中调用
des()
时,iOS和android之间的返回值都不同。我猜是因为每次运行NTLM时,都会有一个用于加密响应的随机挑战。因此,不可能看到iOS和Android版本是否适合这些阶段。
NTLM WALKTHROUGH ON IOS

Step 1: Creates a cryptographic hash of the users password:
lmHashedPassword = -UE}{}*ªÓ´5µî
ntHashedPassword = |SÏ¥ê}�;�� ûQ£õ

Step 2: Sends the first request to the server, with the following Authorisation header:
NTLM TlRMTVNTUAABAAAAA7IAAAUABQBEAAAAJAAkACAAAABHQVRFV0FZLlNUUEFVTFNDQVRIT0xJQ0NPTExFR0UuQ08uVUtBRE1JTg==

Step 3: Server sends a challenge back to client:
q�v¹,

Step 4: Client encrypts this challenge with the hash of the users password and sends back to server (response).
The Authorization header is: NTLM TlRMTVNTUAADAAAAGAAYAKQAAAAYABgAvAAAAAoACgBAAAAAEgASAEoAAABIAEgAXAAAAAAAAADUAAAAAYIAAEEARABNAEkATgB0AGUAcwB0AHMAdABhAGYAZgBHAEEAVABFAFcAQQBZAC4AUwBUAFAAQQBVAEwAUwBDAEEAVABIAE8ATABJAEMAQwBPAEwATABFAEcARQAuAEMATwAuAFUASwAP9HN5WjPCs9hMRrmttnYHieFrThwyUAWanKWtVdzOqDOJ2isUdQeV0ISmv9TT0ek=

Step 5: Now the server has sent the username, challenge and response to the Domain Controller.
The DC compares returns status of: 401