我正在努力让JMeter使用NTLM身份验证。起初,我得到了一个URL和凭证。当我在Firefox和Chrome中测试凭证时,我收到了验证弹出窗口,在提供凭证后,我得到了验证。因此,我创建了一个具有以下配置的测试计划:
- HTTP授权管理器
- HTTP请求默认值
- HTTP请求
我不知道NTLM身份验证架构的域要求。因此,JMeter最终未能进行身份验证,并返回HTTP 401错误。
然后我试着让坏男孩录下测试脚本。当我在Bad boy中输入URL时,我收到了Windows身份验证弹出窗口,而给定的凭据在Bad boy中不起作用。
因此,我尝试了IE,并收到了相同的Windows身份验证弹出窗口,但凭据不起作用。我请求了该域,并在IE中将该域作为域\用户名提供后,我成功地验证了该用户。
我对JMeter也尝试了同样的方法,并在HTTP授权管理器中提供了域。不幸的是,它在JMeter中不起作用。以下是我的测试计划。我已经用别名替换了原始URL、域和凭据。
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.8" jmeter="2.13 r1665067">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">1</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">1</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
<longProp name="ThreadGroup.start_time">1429694411000</longProp>
<longProp name="ThreadGroup.end_time">1429694411000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<AuthManager guiclass="AuthPanel" testclass="AuthManager" testname="HTTP Authorization Manager" enabled="true">
<collectionProp name="AuthManager.auth_list">
<elementProp name="" elementType="Authorization">
<stringProp name="Authorization.url">https://my_domain</stringProp>
<stringProp name="Authorization.username">username</stringProp>
<stringProp name="Authorization.password">password</stringProp>
<stringProp name="Authorization.domain">NTLM_DOMAIN</stringProp>
<stringProp name="Authorization.realm"></stringProp>
</elementProp>
</collectionProp>
</AuthManager>
<hashTree/>
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP Request Defaults" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">my_domain</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path"></stringProp>
<stringProp name="HTTPSampler.implementation">HttpClient4</stringProp>
<stringProp name="HTTPSampler.concurrentPool">4</stringProp>
</ConfigTestElement>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">false</boolProp>
<boolProp name="HTTPSampler.auto_redirects">true</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.implementation">HttpClient4</stringProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>
让JMeter去工作让我很沮丧。我已经尝试了HttpClient3.1&4的实现;他们没有一个工作过。然后,我下载了源代码,看看是否有什么我可以挖掘出来。
这两个类处理JMeter的HTTP实现:
- org.apache.jmeter.protocol.http.sampler网站。HTTPHC4Impl(用于HttpClient4)
- org.apache.jmeter.protocol.http.sampler网站。HTTPHC3Impl(用于HttpClient3.1)
我没有发现任何问题。
我尝试通过Java代码进行身份验证。以下是使用common-httpclient-3.1进行身份验证的实现:
import java.io.IOException;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.NTCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
public class NTLMAuthenticationHttpClient {
public static void main(String[] args) throws HttpException, IOException {
HttpClient client = new HttpClient();
Credentials credentials = new NTCredentials("username", "password", "", "NTLM_DOMAIN");
HttpState state = client.getState();
state.setCredentials(AuthScope.ANY, credentials);
String domain = "my_domain";
String protocol = "https";
HttpMethod method = new GetMethod(protocol + "://" + domain);
method.setDoAuthentication(true);
int status = client.executeMethod(method);
System.out.println(status);
}
}
这段代码一两次返回了HTTP 401,大多数时候我得到的是HTTP 200。
以下是使用httpclient-4.4.1的实现:
import java.io.IOException;
import jcifs.ntlmssp.NtlmFlags;
import jcifs.ntlmssp.Type1Message;
import jcifs.ntlmssp.Type2Message;
import jcifs.ntlmssp.Type3Message;
import jcifs.util.Base64;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.auth.DigestSchemeFactory;
import org.apache.http.impl.auth.KerberosSchemeFactory;
import org.apache.http.impl.auth.NTLMEngine;
import org.apache.http.impl.auth.NTLMEngineException;
import org.apache.http.impl.auth.NTLMScheme;
import org.apache.http.impl.auth.SPNegoSchemeFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
import org.apache.http.protocol.HttpContext;
public class NTLMAuthenticationHttpComponent {
public static void main(String[] args) throws ClientProtocolException,
IOException {
Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder
.<AuthSchemeProvider> create()
.register(AuthSchemes.NTLM, new AuthSchemeProvider() {
public AuthScheme create(HttpContext context) {
return new NTLMScheme(new JCIFSEngine());
}
}).register(AuthSchemes.BASIC, new BasicSchemeFactory())
.register(AuthSchemes.DIGEST, new DigestSchemeFactory())
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
.build();
String domain = "my_domain";
String protocol = "https";
HttpHost targetHost = new HttpHost(domain, 443, protocol);
CredentialsProvider credentialsProvider = new SystemDefaultCredentialsProvider();
credentialsProvider.setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
new NTCredentials("username", "password", null, "NTLM_DOMAIN"));
CloseableHttpClient client = HttpClients.custom()
.setDefaultAuthSchemeRegistry(authSchemeRegistry)
.setDefaultCredentialsProvider(credentialsProvider).build();
HttpGet httpget = new HttpGet(protocol + "//" + domain);
HttpResponse response = client.execute(httpget);
System.out.println(response.getStatusLine().getStatusCode());
}
private static final class JCIFSEngine implements NTLMEngine {
private static final int TYPE_1_FLAGS =
NtlmFlags.NTLMSSP_NEGOTIATE_56 |
NtlmFlags.NTLMSSP_NEGOTIATE_128 |
NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 |
NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
NtlmFlags.NTLMSSP_REQUEST_TARGET;
public String generateType1Msg(final String domain, final String workstation)
throws NTLMEngineException {
final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
return Base64.encode(type1Message.toByteArray());
}
public String generateType3Msg(final String username, final String password,
final String domain, final String workstation, final String challenge)
throws NTLMEngineException {
Type2Message type2Message;
try {
type2Message = new Type2Message(Base64.decode(challenge));
} catch (final IOException exception) {
throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
}
final int type2Flags = type2Message.getFlags();
final int type3Flags = type2Flags
& (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
final Type3Message type3Message = new Type3Message(type2Message, password, domain,
username, workstation, type3Flags);
return Base64.encode(type3Message.toByteArray());
}
}
}
这总是返回Http 401 Unauthorized错误。此代码取自使用JCIFS的HTTP Components site。
我无法找到未经授权的任何原因。JMeter或HTTPClient是否完全支持NTLM身份验证?在阅读了上述网站的注解后,我有一些疑问:
NTLM是Microsoft开发的专有身份验证方案,针对Windows操作系统进行了优化。
直到2008年,还没有正式的、公开的、完整的议定书文件。由于逆向工程的努力,存在非正式的第三方协议描述。目前尚不清楚基于逆向工程的协议是否完整甚至正确。
作为其互操作性原则倡议的一部分,Microsoft于2008年2月发布了MS-NLMP和MS-NTHT规范。
从4.1版开始,HttpClient最初支持基于反向工程方法的NTLMv1、NTLMv2和NTLM2SessionResponse身份验证协议。从版本4.2.3开始,HttpClient现在支持更正确的实现,主要基于Microsoft自己的规范。这有望纠正一些问题,尤其是自Microsoft(自Windows Server 2008 R2起)开始使用其协议的新实现以来。这一新的Microsoft实施在某些情况下导致NTLM的一些较旧的反向工程客户端实现的身份验证失败。
已知新的HttpClient NTLM实现至少已在以下系统上成功尝试:
- Windows Server 2000和Server 2003系统,配置为使用LM和NTLMv1身份验证
- Windows Server 2003系统,配置为使用NTLMv2身份验证
- Windows Server 2008 R2系统,配置为使用NTLM2SessionResponse身份验证
如果当前的HttpClient NTLM实现在您的环境中被证明有问题,我们肯定很想听听。
在浏览器中,当我浏览我用于身份验证的URL时,它请求凭据,然后导航到主页。还有另一个中间页,它返回HTTP 302进行重定向。
任何建议都会对我有很大帮助。
更新:
在JMeter中,以下是我使用Response Header得到的结果:
Thread Name: Thread Group 1-1
Sample Start: 2015-04-26 14:26:39 IST
Load time: 3837
Connect Time: 2716
Latency: 3837
Size in bytes: 940
Headers size in bytes: 940
Body size in bytes: 0
Sample Count: 1
Error Count: 1
Response code: 401
Response message: Unauthorized
Response headers:
HTTP/1.1 401 Unauthorized
Cache-Control: max-age=0
Content-Type: text/plain
Date: Sun, 26 Apr 2015 08:56:42 GMT
Expires: Sun, 26 Apr 2015 08:56:43 GMT
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=0D39812DAECAED077E7A9001864874A9.schbapxu1044_SEP; Expires=Sun, 26-Apr-2015 16:56:42 GMT; Path=/; Secure; HttpOnly
Set-Cookie: dtCookie=2929007D72E613D13BF40F8241EC4B9F|X2RlZmF1bHR8MQ; Path=/; Domain=.my_domain_part2
Set-Cookie: AWSELB=C5C5577906943F772312365AC913FBE510FFA9A080FC6FD7778CB3F66B01593D16E110291976D6D7D50FBFB1DB51745A84041319D726B0F898FAE4520DC36E25BB9AE95FBCB14D902FBC9B5903E8BCB6E32414584F;PATH=/;EXPIRES=Sun, 26-Apr-2015 16:56:42 GMT;SECURE;HTTPONLY
Vary: Accept-Encoding
Via: 1.1 my_domain_part1.my_domain_part2
WWW-Authenticate: NTLM
X-Content-Type-Options: nosniff
X-dynaTrace-JS-Agent: true
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1
Content-Length: 0
Connection: keep-alive
HTTPSampleResult fields:
ContentType: text/plain
DataEncoding: null
2条答案
按热度按时间jv2fixgn1#
它确实为您提供了HTTP授权管理器中的用户名、密码和域
有关详细说明和配置详细信息,请参阅Windows Authentication with Apache JMeter指南。
uubf1zoe2#
由于NTLM的专有性质,除Microsoft外,没有人完全支持它。